4 * ipptool command for CUPS.
6 * Copyright 2007-2010 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/".
17 * main() - Parse options and do tests.
18 * compare_vars() - Compare two variables.
19 * do_tests() - Do tests as specified in the test file.
20 * expand_variables() - Expand variables in a string.
21 * expect_matches() - Return true if the tag matches the specification.
22 * get_collection() - Get a collection value from the current test file.
23 * get_filename() - Get a filename based on the current test file.
24 * get_token() - Get a token from a file.
25 * get_variable() - Get the value of a variable.
26 * iso_date() - Return an ISO 8601 date/time string for the given IPP
28 * print_attr() - Print an attribute on the screen.
29 * print_col() - Print a collection attribute on the screen.
30 * print_csv() - Print a line of CSV text.
31 * print_fatal_error() - Print a fatal error message.
32 * print_line() - Print a line of formatted text.
33 * print_test_error() - Print a test error message.
34 * print_xml_header() - Print a standard XML plist header.
35 * print_xml_string() - Print an XML string with escaping.
36 * print_xml_trailer() - Print the XML trailer with success/fail value.
37 * set_variable() - Set a variable value.
38 * usage() - Show program usage.
39 * validate_attr() - Determine whether an attribute is valid.
40 * with_value() - Test a WITH-VALUE predicate.
44 * Include necessary headers...
47 #include <cups/cups-private.h>
48 #include <cups/file-private.h>
53 #endif /* !O_BINARY */
60 typedef enum _cups_transfer_e
/**** How to send request data ****/
62 _CUPS_TRANSFER_AUTO
, /* Chunk for files, length for static */
63 _CUPS_TRANSFER_CHUNKED
, /* Chunk always */
64 _CUPS_TRANSFER_LENGTH
/* Length always */
67 typedef enum _cups_output_e
/**** Output mode ****/
69 _CUPS_OUTPUT_QUIET
, /* No output */
70 _CUPS_OUTPUT_TEST
, /* Traditional CUPS test output */
71 _CUPS_OUTPUT_PLIST
, /* XML plist test output */
72 _CUPS_OUTPUT_LIST
, /* Tabular list output */
73 _CUPS_OUTPUT_CSV
/* Comma-separated values output */
76 typedef struct _cups_expect_s
/**** Expected attribute info ****/
78 int optional
, /* Optional attribute? */
79 not_expect
; /* Don't expect attribute? */
80 char *name
, /* Attribute name */
81 *of_type
, /* Type name */
82 *same_count_as
, /* Parallel attribute name */
83 *if_defined
, /* Only required if variable defined */
84 *if_undefined
, /* Only required if variable is not defined */
85 *with_value
, /* Attribute must include this value */
86 *define_match
, /* Variable to define on match */
87 *define_no_match
, /* Variable to define on no-match */
88 *define_value
; /* Variable to define with value */
89 int with_regex
, /* WITH-VALUE is a regular expression */
90 count
; /* Expected count if > 0 */
91 ipp_tag_t in_group
; /* IN-GROUP value */
94 typedef struct _cups_status_s
/**** Status info ****/
96 ipp_status_t status
; /* Expected status code */
97 char *if_defined
, /* Only if variable is defined */
98 *if_undefined
; /* Only if variable is not defined */
101 typedef struct _cups_var_s
/**** Variable ****/
103 char *name
, /* Name of variable */
104 *value
; /* Value of variable */
107 typedef struct _cups_vars_s
/**** Set of variables ****/
109 const char *uri
, /* URI for printer */
110 *filename
; /* Filename */
111 char scheme
[64], /* Scheme from URI */
112 userpass
[256], /* Username/password from URI */
113 hostname
[256], /* Hostname from URI */
114 resource
[1024]; /* Resource path from URI */
115 int port
; /* Port number from URI */
116 http_encryption_t encryption
; /* Encryption for connection? */
117 cups_array_t
*vars
; /* Array of variables */
125 _cups_transfer_t Transfer
= _CUPS_TRANSFER_AUTO
;
126 /* How to transfer requests */
127 _cups_output_t Output
= _CUPS_OUTPUT_LIST
;
129 int IgnoreErrors
= 0, /* Ignore errors? */
130 Verbosity
= 0, /* Show all attributes? */
131 Version
= 11, /* Default IPP version */
132 XMLHeader
= 0; /* 1 if header is written */
133 const char * const URIStatusStrings
[] = /* URI status strings */
136 "Bad arguments to function",
137 "Bad resource in URI",
138 "Bad port number in URI",
139 "Bad hostname/address in URI",
140 "Bad username in URI",
144 "Missing scheme in URI",
145 "Unknown scheme in URI",
146 "Missing resource in URI"
154 static int compare_vars(_cups_var_t
*a
, _cups_var_t
*b
);
155 static int do_tests(_cups_vars_t
*vars
, const char *testfile
);
156 static void expand_variables(_cups_vars_t
*vars
, char *dst
, const char *src
,
159 __attribute((nonnull(1,2,3)))
160 #endif /* __GNUC__ */
162 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
163 static ipp_t
*get_collection(_cups_vars_t
*vars
, FILE *fp
, int *linenum
);
164 static char *get_filename(const char *testfile
, char *dst
, const char *src
,
166 static char *get_token(FILE *fp
, char *buf
, int buflen
,
168 static char *get_variable(_cups_vars_t
*vars
, const char *name
);
169 static char *iso_date(ipp_uchar_t
*date
);
170 static void print_attr(ipp_attribute_t
*attr
);
171 static void print_col(ipp_t
*col
);
172 static void print_csv(ipp_attribute_t
*attr
, int num_displayed
,
173 char **displayed
, size_t *widths
);
174 static void print_fatal_error(const char *s
, ...)
176 __attribute__ ((__format__ (__printf__
, 1, 2)))
177 #endif /* __GNUC__ */
179 static void print_line(ipp_attribute_t
*attr
, int num_displayed
,
180 char **displayed
, size_t *widths
);
181 static void print_test_error(const char *s
, ...)
183 __attribute__ ((__format__ (__printf__
, 1, 2)))
184 #endif /* __GNUC__ */
186 static void print_xml_header(void);
187 static void print_xml_string(const char *element
, const char *s
);
188 static void print_xml_trailer(int success
, const char *message
);
189 static void set_variable(_cups_vars_t
*vars
, const char *name
,
191 static void usage(void);
192 static int validate_attr(ipp_attribute_t
*attr
, int print
);
193 static int with_value(char *value
, int regex
, ipp_attribute_t
*attr
);
197 * 'main()' - Parse options and do tests.
200 int /* O - Exit status */
201 main(int argc
, /* I - Number of command-line args */
202 char *argv
[]) /* I - Command-line arguments */
204 int i
; /* Looping var */
205 int status
; /* Status of tests... */
206 char *opt
, /* Current option */
207 name
[1024], /* Name/value buffer */
208 *value
, /* Pointer to value */
209 filename
[1024], /* Real filename */
210 testname
[1024]; /* Real test filename */
211 const char *testfile
; /* Test file to use */
212 int interval
, /* Test interval */
213 repeat
; /* Repeat count */
214 _cups_vars_t vars
; /* Variables */
215 http_uri_status_t uri_status
; /* URI separation status */
216 _cups_globals_t
*cg
= _cupsGlobals();
222 * Initialize the locale and variables...
225 _cupsSetLocale(argv
);
227 memset(&vars
, 0, sizeof(vars
));
228 vars
.vars
= cupsArrayNew((cups_array_func_t
)compare_vars
, NULL
);
233 * ipptool URI testfile
241 for (i
= 1; i
< argc
; i
++)
243 if (argv
[i
][0] == '-')
245 for (opt
= argv
[i
] + 1; *opt
; opt
++)
249 case 'C' : /* Enable HTTP chunking */
250 Transfer
= _CUPS_TRANSFER_CHUNKED
;
253 case 'E' : /* Encrypt with TLS */
255 vars
.encryption
= HTTP_ENCRYPT_REQUIRED
;
257 _cupsLangPrintf(stderr
,
258 _("%s: Sorry, no encryption support compiled in\n"),
260 #endif /* HAVE_SSL */
263 case 'I' : /* Ignore errors */
267 case 'L' : /* Disable HTTP chunking */
268 Transfer
= _CUPS_TRANSFER_LENGTH
;
271 case 'S' : /* Encrypt with SSL */
273 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
275 _cupsLangPrintf(stderr
,
276 _("%s: Sorry, no encryption support compiled in\n"),
278 #endif /* HAVE_SSL */
281 case 'V' : /* Set IPP version */
286 _cupsLangPuts(stderr
,
287 _("ipptool: Missing version for \"-V\".\n"));
291 if (!strcmp(argv
[i
], "1.0"))
293 else if (!strcmp(argv
[i
], "1.1"))
295 else if (!strcmp(argv
[i
], "2.0"))
297 else if (!strcmp(argv
[i
], "2.1"))
299 else if (!strcmp(argv
[i
], "2.2"))
303 _cupsLangPrintf(stderr
,
304 _("ipptool: Bad version %s for \"-V\".\n"),
310 case 'X' : /* Produce XML output */
311 Output
= _CUPS_OUTPUT_PLIST
;
313 if (interval
|| repeat
)
315 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are "
316 "incompatible with -X\".\n"));
321 case 'c' : /* CSV output */
322 Output
= _CUPS_OUTPUT_CSV
;
325 case 'd' : /* Define a variable */
330 _cupsLangPuts(stderr
,
331 _("ipptool: Missing name=value for \"-d\".\n"));
335 strlcpy(name
, argv
[i
], sizeof(name
));
336 if ((value
= strchr(name
, '=')) != NULL
)
339 value
= name
+ strlen(name
);
341 set_variable(&vars
, name
, value
);
344 case 'f' : /* Set the default test filename */
349 _cupsLangPuts(stderr
,
350 _("ipptool: Missing filename for \"-f\".\n"));
354 if (access(argv
[i
], 0) && argv
[i
][0] != '/')
356 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s",
357 cg
->cups_datadir
, argv
[i
]);
358 if (access(argv
[i
], 0))
359 vars
.filename
= argv
[i
];
361 vars
.filename
= filename
;
364 vars
.filename
= argv
[i
];
367 case 'i' : /* Test every N seconds */
372 _cupsLangPuts(stderr
,
373 _("ipptool: Missing seconds for \"-i\".\n"));
377 interval
= atoi(argv
[i
]);
379 if (Output
== _CUPS_OUTPUT_PLIST
&& interval
)
381 _cupsLangPuts(stderr
, _("ipptool: \"-i\" is incompatible with "
387 case 'l' : /* List as a table */
388 Output
= _CUPS_OUTPUT_LIST
;
391 case 'n' : /* Repeat count */
396 _cupsLangPuts(stderr
,
397 _("ipptool: Missing count for \"-n\".\n"));
401 repeat
= atoi(argv
[i
]);
403 if (Output
== _CUPS_OUTPUT_PLIST
&& repeat
)
405 _cupsLangPuts(stderr
, _("ipptool: \"-n\" is incompatible with "
411 case 'q' : /* Be quiet */
412 Output
= _CUPS_OUTPUT_QUIET
;
415 case 't' : /* CUPS test output */
416 Output
= _CUPS_OUTPUT_TEST
;
419 case 'v' : /* Be verbose */
424 _cupsLangPrintf(stderr
, _("ipptool: Unknown option \"-%c\".\n"),
431 else if (!strncmp(argv
[i
], "ipp://", 6) ||
432 !strncmp(argv
[i
], "http://", 7) ||
433 !strncmp(argv
[i
], "https://", 8))
441 _cupsLangPuts(stderr
, _("ipptool: May only specify a single URI.\n"));
446 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
, vars
.uri
,
447 vars
.scheme
, sizeof(vars
.scheme
),
448 vars
.userpass
, sizeof(vars
.userpass
),
449 vars
.hostname
, sizeof(vars
.hostname
),
451 vars
.resource
, sizeof(vars
.resource
));
453 if (uri_status
!= HTTP_URI_OK
)
455 _cupsLangPrintf(stderr
, _("ipptool: Bad URI - %s.\n"),
456 URIStatusStrings
[uri_status
- HTTP_URI_OVERFLOW
]);
460 if (strcmp(vars
.scheme
, "http") && strcmp(vars
.scheme
, "https") &&
461 strcmp(vars
.scheme
, "ipp"))
463 _cupsLangPuts(stderr
, _("ipptool: Only http, https, and ipp URIs are "
476 _cupsLangPuts(stderr
, _("ipptool: URI required before test file."));
480 if (access(argv
[i
], 0) && argv
[i
][0] != '/')
482 snprintf(testname
, sizeof(testname
), "%s/ipptool/%s", cg
->cups_datadir
,
484 if (access(testname
, 0))
492 if (!do_tests(&vars
, testfile
))
497 if (!vars
.uri
|| !testfile
)
501 * Loop if the interval is set...
504 if (Output
== _CUPS_OUTPUT_PLIST
)
505 print_xml_trailer(!status
, NULL
);
506 else if (interval
&& repeat
> 0)
511 do_tests(&vars
, testfile
);
520 do_tests(&vars
, testfile
);
533 * 'compare_vars()' - Compare two variables.
536 static int /* O - Result of comparison */
537 compare_vars(_cups_var_t
*a
, /* I - First variable */
538 _cups_var_t
*b
) /* I - Second variable */
540 return (strcasecmp(a
->name
, b
->name
));
545 * 'do_tests()' - Do tests as specified in the test file.
548 static int /* 1 = success, 0 = failure */
549 do_tests(_cups_vars_t
*vars
, /* I - Variables */
550 const char *testfile
) /* I - Test file to use */
552 int i
, /* Looping var */
553 linenum
, /* Current line number */
554 pass
, /* Did we pass the test? */
555 prev_pass
= 1, /* Did we pass the previous test? */
556 request_id
, /* Current request ID */
557 show_header
= 1, /* Show the test header? */
558 ignore_errors
, /* Ignore test failures? */
559 skip_previous
= 0; /* Skip on previous test failure? */
560 http_t
*http
= NULL
; /* HTTP connection to server */
561 FILE *fp
= NULL
; /* Test file */
562 char resource
[512], /* Resource for request */
563 token
[1024], /* Token from file */
564 *tokenptr
, /* Pointer into token */
565 temp
[1024]; /* Temporary string */
566 ipp_t
*request
= NULL
; /* IPP request */
567 ipp_t
*response
= NULL
; /* IPP response */
568 char attr
[128]; /* Attribute name */
569 ipp_op_t op
; /* Operation */
570 ipp_tag_t group
; /* Current group */
571 ipp_tag_t value
; /* Current value type */
572 ipp_attribute_t
*attrptr
, /* Attribute pointer */
573 *found
, /* Found attribute */
574 *lastcol
= NULL
; /* Last collection attribute */
575 char name
[1024]; /* Name of test */
576 char filename
[1024]; /* Filename */
577 _cups_transfer_t transfer
; /* To chunk or not to chunk */
578 int version
, /* IPP version number to use */
579 skip_test
; /* Skip this test? */
580 int num_statuses
= 0; /* Number of valid status codes */
581 _cups_status_t statuses
[100], /* Valid status codes */
582 *last_status
; /* Last STATUS (for predicates) */
583 int num_expects
= 0; /* Number of expected attributes */
584 _cups_expect_t expects
[200], /* Expected attributes */
585 *expect
, /* Current expected attribute */
586 *last_expect
; /* Last EXPECT (for predicates) */
587 int num_displayed
= 0; /* Number of displayed attributes */
588 char *displayed
[200]; /* Displayed attributes */
589 size_t widths
[200]; /* Width of columns */
593 * Open the test file...
596 if ((fp
= fopen(testfile
, "r")) == NULL
)
598 print_fatal_error("Unable to open test file %s - %s", testfile
,
605 * Connect to the server...
608 if ((http
= httpConnectEncrypt(vars
->hostname
, vars
->port
,
609 vars
->encryption
)) == NULL
)
611 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
612 vars
->port
, strerror(errno
));
621 CUPS_SRAND(time(NULL
));
625 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
627 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
630 * Expect an open brace...
633 if (!strcmp(token
, "DEFINE"))
639 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
640 get_token(fp
, temp
, sizeof(temp
), &linenum
))
642 expand_variables(vars
, token
, temp
, sizeof(token
));
643 set_variable(vars
, attr
, token
);
647 print_fatal_error("Missing DEFINE name and/or value on line %d.",
655 else if (!strcmp(token
, "IGNORE-ERRORS"))
662 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
663 (!strcasecmp(temp
, "yes") || !strcasecmp(temp
, "no")))
665 IgnoreErrors
= !strcasecmp(temp
, "yes");
669 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
676 else if (!strcmp(token
, "INCLUDE"))
683 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
686 * Map the filename to and then run the tests...
689 if (!do_tests(vars
, get_filename(testfile
, filename
, temp
,
700 print_fatal_error("Missing INCLUDE filename on line %d.", linenum
);
708 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
711 * SKIP-IF-DEFINED variable
714 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
716 if (get_variable(vars
, temp
))
721 print_fatal_error("Missing SKIP-IF-DEFINED value on line %d.", linenum
);
726 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
729 * SKIP-IF-NOT-DEFINED variable
732 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
734 if (!get_variable(vars
, temp
))
739 print_fatal_error("Missing SKIP-IF-NOT-DEFINED value on line %d.",
745 else if (!strcmp(token
, "TRANSFER"))
753 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
755 if (!strcmp(temp
, "auto"))
756 Transfer
= _CUPS_TRANSFER_AUTO
;
757 else if (!strcmp(temp
, "chunked"))
758 Transfer
= _CUPS_TRANSFER_CHUNKED
;
759 else if (!strcmp(temp
, "length"))
760 Transfer
= _CUPS_TRANSFER_LENGTH
;
763 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
771 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
778 else if (!strcmp(token
, "VERSION"))
780 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
782 if (!strcmp(temp
, "1.0"))
784 else if (!strcmp(temp
, "1.1"))
786 else if (!strcmp(temp
, "2.0"))
788 else if (!strcmp(temp
, "2.1"))
790 else if (!strcmp(temp
, "2.2"))
794 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
801 print_fatal_error("Missing VERSION number on line %d.", linenum
);
808 else if (strcmp(token
, "{"))
810 print_fatal_error("Unexpected token %s seen on line %d.", token
, linenum
);
816 * Initialize things...
821 if (Output
== _CUPS_OUTPUT_PLIST
)
823 else if (Output
== _CUPS_OUTPUT_TEST
)
824 printf("\"%s\":\n", testfile
);
829 strlcpy(resource
, vars
->resource
, sizeof(resource
));
834 group
= IPP_TAG_ZERO
;
835 ignore_errors
= IgnoreErrors
;
843 strlcpy(name
, testfile
, sizeof(name
));
844 if (strrchr(name
, '.') != NULL
)
845 *strrchr(name
, '.') = '\0';
848 * Parse until we see a close brace...
851 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
853 if (strcasecmp(token
, "COUNT") &&
854 strcasecmp(token
, "DEFINE-MATCH") &&
855 strcasecmp(token
, "DEFINE-NO-MATCH") &&
856 strcasecmp(token
, "DEFINE-VALUE") &&
857 strcasecmp(token
, "IF-DEFINED") &&
858 strcasecmp(token
, "IF-UNDEFINED") &&
859 strcasecmp(token
, "IN-GROUP") &&
860 strcasecmp(token
, "OF-TYPE") &&
861 strcasecmp(token
, "SAME-COUNT-AS") &&
862 strcasecmp(token
, "WITH-VALUE"))
865 if (strcasecmp(token
, "IF-DEFINED") &&
866 strcasecmp(token
, "IF-UNDEFINED"))
869 if (!strcmp(token
, "}"))
871 else if (!strcmp(token
, "{") && lastcol
)
874 * Another collection value
877 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
878 /* Collection value */
882 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
886 * Reallocate memory...
889 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
890 (lastcol
->num_values
+ 1) *
891 sizeof(ipp_value_t
))) == NULL
)
893 print_fatal_error("Unable to allocate memory on line %d.", linenum
);
898 if (tempcol
!= lastcol
)
901 * Reset pointers in the list...
905 request
->prev
->next
= tempcol
;
907 request
->attrs
= tempcol
;
909 lastcol
= request
->current
= request
->last
= tempcol
;
912 lastcol
->values
[lastcol
->num_values
].collection
= col
;
913 lastcol
->num_values
++;
921 else if (!strcmp(token
, "DEFINE"))
927 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
928 get_token(fp
, temp
, sizeof(temp
), &linenum
))
930 expand_variables(vars
, token
, temp
, sizeof(token
));
931 set_variable(vars
, attr
, token
);
935 print_fatal_error("Missing DEFINE name and/or value on line %d.",
941 else if (!strcmp(token
, "IGNORE-ERRORS"))
948 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
949 (!strcasecmp(temp
, "yes") || !strcasecmp(temp
, "no")))
951 ignore_errors
= !strcasecmp(temp
, "yes");
955 print_fatal_error("Missing IGNORE-ERRORS value on line %d.", linenum
);
962 else if (!strcasecmp(token
, "NAME"))
968 get_token(fp
, name
, sizeof(name
), &linenum
);
970 else if (!strcmp(token
, "REQUEST-ID"))
977 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
979 if (isdigit(temp
[0] & 255))
980 request_id
= atoi(temp
);
981 else if (!strcasecmp(temp
, "random"))
982 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
985 print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp
,
993 print_fatal_error("Missing REQUEST-ID value on line %d.", linenum
);
998 else if (!strcmp(token
, "SKIP-IF-DEFINED"))
1001 * SKIP-IF-DEFINED variable
1004 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1006 if (get_variable(vars
, temp
))
1011 print_fatal_error("Missing SKIP-IF-DEFINED value on line %d.",
1017 else if (!strcmp(token
, "SKIP-IF-NOT-DEFINED"))
1020 * SKIP-IF-NOT-DEFINED variable
1023 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1025 if (!get_variable(vars
, temp
))
1030 print_fatal_error("Missing SKIP-IF-NOT-DEFINED value on line %d.",
1036 else if (!strcmp(token
, "SKIP-PREVIOUS-ERROR"))
1039 * SKIP-PREVIOUS-ERROR yes
1040 * SKIP-PREVIOUS-ERROR no
1043 if (get_token(fp
, temp
, sizeof(temp
), &linenum
) &&
1044 (!strcasecmp(temp
, "yes") || !strcasecmp(temp
, "no")))
1046 skip_previous
= !strcasecmp(temp
, "yes");
1050 print_fatal_error("Missing SKIP-PREVIOUS-ERROR value on line %d.", linenum
);
1057 else if (!strcmp(token
, "TRANSFER"))
1065 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1067 if (!strcmp(temp
, "auto"))
1068 transfer
= _CUPS_TRANSFER_AUTO
;
1069 else if (!strcmp(temp
, "chunked"))
1070 transfer
= _CUPS_TRANSFER_CHUNKED
;
1071 else if (!strcmp(temp
, "length"))
1072 transfer
= _CUPS_TRANSFER_LENGTH
;
1075 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
1083 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
1088 else if (!strcasecmp(token
, "VERSION"))
1090 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
1092 if (!strcmp(temp
, "0.0"))
1094 else if (!strcmp(temp
, "1.0"))
1096 else if (!strcmp(temp
, "1.1"))
1098 else if (!strcmp(temp
, "2.0"))
1100 else if (!strcmp(temp
, "2.1"))
1102 else if (!strcmp(temp
, "2.2"))
1106 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
1113 print_fatal_error("Missing VERSION number on line %d.", linenum
);
1118 else if (!strcasecmp(token
, "RESOURCE"))
1124 if (!get_token(fp
, resource
, sizeof(resource
), &linenum
))
1126 print_fatal_error("Missing RESOURCE path on line %d.", linenum
);
1131 else if (!strcasecmp(token
, "OPERATION"))
1137 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1139 print_fatal_error("Missing OPERATION code on line %d.", linenum
);
1144 if ((op
= ippOpValue(token
)) < 0 && (op
= strtol(token
, NULL
, 0)) == 0)
1146 print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token
,
1152 else if (!strcasecmp(token
, "GROUP"))
1155 * Attribute group...
1158 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1160 print_fatal_error("Missing GROUP tag on line %d.", linenum
);
1165 if ((value
= ippTagValue(token
)) < 0)
1167 print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token
, linenum
);
1173 ippAddSeparator(request
);
1177 else if (!strcasecmp(token
, "DELAY"))
1180 * Delay before operation...
1185 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1187 print_fatal_error("Missing DELAY value on line %d.", linenum
);
1192 if ((delay
= atoi(token
)) <= 0)
1194 print_fatal_error("Bad DELAY value \"%s\" on line %d.", token
,
1202 else if (!strcasecmp(token
, "ATTR"))
1208 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1210 print_fatal_error("Missing ATTR value tag on line %d.", linenum
);
1215 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
1217 print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token
,
1223 if (!get_token(fp
, attr
, sizeof(attr
), &linenum
))
1225 print_fatal_error("Missing ATTR name on line %d.", linenum
);
1230 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1232 print_fatal_error("Missing ATTR value on line %d.", linenum
);
1237 expand_variables(vars
, token
, temp
, sizeof(token
));
1241 case IPP_TAG_BOOLEAN
:
1242 if (!strcasecmp(token
, "true"))
1243 ippAddBoolean(request
, group
, attr
, 1);
1245 ippAddBoolean(request
, group
, attr
, atoi(token
));
1248 case IPP_TAG_INTEGER
:
1250 ippAddInteger(request
, group
, value
, attr
, atoi(token
));
1253 case IPP_TAG_RESOLUTION
:
1255 int xres
, /* X resolution */
1256 yres
; /* Y resolution */
1257 char *ptr
; /* Pointer into value */
1259 xres
= yres
= strtol(token
, (char **)&ptr
, 10);
1260 if (ptr
> token
&& xres
> 0)
1263 yres
= strtol(ptr
+ 1, (char **)&ptr
, 10);
1266 if (ptr
<= token
|| xres
<= 0 || yres
<= 0 || !ptr
||
1267 (strcasecmp(ptr
, "dpi") && strcasecmp(ptr
, "dpc") &&
1268 strcasecmp(ptr
, "other")))
1270 print_fatal_error("Bad resolution value \"%s\" on line %d.",
1276 if (!strcasecmp(ptr
, "dpi"))
1277 ippAddResolution(request
, group
, attr
, IPP_RES_PER_INCH
,
1279 else if (!strcasecmp(ptr
, "dpc"))
1280 ippAddResolution(request
, group
, attr
, IPP_RES_PER_CM
,
1283 ippAddResolution(request
, group
, attr
, (ipp_res_t
)0,
1288 case IPP_TAG_RANGE
:
1290 int lowers
[4], /* Lower value */
1291 uppers
[4], /* Upper values */
1292 num_vals
; /* Number of values */
1295 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
1296 lowers
+ 0, uppers
+ 0,
1297 lowers
+ 1, uppers
+ 1,
1298 lowers
+ 2, uppers
+ 2,
1299 lowers
+ 3, uppers
+ 3);
1301 if ((num_vals
& 1) || num_vals
== 0)
1303 print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
1304 "%d.", token
, linenum
);
1309 ippAddRanges(request
, group
, attr
, num_vals
/ 2, lowers
,
1314 case IPP_TAG_BEGIN_COLLECTION
:
1315 if (!strcmp(token
, "{"))
1317 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1318 /* Collection value */
1322 lastcol
= ippAddCollection(request
, group
, attr
, col
);
1333 print_fatal_error("Bad ATTR collection value on line %d.",
1341 print_fatal_error("Unsupported ATTR value tag %s on line %d.",
1342 ippTagString(value
), linenum
);
1346 case IPP_TAG_TEXTLANG
:
1347 case IPP_TAG_NAMELANG
:
1350 case IPP_TAG_KEYWORD
:
1352 case IPP_TAG_URISCHEME
:
1353 case IPP_TAG_CHARSET
:
1354 case IPP_TAG_LANGUAGE
:
1355 case IPP_TAG_MIMETYPE
:
1356 if (!strchr(token
, ','))
1357 ippAddString(request
, group
, value
, attr
, NULL
, token
);
1361 * Multiple string values...
1364 int num_values
; /* Number of values */
1365 char *values
[100], /* Values */
1366 *ptr
; /* Pointer to next value */
1372 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
1375 values
[num_values
] = ptr
;
1379 ippAddStrings(request
, group
, value
, attr
, num_values
,
1380 NULL
, (const char **)values
);
1385 else if (!strcasecmp(token
, "FILE"))
1391 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1393 print_fatal_error("Missing FILE filename on line %d.", linenum
);
1398 expand_variables(vars
, token
, temp
, sizeof(token
));
1399 get_filename(testfile
, filename
, token
, sizeof(filename
));
1401 else if (!strcasecmp(token
, "STATUS"))
1407 if (num_statuses
>= (int)(sizeof(statuses
) / sizeof(statuses
[0])))
1409 print_fatal_error("Too many STATUS's on line %d.", linenum
);
1414 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1416 print_fatal_error("Missing STATUS code on line %d.", linenum
);
1421 if ((statuses
[num_statuses
].status
= ippErrorValue(token
)) < 0 &&
1422 (statuses
[num_statuses
].status
= strtol(token
, NULL
, 0)) == 0)
1424 print_fatal_error("Bad STATUS code \"%s\" on line %d.", token
,
1430 last_status
= statuses
+ num_statuses
;
1433 last_status
->if_defined
= NULL
;
1434 last_status
->if_undefined
= NULL
;
1436 else if (!strcasecmp(token
, "EXPECT"))
1439 * Expected attributes...
1442 if (num_expects
>= (int)(sizeof(expects
) / sizeof(expects
[0])))
1444 print_fatal_error("Too many EXPECT's on line %d.", linenum
);
1449 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1451 print_fatal_error("Missing EXPECT name on line %d.", linenum
);
1456 last_expect
= expects
+ num_expects
;
1459 memset(last_expect
, 0, sizeof(_cups_expect_t
));
1461 if (token
[0] == '!')
1463 last_expect
->not_expect
= 1;
1464 last_expect
->name
= strdup(token
+ 1);
1466 else if (token
[0] == '?')
1468 last_expect
->optional
= 1;
1469 last_expect
->name
= strdup(token
+ 1);
1472 last_expect
->name
= strdup(token
);
1474 else if (!strcasecmp(token
, "COUNT"))
1476 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1478 print_fatal_error("Missing COUNT number on line %d.", linenum
);
1483 if ((i
= atoi(token
)) <= 0)
1485 print_fatal_error("Bad COUNT \"%s\" on line %d.", token
, linenum
);
1491 last_expect
->count
= i
;
1494 print_fatal_error("COUNT without a preceding EXPECT on line %d.",
1500 else if (!strcasecmp(token
, "DEFINE-MATCH"))
1502 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1504 print_fatal_error("Missing DEFINE-MATCH variable on line %d.",
1511 last_expect
->define_match
= strdup(token
);
1514 print_fatal_error("DEFINE-MATCH without a preceding EXPECT on line "
1520 else if (!strcasecmp(token
, "DEFINE-NO-MATCH"))
1522 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1524 print_fatal_error("Missing DEFINE-NO-MATCH variable on line %d.",
1531 last_expect
->define_no_match
= strdup(token
);
1534 print_fatal_error("DEFINE-NO-MATCH without a preceding EXPECT on "
1535 "line %d.", linenum
);
1540 else if (!strcasecmp(token
, "DEFINE-VALUE"))
1542 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1544 print_fatal_error("Missing DEFINE-VALUE variable on line %d.",
1551 last_expect
->define_value
= strdup(token
);
1554 print_fatal_error("DEFINE-VALUE without a preceding EXPECT on line "
1560 else if (!strcasecmp(token
, "OF-TYPE"))
1562 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1564 print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
1571 last_expect
->of_type
= strdup(token
);
1574 print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
1580 else if (!strcasecmp(token
, "IN-GROUP"))
1582 ipp_tag_t in_group
; /* IN-GROUP value */
1585 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1587 print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum
);
1592 if ((in_group
= ippTagValue(token
)) == (ipp_tag_t
)-1)
1595 else if (last_expect
)
1596 last_expect
->in_group
= in_group
;
1599 print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
1605 else if (!strcasecmp(token
, "SAME-COUNT-AS"))
1607 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1609 print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum
);
1615 last_expect
->same_count_as
= strdup(token
);
1618 print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
1624 else if (!strcasecmp(token
, "IF-DEFINED"))
1626 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1628 print_fatal_error("Missing IF-DEFINED name on line %d.", linenum
);
1634 last_expect
->if_defined
= strdup(token
);
1635 else if (last_status
)
1636 last_status
->if_defined
= strdup(token
);
1639 print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
1640 "on line %d.", linenum
);
1645 else if (!strcasecmp(token
, "IF-UNDEFINED"))
1647 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1649 print_fatal_error("Missing IF-UNDEFINED name on line %d.", linenum
);
1655 last_expect
->if_undefined
= strdup(token
);
1656 else if (last_status
)
1657 last_status
->if_undefined
= strdup(token
);
1660 print_fatal_error("IF-UNDEFINED without a preceding EXPECT or STATUS "
1661 "on line %d.", linenum
);
1666 else if (!strcasecmp(token
, "WITH-VALUE"))
1668 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1670 print_fatal_error("Missing WITH-VALUE value on line %d.", linenum
);
1677 tokenptr
= token
+ strlen(token
) - 1;
1678 if (token
[0] == '/' && tokenptr
> token
&& *tokenptr
== '/')
1681 * WITH-VALUE is a POSIX extended regular expression.
1684 last_expect
->with_value
= calloc(1, tokenptr
- token
);
1685 last_expect
->with_regex
= 1;
1687 if (last_expect
->with_value
)
1688 memcpy(last_expect
->with_value
, token
+ 1, tokenptr
- token
- 1);
1693 * WITH-VALUE is a literal value...
1696 last_expect
->with_value
= strdup(token
);
1701 print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
1707 else if (!strcasecmp(token
, "DISPLAY"))
1710 * Display attributes...
1713 if (num_displayed
>= (int)(sizeof(displayed
) / sizeof(displayed
[0])))
1715 print_fatal_error("Too many DISPLAY's on line %d", linenum
);
1720 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1722 print_fatal_error("Missing DISPLAY name on line %d.", linenum
);
1727 displayed
[num_displayed
] = strdup(token
);
1732 print_fatal_error("Unexpected token %s seen on line %d.", token
,
1740 * Submit the IPP request...
1743 request
->request
.op
.version
[0] = version
/ 10;
1744 request
->request
.op
.version
[1] = version
% 10;
1745 request
->request
.op
.operation_id
= op
;
1746 request
->request
.op
.request_id
= request_id
;
1748 if (Output
== _CUPS_OUTPUT_PLIST
)
1751 puts("<key>Name</key>");
1752 print_xml_string("string", name
);
1753 puts("<key>Operation</key>");
1754 print_xml_string("string", ippOpString(op
));
1755 puts("<key>RequestAttributes</key>");
1757 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
1758 print_attr(attrptr
);
1761 else if (Output
== _CUPS_OUTPUT_TEST
)
1765 printf(" %s:\n", ippOpString(op
));
1767 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
1768 print_attr(attrptr
);
1771 printf(" %-69.69s [", name
);
1775 if ((skip_previous
&& !prev_pass
) || skip_test
)
1780 if (Output
== _CUPS_OUTPUT_PLIST
)
1782 puts("<key>Successful</key>");
1784 puts("<key>StatusCode</key>");
1785 print_xml_string("string", "skipped");
1786 puts("<key>ResponseAttributes</key>");
1790 else if (Output
== _CUPS_OUTPUT_TEST
)
1796 if (transfer
== _CUPS_TRANSFER_CHUNKED
||
1797 (transfer
== _CUPS_TRANSFER_AUTO
&& filename
[0]))
1800 * Send request using chunking...
1803 http_status_t status
= cupsSendRequest(http
, request
, resource
, 0);
1805 if (status
== HTTP_CONTINUE
&& filename
[0])
1807 int fd
; /* File to send */
1808 char buffer
[8192]; /* Copy buffer */
1809 ssize_t bytes
; /* Bytes read/written */
1811 if ((fd
= open(filename
, O_RDONLY
| O_BINARY
)) >= 0)
1813 while ((bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
1814 if ((status
= cupsWriteRequestData(http
, buffer
,
1815 bytes
)) != HTTP_CONTINUE
)
1820 snprintf(buffer
, sizeof(buffer
), "%s: %s", filename
, strerror(errno
));
1821 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
1823 status
= HTTP_ERROR
;
1829 if (status
== HTTP_CONTINUE
)
1830 response
= cupsGetResponse(http
, resource
);
1834 else if (filename
[0])
1835 response
= cupsDoFileRequest(http
, request
, resource
, filename
);
1837 response
= cupsDoRequest(http
, request
, resource
);
1843 prev_pass
= pass
= 0;
1846 if (http
->version
!= HTTP_1_1
)
1847 prev_pass
= pass
= 0;
1849 if (response
->request
.status
.version
[0] != (version
/ 10) ||
1850 response
->request
.status
.version
[1] != (version
% 10) ||
1851 response
->request
.status
.request_id
!= request_id
)
1852 prev_pass
= pass
= 0;
1854 if ((attrptr
= ippFindAttribute(response
, "job-id",
1855 IPP_TAG_INTEGER
)) != NULL
)
1857 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
1858 set_variable(vars
, "job-id", temp
);
1861 if ((attrptr
= ippFindAttribute(response
, "job-uri",
1862 IPP_TAG_URI
)) != NULL
)
1863 set_variable(vars
, "job-uri", attrptr
->values
[0].string
.text
);
1865 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id",
1866 IPP_TAG_INTEGER
)) != NULL
)
1868 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
1869 set_variable(vars
, "notify-subscription-id", temp
);
1872 attrptr
= response
->attrs
;
1873 if (!attrptr
|| !attrptr
->name
||
1874 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
1875 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1876 attrptr
->num_values
!= 1 ||
1877 strcmp(attrptr
->name
, "attributes-charset"))
1878 prev_pass
= pass
= 0;
1882 attrptr
= attrptr
->next
;
1883 if (!attrptr
|| !attrptr
->name
||
1884 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
1885 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1886 attrptr
->num_values
!= 1 ||
1887 strcmp(attrptr
->name
, "attributes-natural-language"))
1888 prev_pass
= pass
= 0;
1891 if ((attrptr
= ippFindAttribute(response
, "status-message",
1892 IPP_TAG_ZERO
)) != NULL
&&
1893 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
1894 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1895 attrptr
->num_values
!= 1 ||
1896 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1897 strlen(attrptr
->values
[0].string
.text
) > 255)))
1898 prev_pass
= pass
= 0;
1900 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
1901 IPP_TAG_ZERO
)) != NULL
&&
1902 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
1903 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1904 attrptr
->num_values
!= 1 ||
1905 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1906 strlen(attrptr
->values
[0].string
.text
) > 1023)))
1907 prev_pass
= pass
= 0;
1909 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
1911 attrptr
= attrptr
->next
)
1913 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
1915 prev_pass
= pass
= 0;
1919 if (!validate_attr(attrptr
, 0))
1921 prev_pass
= pass
= 0;
1926 for (i
= 0; i
< num_statuses
; i
++)
1928 if (statuses
[i
].if_defined
&&
1929 !get_variable(vars
, statuses
[i
].if_defined
))
1932 if (statuses
[i
].if_undefined
&&
1933 get_variable(vars
, statuses
[i
].if_undefined
))
1936 if (response
->request
.status
.status_code
== statuses
[i
].status
)
1940 if (i
== num_statuses
&& num_statuses
> 0)
1941 prev_pass
= pass
= 0;
1944 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
1946 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
1949 if (expect
->if_undefined
&& get_variable(vars
, expect
->if_undefined
))
1952 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
1954 if ((found
&& expect
->not_expect
) ||
1955 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
1956 (found
&& !expect_matches(expect
, found
->value_tag
)) ||
1957 (found
&& expect
->in_group
&&
1958 found
->group_tag
!= expect
->in_group
))
1960 if (expect
->define_no_match
)
1961 set_variable(vars
, expect
->define_no_match
, "1");
1962 else if (!expect
->define_match
)
1963 prev_pass
= pass
= 0;
1969 !with_value(expect
->with_value
, expect
->with_regex
, found
))
1971 if (expect
->define_no_match
)
1972 set_variable(vars
, expect
->define_no_match
, "1");
1973 else if (!expect
->define_match
)
1974 prev_pass
= pass
= 0;
1979 if (found
&& expect
->count
> 0 && found
->num_values
!= expect
->count
)
1981 if (expect
->define_no_match
)
1982 set_variable(vars
, expect
->define_no_match
, "1");
1983 else if (!expect
->define_match
)
1984 prev_pass
= pass
= 0;
1989 if (found
&& expect
->same_count_as
)
1991 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
1994 if (!attrptr
|| attrptr
->num_values
!= found
->num_values
)
1996 if (expect
->define_no_match
)
1997 set_variable(vars
, expect
->define_no_match
, "1");
1998 else if (!expect
->define_match
)
1999 prev_pass
= pass
= 0;
2005 if (found
&& expect
->define_match
)
2006 set_variable(vars
, expect
->define_match
, "1");
2008 if (found
&& expect
->define_value
)
2010 _ippAttrString(found
, token
, sizeof(token
));
2011 set_variable(vars
, expect
->define_value
, token
);
2017 if (Output
== _CUPS_OUTPUT_PLIST
)
2019 puts("<key>Successful</key>");
2020 puts(prev_pass
? "<true />" : "<false />");
2021 puts("<key>StatusCode</key>");
2022 print_xml_string("string", ippErrorString(cupsLastError()));
2023 puts("<key>ResponseAttributes</key>");
2025 for (attrptr
= response
? response
->attrs
: NULL
;
2027 attrptr
= attrptr
->next
)
2028 print_attr(attrptr
);
2031 else if (Output
== _CUPS_OUTPUT_TEST
)
2033 puts(prev_pass
? "PASS]" : "FAIL]");
2035 if (Verbosity
&& response
)
2037 printf(" RECEIVED: %lu bytes in response\n",
2038 (unsigned long)ippLength(response
));
2039 printf(" status-code = %x (%s)\n", cupsLastError(),
2040 ippErrorString(cupsLastError()));
2042 for (attrptr
= response
->attrs
;
2044 attrptr
= attrptr
->next
)
2046 print_attr(attrptr
);
2050 else if (!prev_pass
)
2051 fprintf(stderr
, "%s\n", cupsLastErrorString());
2053 if (prev_pass
&& Output
!= _CUPS_OUTPUT_PLIST
&&
2054 Output
!= _CUPS_OUTPUT_QUIET
&& !Verbosity
&& num_displayed
> 0)
2056 if (Output
>= _CUPS_OUTPUT_LIST
)
2058 size_t width
; /* Length of value */
2061 for (i
= 0; i
< num_displayed
; i
++)
2063 widths
[i
] = strlen(displayed
[i
]);
2065 for (attrptr
= ippFindAttribute(response
, displayed
[i
], IPP_TAG_ZERO
);
2067 attrptr
= ippFindNextAttribute(response
, displayed
[i
],
2070 width
= _ippAttrString(attrptr
, NULL
, 0);
2071 if (width
> widths
[i
])
2076 if (Output
== _CUPS_OUTPUT_CSV
)
2077 print_csv(NULL
, num_displayed
, displayed
, widths
);
2079 print_line(NULL
, num_displayed
, displayed
, widths
);
2081 attrptr
= response
->attrs
;
2085 while (attrptr
&& attrptr
->group_tag
<= IPP_TAG_OPERATION
)
2086 attrptr
= attrptr
->next
;
2090 if (Output
== _CUPS_OUTPUT_CSV
)
2091 print_csv(attrptr
, num_displayed
, displayed
, widths
);
2093 print_line(attrptr
, num_displayed
, displayed
, widths
);
2095 while (attrptr
&& attrptr
->group_tag
> IPP_TAG_OPERATION
)
2096 attrptr
= attrptr
->next
;
2102 for (attrptr
= response
->attrs
;
2104 attrptr
= attrptr
->next
)
2108 for (i
= 0; i
< num_displayed
; i
++)
2110 if (!strcmp(displayed
[i
], attrptr
->name
))
2112 print_attr(attrptr
);
2120 else if (!prev_pass
)
2122 if (Output
== _CUPS_OUTPUT_PLIST
)
2124 puts("<key>Errors</key>");
2128 if (http
->version
!= HTTP_1_1
)
2129 print_test_error("Bad HTTP version (%d.%d)", http
->version
/ 100,
2130 http
->version
% 100);
2133 print_test_error("IPP request failed with status %s (%s)",
2134 ippErrorString(cupsLastError()),
2135 cupsLastErrorString());
2138 if (response
->request
.status
.version
[0] != (version
/ 10) ||
2139 response
->request
.status
.version
[1] != (version
% 10))
2140 print_test_error("Bad version %d.%d in response - expected %d.%d "
2141 "(RFC 2911 section 3.1.8).",
2142 response
->request
.status
.version
[0],
2143 response
->request
.status
.version
[1],
2144 version
/ 10, version
% 10);
2146 if (response
->request
.status
.request_id
!= request_id
)
2147 print_test_error("Bad request ID %d in response - expected %d "
2148 "(RFC 2911 section 3.1.1)",
2149 response
->request
.status
.request_id
, request_id
);
2151 attrptr
= response
->attrs
;
2153 print_test_error("Missing first attribute \"attributes-charset "
2154 "(charset)\" in group operation-attributes-tag "
2155 "(RFC 2911 section 3.1.4).");
2158 if (!attrptr
->name
||
2159 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
2160 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2161 attrptr
->num_values
!= 1 ||
2162 strcmp(attrptr
->name
, "attributes-charset"))
2163 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
2164 "expected \"attributes-charset (charset)\" in "
2165 "group operation-attributes-tag (RFC 2911 section "
2167 attrptr
->name
? attrptr
->name
: "(null)",
2168 attrptr
->num_values
> 1 ? "1setOf " : "",
2169 ippTagString(attrptr
->value_tag
),
2170 ippTagString(attrptr
->group_tag
));
2172 attrptr
= attrptr
->next
;
2174 print_test_error("Missing second attribute \"attributes-natural-"
2175 "language (naturalLanguage)\" in group "
2176 "operation-attributes-tag (RFC 2911 section "
2178 else if (!attrptr
->name
||
2179 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
2180 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
2181 attrptr
->num_values
!= 1 ||
2182 strcmp(attrptr
->name
, "attributes-natural-language"))
2183 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
2184 "expected \"attributes-natural-language "
2185 "(naturalLanguage)\" in group "
2186 "operation-attributes-tag (RFC 2911 section "
2188 attrptr
->name
? attrptr
->name
: "(null)",
2189 attrptr
->num_values
> 1 ? "1setOf " : "",
2190 ippTagString(attrptr
->value_tag
),
2191 ippTagString(attrptr
->group_tag
));
2194 if ((attrptr
= ippFindAttribute(response
, "status-message",
2195 IPP_TAG_ZERO
)) != NULL
)
2197 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2198 print_test_error("status-message (text(255)) has wrong value tag "
2199 "%s (RFC 2911 section 3.1.6.2).",
2200 ippTagString(attrptr
->value_tag
));
2201 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2202 print_test_error("status-message (text(255)) has wrong group tag "
2203 "%s (RFC 2911 section 3.1.6.2).",
2204 ippTagString(attrptr
->group_tag
));
2205 if (attrptr
->num_values
!= 1)
2206 print_test_error("status-message (text(255)) has %d values "
2207 "(RFC 2911 section 3.1.6.2).",
2208 attrptr
->num_values
);
2209 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2210 strlen(attrptr
->values
[0].string
.text
) > 255)
2211 print_test_error("status-message (text(255)) has bad length %d"
2212 " (RFC 2911 section 3.1.6.2).",
2213 (int)strlen(attrptr
->values
[0].string
.text
));
2216 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
2217 IPP_TAG_ZERO
)) != NULL
)
2219 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
2220 print_test_error("detailed-status-message (text(MAX)) has wrong "
2221 "value tag %s (RFC 2911 section 3.1.6.3).",
2222 ippTagString(attrptr
->value_tag
));
2223 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
2224 print_test_error("detailed-status-message (text(MAX)) has wrong "
2225 "group tag %s (RFC 2911 section 3.1.6.3).",
2226 ippTagString(attrptr
->group_tag
));
2227 if (attrptr
->num_values
!= 1)
2228 print_test_error("detailed-status-message (text(MAX)) has %d values"
2229 " (RFC 2911 section 3.1.6.3).",
2230 attrptr
->num_values
);
2231 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
2232 strlen(attrptr
->values
[0].string
.text
) > 1023)
2233 print_test_error("detailed-status-message (text(MAX)) has bad "
2234 "length %d (RFC 2911 section 3.1.6.3).",
2235 (int)strlen(attrptr
->values
[0].string
.text
));
2238 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
2240 attrptr
= attrptr
->next
)
2242 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
2243 print_test_error("Attribute groups out of order (%s < %s)",
2244 ippTagString(attrptr
->group_tag
),
2245 ippTagString(group
));
2247 validate_attr(attrptr
, 1);
2250 for (i
= 0; i
< num_statuses
; i
++)
2252 if (statuses
[i
].if_defined
&&
2253 !get_variable(vars
, statuses
[i
].if_defined
))
2256 if (statuses
[i
].if_undefined
&&
2257 get_variable(vars
, statuses
[i
].if_undefined
))
2260 if (response
->request
.status
.status_code
== statuses
[i
].status
)
2264 if (i
== num_statuses
&& num_statuses
> 0)
2266 print_test_error("Bad status-code (%s)",
2267 ippErrorString(cupsLastError()));
2268 print_test_error("status-message=\"%s\"", cupsLastErrorString());
2271 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2273 if (expect
->define_match
|| expect
->define_no_match
)
2276 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
2279 if (expect
->if_undefined
&& get_variable(vars
, expect
->if_undefined
))
2282 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
2284 if (found
&& expect
->not_expect
)
2285 print_test_error("NOT EXPECTED: %s", expect
->name
);
2286 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
2287 print_test_error("EXPECTED: %s", expect
->name
);
2290 if (!expect_matches(expect
, found
->value_tag
))
2291 print_test_error("EXPECTED: %s OF-TYPE %s (got %s)",
2292 expect
->name
, expect
->of_type
,
2293 ippTagString(found
->value_tag
));
2295 if (expect
->in_group
&& found
->group_tag
!= expect
->in_group
)
2296 print_test_error("EXPECTED: %s IN-GROUP %s (got %s).",
2297 expect
->name
, ippTagString(expect
->in_group
),
2298 ippTagString(found
->group_tag
));
2300 if (!with_value(expect
->with_value
, expect
->with_regex
, found
))
2302 if (expect
->with_regex
)
2303 print_test_error("EXPECTED: %s WITH-VALUE /%s/",
2304 expect
->name
, expect
->with_value
);
2306 print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
2307 expect
->name
, expect
->with_value
);
2310 if (expect
->count
> 0 && found
->num_values
!= expect
->count
)
2312 print_test_error("EXPECTED: %s COUNT %d (got %d)", expect
->name
,
2313 expect
->count
, found
->num_values
);
2316 if (expect
->same_count_as
)
2318 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
2322 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2323 "(not returned)", expect
->name
,
2324 found
->num_values
, expect
->same_count_as
);
2325 else if (attrptr
->num_values
!= found
->num_values
)
2326 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
2327 "(%d values)", expect
->name
, found
->num_values
,
2328 expect
->same_count_as
, attrptr
->num_values
);
2334 if (Output
== _CUPS_OUTPUT_PLIST
)
2338 if (Output
== _CUPS_OUTPUT_PLIST
)
2343 ippDelete(response
);
2346 for (i
= 0; i
< num_statuses
; i
++)
2348 if (statuses
[i
].if_defined
)
2349 free(statuses
[i
].if_defined
);
2350 if (statuses
[i
].if_undefined
)
2351 free(statuses
[i
].if_undefined
);
2355 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2358 if (expect
->of_type
)
2359 free(expect
->of_type
);
2360 if (expect
->same_count_as
)
2361 free(expect
->same_count_as
);
2362 if (expect
->if_defined
)
2363 free(expect
->if_defined
);
2364 if (expect
->if_undefined
)
2365 free(expect
->if_undefined
);
2366 if (expect
->with_value
)
2367 free(expect
->with_value
);
2368 if (expect
->define_match
)
2369 free(expect
->define_match
);
2370 if (expect
->define_no_match
)
2371 free(expect
->define_no_match
);
2372 if (expect
->define_value
)
2373 free(expect
->define_value
);
2377 for (i
= 0; i
< num_displayed
; i
++)
2381 if (!ignore_errors
&& !prev_pass
)
2392 ippDelete(response
);
2394 for (i
= 0; i
< num_statuses
; i
++)
2396 if (statuses
[i
].if_defined
)
2397 free(statuses
[i
].if_defined
);
2398 if (statuses
[i
].if_undefined
)
2399 free(statuses
[i
].if_undefined
);
2402 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2405 if (expect
->of_type
)
2406 free(expect
->of_type
);
2407 if (expect
->same_count_as
)
2408 free(expect
->same_count_as
);
2409 if (expect
->if_defined
)
2410 free(expect
->if_defined
);
2411 if (expect
->if_undefined
)
2412 free(expect
->if_undefined
);
2413 if (expect
->with_value
)
2414 free(expect
->with_value
);
2415 if (expect
->define_match
)
2416 free(expect
->define_match
);
2417 if (expect
->define_no_match
)
2418 free(expect
->define_no_match
);
2419 if (expect
->define_value
)
2420 free(expect
->define_value
);
2423 for (i
= 0; i
< num_displayed
; i
++)
2431 * 'expand_variables()' - Expand variables in a string.
2435 expand_variables(_cups_vars_t
*vars
, /* I - Variables */
2436 char *dst
, /* I - Destination string buffer */
2437 const char *src
, /* I - Source string */
2438 size_t dstsize
) /* I - Size of destination buffer */
2440 char *dstptr
, /* Pointer into destination */
2441 *dstend
, /* End of destination */
2442 temp
[256], /* Temporary string */
2443 *tempptr
; /* Pointer into temporary string */
2444 const char *value
; /* Value to substitute */
2448 dstend
= dst
+ dstsize
- 1;
2450 while (*src
&& dstptr
< dstend
)
2455 * Substitute a string/number...
2458 if (!strncmp(src
, "$$", 2))
2463 else if (!strncmp(src
, "$ENV[", 5))
2465 strlcpy(temp
, src
+ 5, sizeof(temp
));
2467 for (tempptr
= temp
; *tempptr
; tempptr
++)
2468 if (*tempptr
== ']')
2474 value
= getenv(temp
);
2475 src
+= tempptr
- temp
+ 5;
2479 strlcpy(temp
, src
+ 1, sizeof(temp
));
2481 for (tempptr
= temp
; *tempptr
; tempptr
++)
2482 if (!isalnum(*tempptr
& 255) && *tempptr
!= '-' && *tempptr
!= '_')
2488 if (!strcmp(temp
, "uri"))
2490 else if (!strcmp(temp
, "filename"))
2491 value
= vars
->filename
;
2492 else if (!strcmp(temp
, "scheme") || !strcmp(temp
, "method"))
2493 value
= vars
->scheme
;
2494 else if (!strcmp(temp
, "username"))
2495 value
= vars
->userpass
;
2496 else if (!strcmp(temp
, "hostname"))
2497 value
= vars
->hostname
;
2498 else if (!strcmp(temp
, "port"))
2500 snprintf(temp
, sizeof(temp
), "%d", vars
->port
);
2503 else if (!strcmp(temp
, "resource"))
2504 value
= vars
->resource
;
2505 else if (!strcmp(temp
, "user"))
2508 value
= get_variable(vars
, temp
);
2510 src
+= tempptr
- temp
+ 1;
2520 strlcpy(dstptr
, value
, dstend
- dstptr
+ 1);
2521 dstptr
+= strlen(dstptr
);
2533 * 'expect_matches()' - Return true if the tag matches the specification.
2536 static int /* O - 1 if matches, 0 otherwise */
2538 _cups_expect_t
*expect
, /* I - Expected attribute */
2539 ipp_tag_t value_tag
) /* I - Value tag for attribute */
2541 int match
; /* Match? */
2542 char *of_type
, /* Type name to match */
2543 *next
, /* Next name to match */
2544 sep
; /* Separator character */
2548 * If we don't expect a particular type, return immediately...
2551 if (!expect
->of_type
)
2555 * Parse the "of_type" value since the string can contain multiple attribute
2556 * types separated by "," or "|"...
2559 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
2562 * Find the next separator, and set it (temporarily) to nul if present.
2565 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
2567 if ((sep
= *next
) != '\0')
2571 * Support some meta-types to make it easier to write the test file.
2574 if (!strcmp(of_type
, "text"))
2575 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
2576 else if (!strcmp(of_type
, "name"))
2577 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
2578 else if (!strcmp(of_type
, "collection"))
2579 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
2581 match
= value_tag
== ippTagValue(of_type
);
2584 * Restore the separator if we have one...
2596 * 'get_collection()' - Get a collection value from the current test file.
2599 static ipp_t
* /* O - Collection value */
2600 get_collection(_cups_vars_t
*vars
, /* I - Variables */
2601 FILE *fp
, /* I - File to read from */
2602 int *linenum
) /* IO - Line number */
2604 char token
[1024], /* Token from file */
2605 temp
[1024], /* Temporary string */
2606 attr
[128]; /* Attribute name */
2607 ipp_tag_t value
; /* Current value type */
2608 ipp_t
*col
= ippNew(); /* Collection value */
2609 ipp_attribute_t
*lastcol
= NULL
; /* Last collection attribute */
2612 while (get_token(fp
, token
, sizeof(token
), linenum
) != NULL
)
2614 if (!strcmp(token
, "}"))
2616 else if (!strcmp(token
, "{") && lastcol
)
2619 * Another collection value
2622 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
2623 /* Collection value */
2627 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
2631 * Reallocate memory...
2634 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
2635 (lastcol
->num_values
+ 1) *
2636 sizeof(ipp_value_t
))) == NULL
)
2638 print_fatal_error("Unable to allocate memory on line %d.", *linenum
);
2642 if (tempcol
!= lastcol
)
2645 * Reset pointers in the list...
2649 col
->prev
->next
= tempcol
;
2651 col
->attrs
= tempcol
;
2653 lastcol
= col
->current
= col
->last
= tempcol
;
2656 lastcol
->values
[lastcol
->num_values
].collection
= subcol
;
2657 lastcol
->num_values
++;
2662 else if (!strcasecmp(token
, "MEMBER"))
2670 if (!get_token(fp
, token
, sizeof(token
), linenum
))
2672 print_fatal_error("Missing MEMBER value tag on line %d.", *linenum
);
2676 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
2678 print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token
,
2683 if (!get_token(fp
, attr
, sizeof(attr
), linenum
))
2685 print_fatal_error("Missing MEMBER name on line %d.", *linenum
);
2689 if (!get_token(fp
, temp
, sizeof(temp
), linenum
))
2691 print_fatal_error("Missing MEMBER value on line %d.", *linenum
);
2695 expand_variables(vars
, token
, temp
, sizeof(token
));
2699 case IPP_TAG_BOOLEAN
:
2700 if (!strcasecmp(token
, "true"))
2701 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, 1);
2703 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, atoi(token
));
2706 case IPP_TAG_INTEGER
:
2708 ippAddInteger(col
, IPP_TAG_ZERO
, value
, attr
, atoi(token
));
2711 case IPP_TAG_RESOLUTION
:
2713 int xres
, /* X resolution */
2714 yres
; /* Y resolution */
2715 char units
[6]; /* Units */
2717 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
2718 (strcasecmp(units
, "dpi") && strcasecmp(units
, "dpc") &&
2719 strcasecmp(units
, "other")))
2721 print_fatal_error("Bad resolution value \"%s\" on line %d.",
2726 if (!strcasecmp(units
, "dpi"))
2727 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2729 else if (!strcasecmp(units
, "dpc"))
2730 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2733 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2738 case IPP_TAG_RANGE
:
2740 int lowers
[4], /* Lower value */
2741 uppers
[4], /* Upper values */
2742 num_vals
; /* Number of values */
2745 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
2746 lowers
+ 0, uppers
+ 0,
2747 lowers
+ 1, uppers
+ 1,
2748 lowers
+ 2, uppers
+ 2,
2749 lowers
+ 3, uppers
+ 3);
2751 if ((num_vals
& 1) || num_vals
== 0)
2753 print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
2758 ippAddRanges(col
, IPP_TAG_ZERO
, attr
, num_vals
/ 2, lowers
,
2763 case IPP_TAG_BEGIN_COLLECTION
:
2764 if (!strcmp(token
, "{"))
2766 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
2767 /* Collection value */
2771 lastcol
= ippAddCollection(col
, IPP_TAG_ZERO
, attr
, subcol
);
2779 print_fatal_error("Bad collection value on line %d.", *linenum
);
2785 if (!strchr(token
, ','))
2786 ippAddString(col
, IPP_TAG_ZERO
, value
, attr
, NULL
, token
);
2790 * Multiple string values...
2793 int num_values
; /* Number of values */
2794 char *values
[100], /* Values */
2795 *ptr
; /* Pointer to next value */
2801 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
2804 values
[num_values
] = ptr
;
2808 ippAddStrings(col
, IPP_TAG_ZERO
, value
, attr
, num_values
,
2809 NULL
, (const char **)values
);
2819 * If we get here there was a parse error; free memory and return.
2831 * 'get_filename()' - Get a filename based on the current test file.
2834 static char * /* O - Filename */
2835 get_filename(const char *testfile
, /* I - Current test file */
2836 char *dst
, /* I - Destination filename */
2837 const char *src
, /* I - Source filename */
2838 size_t dstsize
) /* I - Size of destination buffer */
2840 char *dstptr
; /* Pointer into destination */
2841 _cups_globals_t
*cg
= _cupsGlobals();
2845 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
2848 * Map <filename> to CUPS_DATADIR/ipptool/filename...
2851 snprintf(dst
, dstsize
, "%s/ipptool/%s", cg
->cups_datadir
, src
+ 1);
2852 dstptr
= dst
+ strlen(dst
) - 1;
2856 else if (*src
== '/' || !strchr(testfile
, '/'))
2859 * Use the path as-is...
2862 strlcpy(dst
, src
, dstsize
);
2867 * Make path relative to testfile...
2870 strlcpy(dst
, testfile
, dstsize
);
2871 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
2874 dstptr
= dst
; /* Should never happen */
2876 strlcpy(dstptr
, src
, dstsize
- (dstptr
- dst
));
2884 * 'get_token()' - Get a token from a file.
2887 static char * /* O - Token from file or NULL on EOF */
2888 get_token(FILE *fp
, /* I - File to read from */
2889 char *buf
, /* I - Buffer to read into */
2890 int buflen
, /* I - Length of buffer */
2891 int *linenum
) /* IO - Current line number */
2893 int ch
, /* Character from file */
2894 quote
; /* Quoting character */
2895 char *bufptr
, /* Pointer into buffer */
2896 *bufend
; /* End of buffer */
2902 * Skip whitespace...
2905 while (isspace(ch
= getc(fp
)))
2917 else if (ch
== '\'' || ch
== '\"')
2920 * Quoted text or regular expression...
2925 bufend
= buf
+ buflen
- 1;
2927 while ((ch
= getc(fp
)) != EOF
)
2932 * Escape next character...
2935 if (bufptr
< bufend
)
2938 if ((ch
= getc(fp
)) != EOF
&& bufptr
< bufend
)
2941 else if (ch
== quote
)
2943 else if (bufptr
< bufend
)
2957 while ((ch
= getc(fp
)) != EOF
)
2966 * Whitespace delimited text...
2972 bufend
= buf
+ buflen
- 1;
2974 while ((ch
= getc(fp
)) != EOF
)
2975 if (isspace(ch
) || ch
== '#')
2977 else if (bufptr
< bufend
)
2982 else if (ch
== '\n')
2994 * 'get_variable()' - Get the value of a variable.
2997 static char * /* O - Value or NULL */
2998 get_variable(_cups_vars_t
*vars
, /* I - Variables */
2999 const char *name
) /* I - Variable name */
3001 _cups_var_t key
, /* Search key */
3002 *match
; /* Matching variable, if any */
3005 key
.name
= (char *)name
;
3006 match
= cupsArrayFind(vars
->vars
, &key
);
3008 return (match
? match
->value
: NULL
);
3013 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
3017 static char * /* O - ISO 8601 date/time string */
3018 iso_date(ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
3020 unsigned year
= (date
[0] << 8) + date
[1];
3022 static char buffer
[255]; /* String buffer */
3025 if (date
[9] == 0 && date
[10] == 0)
3026 snprintf(buffer
, sizeof(buffer
), "%04u-%02u-%02uT%02u:%02u:%02uZ",
3027 year
, date
[2], date
[3], date
[4], date
[5], date
[6]);
3029 snprintf(buffer
, sizeof(buffer
), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
3030 year
, date
[2], date
[3], date
[4], date
[5], date
[6],
3031 date
[8], date
[9], date
[10]);
3038 * 'print_attr()' - Print an attribute on the screen.
3042 print_attr(ipp_attribute_t
*attr
) /* I - Attribute to print */
3044 int i
; /* Looping var */
3045 ipp_attribute_t
*colattr
; /* Collection attribute */
3048 if (Output
== _CUPS_OUTPUT_PLIST
)
3052 printf("<key>%s</key>\n<true />\n", ippTagString(attr
->group_tag
));
3056 print_xml_string("key", attr
->name
);
3057 if (attr
->num_values
> 1)
3060 else if (Output
== _CUPS_OUTPUT_TEST
)
3064 puts(" -- separator --");
3068 printf(" %s (%s%s) = ", attr
->name
,
3069 attr
->num_values
> 1 ? "1setOf " : "",
3070 ippTagString(attr
->value_tag
));
3073 switch (attr
->value_tag
)
3075 case IPP_TAG_INTEGER
:
3077 for (i
= 0; i
< attr
->num_values
; i
++)
3078 if (Output
== _CUPS_OUTPUT_PLIST
)
3079 printf("<integer>%d</integer>\n", attr
->values
[i
].integer
);
3081 printf("%d ", attr
->values
[i
].integer
);
3084 case IPP_TAG_BOOLEAN
:
3085 for (i
= 0; i
< attr
->num_values
; i
++)
3086 if (Output
== _CUPS_OUTPUT_PLIST
)
3087 puts(attr
->values
[i
].boolean
? "<true />" : "<false />");
3088 else if (attr
->values
[i
].boolean
)
3089 fputs("true ", stdout
);
3091 fputs("false ", stdout
);
3094 case IPP_TAG_RANGE
:
3095 for (i
= 0; i
< attr
->num_values
; i
++)
3096 if (Output
== _CUPS_OUTPUT_PLIST
)
3097 printf("<dict><key>lower</key><integer>%d</integer>"
3098 "<key>upper</key><integer>%d</integer></dict>\n",
3099 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
3101 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3102 attr
->values
[i
].range
.upper
);
3105 case IPP_TAG_RESOLUTION
:
3106 for (i
= 0; i
< attr
->num_values
; i
++)
3107 if (Output
== _CUPS_OUTPUT_PLIST
)
3108 printf("<dict><key>xres</key><integer>%d</integer>"
3109 "<key>yres</key><integer>%d</integer>"
3110 "<key>units</key><string>%s</string></dict>\n",
3111 attr
->values
[i
].resolution
.xres
,
3112 attr
->values
[i
].resolution
.yres
,
3113 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3116 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3117 attr
->values
[i
].resolution
.yres
,
3118 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3123 for (i
= 0; i
< attr
->num_values
; i
++)
3124 if (Output
== _CUPS_OUTPUT_PLIST
)
3125 printf("<date>%s</date>\n", iso_date(attr
->values
[i
].date
));
3127 printf("%s ", iso_date(attr
->values
[i
].date
));
3130 case IPP_TAG_STRING
:
3133 case IPP_TAG_KEYWORD
:
3134 case IPP_TAG_CHARSET
:
3136 case IPP_TAG_MIMETYPE
:
3137 case IPP_TAG_LANGUAGE
:
3138 for (i
= 0; i
< attr
->num_values
; i
++)
3139 if (Output
== _CUPS_OUTPUT_PLIST
)
3140 print_xml_string("string", attr
->values
[i
].string
.text
);
3142 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3145 case IPP_TAG_TEXTLANG
:
3146 case IPP_TAG_NAMELANG
:
3147 for (i
= 0; i
< attr
->num_values
; i
++)
3148 if (Output
== _CUPS_OUTPUT_PLIST
)
3150 fputs("<dict><key>language</key><string>", stdout
);
3151 print_xml_string(NULL
, attr
->values
[i
].string
.charset
);
3152 fputs("</string><key>string</key><string>", stdout
);
3153 print_xml_string(NULL
, attr
->values
[i
].string
.text
);
3154 puts("</string></dict>");
3157 printf("\"%s\",%s ", attr
->values
[i
].string
.text
,
3158 attr
->values
[i
].string
.charset
);
3161 case IPP_TAG_BEGIN_COLLECTION
:
3162 for (i
= 0; i
< attr
->num_values
; i
++)
3164 if (Output
== _CUPS_OUTPUT_PLIST
)
3167 for (colattr
= attr
->values
[i
].collection
->attrs
;
3169 colattr
= colattr
->next
)
3170 print_attr(colattr
);
3178 print_col(attr
->values
[i
].collection
);
3184 if (Output
== _CUPS_OUTPUT_PLIST
)
3185 printf("<string><<%s>></string>\n",
3186 ippTagString(attr
->value_tag
));
3188 fputs(ippTagString(attr
->value_tag
), stdout
);
3192 if (Output
== _CUPS_OUTPUT_PLIST
)
3194 if (attr
->num_values
> 1)
3203 * 'print_col()' - Print a collection attribute on the screen.
3207 print_col(ipp_t
*col
) /* I - Collection attribute to print */
3209 int i
; /* Looping var */
3210 ipp_attribute_t
*attr
; /* Current attribute in collection */
3213 fputs("{ ", stdout
);
3214 for (attr
= col
->attrs
; attr
; attr
= attr
->next
)
3216 printf("%s (%s%s) = ", attr
->name
, attr
->num_values
> 1 ? "1setOf " : "",
3217 ippTagString(attr
->value_tag
));
3219 switch (attr
->value_tag
)
3221 case IPP_TAG_INTEGER
:
3223 for (i
= 0; i
< attr
->num_values
; i
++)
3224 printf("%d ", attr
->values
[i
].integer
);
3227 case IPP_TAG_BOOLEAN
:
3228 for (i
= 0; i
< attr
->num_values
; i
++)
3229 if (attr
->values
[i
].boolean
)
3235 case IPP_TAG_NOVALUE
:
3239 case IPP_TAG_RANGE
:
3240 for (i
= 0; i
< attr
->num_values
; i
++)
3241 printf("%d-%d ", attr
->values
[i
].range
.lower
,
3242 attr
->values
[i
].range
.upper
);
3245 case IPP_TAG_RESOLUTION
:
3246 for (i
= 0; i
< attr
->num_values
; i
++)
3247 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
3248 attr
->values
[i
].resolution
.yres
,
3249 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
3253 case IPP_TAG_STRING
:
3256 case IPP_TAG_KEYWORD
:
3257 case IPP_TAG_CHARSET
:
3259 case IPP_TAG_MIMETYPE
:
3260 case IPP_TAG_LANGUAGE
:
3261 for (i
= 0; i
< attr
->num_values
; i
++)
3262 printf("\"%s\" ", attr
->values
[i
].string
.text
);
3265 case IPP_TAG_TEXTLANG
:
3266 case IPP_TAG_NAMELANG
:
3267 for (i
= 0; i
< attr
->num_values
; i
++)
3268 printf("\"%s\",%s ", attr
->values
[i
].string
.text
,
3269 attr
->values
[i
].string
.charset
);
3272 case IPP_TAG_BEGIN_COLLECTION
:
3273 for (i
= 0; i
< attr
->num_values
; i
++)
3275 print_col(attr
->values
[i
].collection
);
3281 break; /* anti-compiler-warning-code */
3290 * 'print_csv()' - Print a line of CSV text.
3295 ipp_attribute_t
*attr
, /* I - First attribute for line */
3296 int num_displayed
, /* I - Number of attributes to display */
3297 char **displayed
, /* I - Attributes to display */
3298 size_t *widths
) /* I - Column widths */
3300 int i
; /* Looping var */
3301 size_t maxlength
; /* Max length of all columns */
3302 char *buffer
, /* String buffer */
3303 *bufptr
; /* Pointer into buffer */
3304 ipp_attribute_t
*current
; /* Current attribute */
3308 * Get the maximum string length we have to show and allocate...
3311 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
3312 if (widths
[i
] > maxlength
)
3313 maxlength
= widths
[i
];
3317 if ((buffer
= malloc(maxlength
)) == NULL
)
3321 * Loop through the attributes to display...
3326 for (i
= 0; i
< num_displayed
; i
++)
3333 for (current
= attr
; current
; current
= current
->next
)
3337 else if (!strcmp(current
->name
, displayed
[i
]))
3339 _ippAttrString(current
, buffer
, maxlength
);
3344 if (strchr(buffer
, ',') != NULL
|| strchr(buffer
, '\"') != NULL
||
3345 strchr(buffer
, '\\') != NULL
)
3348 for (bufptr
= buffer
; *bufptr
; bufptr
++)
3350 if (*bufptr
== '\\' || *bufptr
== '\"')
3357 fputs(buffer
, stdout
);
3363 for (i
= 0; i
< num_displayed
; i
++)
3368 fputs(displayed
[i
], stdout
);
3378 * 'print_fatal_error()' - Print a fatal error message.
3382 print_fatal_error(const char *s
, /* I - Printf-style format string */
3383 ...) /* I - Additional arguments as needed */
3385 char buffer
[10240]; /* Format buffer */
3386 va_list ap
; /* Pointer to arguments */
3390 * Format the error message...
3394 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
3401 if (Output
== _CUPS_OUTPUT_PLIST
)
3404 print_xml_trailer(0, buffer
);
3407 _cupsLangPrintf(stderr
, "ipptool: %s\n", buffer
);
3412 * 'print_line()' - Print a line of formatted or CSV text.
3417 ipp_attribute_t
*attr
, /* I - First attribute for line */
3418 int num_displayed
, /* I - Number of attributes to display */
3419 char **displayed
, /* I - Attributes to display */
3420 size_t *widths
) /* I - Column widths */
3422 int i
; /* Looping var */
3423 size_t maxlength
; /* Max length of all columns */
3424 char *buffer
; /* String buffer */
3425 ipp_attribute_t
*current
; /* Current attribute */
3429 * Get the maximum string length we have to show and allocate...
3432 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
3433 if (widths
[i
] > maxlength
)
3434 maxlength
= widths
[i
];
3438 if ((buffer
= malloc(maxlength
)) == NULL
)
3442 * Loop through the attributes to display...
3447 for (i
= 0; i
< num_displayed
; i
++)
3454 for (current
= attr
; current
; current
= current
->next
)
3458 else if (!strcmp(current
->name
, displayed
[i
]))
3460 _ippAttrString(current
, buffer
, maxlength
);
3465 printf("%*s", (int)-widths
[i
], buffer
);
3471 for (i
= 0; i
< num_displayed
; i
++)
3476 printf("%*s", (int)-widths
[i
], displayed
[i
]);
3480 for (i
= 0; i
< num_displayed
; i
++)
3485 memset(buffer
, '-', widths
[i
]);
3486 buffer
[widths
[i
]] = '\0';
3487 fputs(buffer
, stdout
);
3497 * 'print_test_error()' - Print a test error message.
3501 print_test_error(const char *s
, /* I - Printf-style format string */
3502 ...) /* I - Additional arguments as needed */
3504 char buffer
[10240]; /* Format buffer */
3505 va_list ap
; /* Pointer to arguments */
3509 * Format the error message...
3513 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
3520 if (Output
== _CUPS_OUTPUT_PLIST
)
3521 print_xml_string("string", buffer
);
3523 printf(" %s\n", buffer
);
3528 * 'print_xml_header()' - Print a standard XML plist header.
3532 print_xml_header(void)
3536 puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
3537 puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
3538 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
3539 puts("<plist version=\"1.0\">");
3541 puts("<key>Transfer</key>");
3542 printf("<string>%s</string>\n",
3543 Transfer
== _CUPS_TRANSFER_AUTO
? "auto" :
3544 Transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
3545 puts("<key>Tests</key>");
3554 * 'print_xml_string()' - Print an XML string with escaping.
3558 print_xml_string(const char *element
, /* I - Element name or NULL */
3559 const char *s
) /* I - String to print */
3562 printf("<%s>", element
);
3567 fputs("&", stdout
);
3569 fputs("<", stdout
);
3571 fputs(">", stdout
);
3579 printf("</%s>\n", element
);
3584 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
3588 print_xml_trailer(int success
, /* I - 1 on success, 0 on failure */
3589 const char *message
) /* I - Error message or NULL */
3594 puts("<key>Successful</key>");
3595 puts(success
? "<true />" : "<false />");
3598 puts("<key>ErrorMessage</key>");
3599 print_xml_string("string", message
);
3610 * 'set_variable()' - Set a variable value.
3614 set_variable(_cups_vars_t
*vars
, /* I - Variables */
3615 const char *name
, /* I - Variable name */
3616 const char *value
) /* I - Value string */
3618 _cups_var_t key
, /* Search key */
3619 *var
; /* New variable */
3622 key
.name
= (char *)name
;
3623 if ((var
= cupsArrayFind(vars
->vars
, &key
)) != NULL
)
3626 var
->value
= strdup(value
);
3628 else if ((var
= malloc(sizeof(_cups_var_t
))) == NULL
)
3630 print_fatal_error("Unable to allocate memory for variable \"%s\".", name
);
3635 var
->name
= strdup(name
);
3636 var
->value
= strdup(value
);
3638 cupsArrayAdd(vars
->vars
, var
);
3644 * 'usage()' - Show program usage.
3650 _cupsLangPuts(stderr
,
3651 _("Usage: ipptool [options] URI filename [ ... "
3656 "-C Send requests using chunking (default)\n"
3657 "-E Test with TLS encryption.\n"
3658 "-I Ignore errors\n"
3659 "-L Send requests using content-length\n"
3660 "-S Test with SSL encryption.\n"
3661 "-V version Set default IPP version.\n"
3662 "-X Produce XML plist instead of plain text.\n"
3663 "-d name=value Define variable.\n"
3664 "-f filename Set default request filename.\n"
3665 "-i seconds Repeat the last file with the given time "
3667 "-n count Repeat the last file the given number of "
3669 "-q Be quiet - no output except errors.\n"
3670 "-t Produce a test report.\n"
3671 "-v Show all attributes sent and received.\n"));
3678 * 'validate_attr()' - Determine whether an attribute is valid.
3681 static int /* O - 1 if valid, 0 otherwise */
3682 validate_attr(ipp_attribute_t
*attr
, /* I - Attribute to validate */
3683 int print
) /* I - 1 = report issues to stdout */
3685 int i
; /* Looping var */
3686 char scheme
[64], /* Scheme from URI */
3687 userpass
[256], /* Username/password from URI */
3688 hostname
[256], /* Hostname from URI */
3689 resource
[1024]; /* Resource from URI */
3690 int port
, /* Port number from URI */
3691 uri_status
, /* URI separation status */
3692 valid
= 1; /* Is the attribute valid? */
3693 const char *ptr
; /* Pointer into string */
3694 ipp_attribute_t
*colattr
; /* Collection attribute */
3695 regex_t re
; /* Regular expression */
3696 ipp_uchar_t
*date
; /* Current date value */
3707 * Validate the attribute name.
3710 for (ptr
= attr
->name
; *ptr
; ptr
++)
3711 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
3714 if (*ptr
|| ptr
== attr
->name
)
3719 print_test_error("\"%s\": Bad attribute name - invalid character (RFC "
3720 "2911 section 4.1.3).", attr
->name
);
3723 if ((ptr
- attr
->name
) > 255)
3728 print_test_error("\"%s\": Bad attribute name - bad length (RFC 2911 "
3729 "section 4.1.3).", attr
->name
);
3732 switch (attr
->value_tag
)
3734 case IPP_TAG_INTEGER
:
3737 case IPP_TAG_BOOLEAN
:
3738 for (i
= 0; i
< attr
->num_values
; i
++)
3740 if (attr
->values
[i
].boolean
!= 0 &&
3741 attr
->values
[i
].boolean
!= 1)
3746 print_test_error("\"%s\": Bad boolen value %d (RFC 2911 section "
3747 "4.1.10).", attr
->name
, attr
->values
[i
].boolean
);
3755 for (i
= 0; i
< attr
->num_values
; i
++)
3757 if (attr
->values
[i
].integer
< 1)
3762 print_test_error("\"%s\": Bad enum value %d - out of range "
3763 "(RFC 2911 section 4.1.4).", attr
->name
,
3764 attr
->values
[i
].integer
);
3771 case IPP_TAG_STRING
:
3772 for (i
= 0; i
< attr
->num_values
; i
++)
3774 if (attr
->values
[i
].unknown
.length
> 1023)
3779 print_test_error("\"%s\": Bad octetString value - bad length %d "
3780 "(RFC 2911 section 4.1.10).", attr
->name
,
3781 attr
->values
[i
].unknown
.length
);
3789 for (i
= 0; i
< attr
->num_values
; i
++)
3791 date
= attr
->values
[i
].date
;
3793 if (date
[2] < 1 || date
[2] > 12)
3798 print_test_error("\"%s\": Bad dateTime month %u (RFC 2911 "
3799 "section 4.1.13).", attr
->name
, date
[2]);
3804 if (date
[3] < 1 || date
[3] > 31)
3809 print_test_error("\"%s\": Bad dateTime day %u (RFC 2911 "
3810 "section 4.1.13).", attr
->name
, date
[3]);
3820 print_test_error("\"%s\": Bad dateTime hours %u (RFC 2911 "
3821 "section 4.1.13).", attr
->name
, date
[4]);
3831 print_test_error("\"%s\": Bad dateTime minutes %u (RFC 2911 "
3832 "section 4.1.13).", attr
->name
, date
[5]);
3842 print_test_error("\"%s\": Bad dateTime seconds %u (RFC 2911 "
3843 "section 4.1.13).", attr
->name
, date
[6]);
3853 print_test_error("\"%s\": Bad dateTime deciseconds %u (RFC 2911 "
3854 "section 4.1.13).", attr
->name
, date
[7]);
3859 if (date
[8] != '-' && date
[8] != '+')
3864 print_test_error("\"%s\": Bad dateTime UTC sign '%c' (RFC 2911 "
3865 "section 4.1.13).", attr
->name
, date
[8]);
3875 print_test_error("\"%s\": Bad dateTime UTC hours %u (RFC 2911 "
3876 "section 4.1.13).", attr
->name
, date
[9]);
3886 print_test_error("\"%s\": Bad dateTime UTC minutes %u (RFC 2911 "
3887 "section 4.1.13).", attr
->name
, date
[10]);
3894 case IPP_TAG_RESOLUTION
:
3895 for (i
= 0; i
< attr
->num_values
; i
++)
3897 if (attr
->values
[i
].resolution
.xres
<= 0)
3902 print_test_error("\"%s\": Bad resolution value %dx%d%s - cross "
3903 "feed resolution must be positive (RFC 2911 "
3904 "section 4.1.13).", attr
->name
,
3905 attr
->values
[i
].resolution
.xres
,
3906 attr
->values
[i
].resolution
.yres
,
3907 attr
->values
[i
].resolution
.units
==
3908 IPP_RES_PER_INCH
? "dpi" :
3909 attr
->values
[i
].resolution
.units
==
3910 IPP_RES_PER_CM
? "dpc" : "unknown");
3915 if (attr
->values
[i
].resolution
.yres
<= 0)
3920 print_test_error("\"%s\": Bad resolution value %dx%d%s - feed "
3921 "resolution must be positive (RFC 2911 section "
3922 "4.1.13).", attr
->name
,
3923 attr
->values
[i
].resolution
.xres
,
3924 attr
->values
[i
].resolution
.yres
,
3925 attr
->values
[i
].resolution
.units
==
3926 IPP_RES_PER_INCH
? "dpi" :
3927 attr
->values
[i
].resolution
.units
==
3928 IPP_RES_PER_CM
? "dpc" : "unknown");
3933 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
3934 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
3939 print_test_error("\"%s\": Bad resolution value %dx%d%s - bad "
3940 "units value (RFC 2911 section 4.1.13).",
3941 attr
->name
, attr
->values
[i
].resolution
.xres
,
3942 attr
->values
[i
].resolution
.yres
,
3943 attr
->values
[i
].resolution
.units
==
3944 IPP_RES_PER_INCH
? "dpi" :
3945 attr
->values
[i
].resolution
.units
==
3946 IPP_RES_PER_CM
? "dpc" : "unknown");
3953 case IPP_TAG_RANGE
:
3954 for (i
= 0; i
< attr
->num_values
; i
++)
3956 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3961 print_test_error("\"%s\": Bad rangeOfInteger value %d-%d - lower "
3962 "greater than upper (RFC 2911 section 4.1.13).",
3963 attr
->name
, attr
->values
[i
].range
.lower
,
3964 attr
->values
[i
].range
.upper
);
3971 case IPP_TAG_BEGIN_COLLECTION
:
3972 for (i
= 0; i
< attr
->num_values
; i
++)
3974 for (colattr
= attr
->values
[i
].collection
->attrs
;
3976 colattr
= colattr
->next
)
3978 if (!validate_attr(colattr
, 0))
3985 if (colattr
&& print
)
3987 print_test_error("\"%s\": Bad collection value.", attr
->name
);
3991 validate_attr(colattr
, print
);
3992 colattr
= colattr
->next
;
3999 case IPP_TAG_TEXTLANG
:
4000 for (i
= 0; i
< attr
->num_values
; i
++)
4002 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4004 if ((*ptr
& 0xe0) == 0xc0)
4007 if ((*ptr
& 0xc0) != 0x80)
4010 else if ((*ptr
& 0xf0) == 0xe0)
4013 if ((*ptr
& 0xc0) != 0x80)
4016 if ((*ptr
& 0xc0) != 0x80)
4019 else if ((*ptr
& 0xf8) == 0xf0)
4022 if ((*ptr
& 0xc0) != 0x80)
4025 if ((*ptr
& 0xc0) != 0x80)
4028 if ((*ptr
& 0xc0) != 0x80)
4031 else if (*ptr
& 0x80)
4040 print_test_error("\"%s\": Bad text value \"%s\" - bad UTF-8 "
4041 "sequence (RFC 2911 section 4.1.1).", attr
->name
,
4042 attr
->values
[i
].string
.text
);
4047 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4052 print_test_error("\"%s\": Bad text value \"%s\" - bad length %d "
4053 "(RFC 2911 section 4.1.1).", attr
->name
,
4054 attr
->values
[i
].string
.text
,
4055 (int)strlen(attr
->values
[i
].string
.text
));
4063 case IPP_TAG_NAMELANG
:
4064 for (i
= 0; i
< attr
->num_values
; i
++)
4066 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4068 if ((*ptr
& 0xe0) == 0xc0)
4071 if ((*ptr
& 0xc0) != 0x80)
4074 else if ((*ptr
& 0xf0) == 0xe0)
4077 if ((*ptr
& 0xc0) != 0x80)
4080 if ((*ptr
& 0xc0) != 0x80)
4083 else if ((*ptr
& 0xf8) == 0xf0)
4086 if ((*ptr
& 0xc0) != 0x80)
4089 if ((*ptr
& 0xc0) != 0x80)
4092 if ((*ptr
& 0xc0) != 0x80)
4095 else if (*ptr
& 0x80)
4104 print_test_error("\"%s\": Bad name value \"%s\" - bad UTF-8 "
4105 "sequence (RFC 2911 section 4.1.2).", attr
->name
,
4106 attr
->values
[i
].string
.text
);
4111 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
4116 print_test_error("\"%s\": Bad name value \"%s\" - bad length %d "
4117 "(RFC 2911 section 4.1.2).", attr
->name
,
4118 attr
->values
[i
].string
.text
,
4119 (int)strlen(attr
->values
[i
].string
.text
));
4126 case IPP_TAG_KEYWORD
:
4127 for (i
= 0; i
< attr
->num_values
; i
++)
4129 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4130 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
4134 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4139 print_test_error("\"%s\": Bad keyword value \"%s\" - invalid "
4140 "character (RFC 2911 section 4.1.3).",
4141 attr
->name
, attr
->values
[i
].string
.text
);
4146 if ((ptr
- attr
->values
[i
].string
.text
) > 255)
4151 print_test_error("\"%s\": Bad keyword value \"%s\" - bad "
4152 "length %d (RFC 2911 section 4.1.3).",
4153 attr
->name
, attr
->values
[i
].string
.text
,
4154 (int)strlen(attr
->values
[i
].string
.text
));
4162 for (i
= 0; i
< attr
->num_values
; i
++)
4164 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
4165 attr
->values
[i
].string
.text
,
4166 scheme
, sizeof(scheme
),
4167 userpass
, sizeof(userpass
),
4168 hostname
, sizeof(hostname
),
4169 &port
, resource
, sizeof(resource
));
4171 if (uri_status
< HTTP_URI_OK
)
4176 print_test_error("\"%s\": Bad URI value \"%s\" - %s "
4177 "(RFC 2911 section 4.1.5).", attr
->name
,
4178 attr
->values
[i
].string
.text
,
4179 URIStatusStrings
[uri_status
-
4180 HTTP_URI_OVERFLOW
]);
4185 if (strlen(attr
->values
[i
].string
.text
) > 1023)
4190 print_test_error("\"%s\": Bad URI value \"%s\" - bad length %d "
4191 "(RFC 2911 section 4.1.5).", attr
->name
,
4192 attr
->values
[i
].string
.text
,
4193 (int)strlen(attr
->values
[i
].string
.text
));
4200 case IPP_TAG_URISCHEME
:
4201 for (i
= 0; i
< attr
->num_values
; i
++)
4203 ptr
= attr
->values
[i
].string
.text
;
4204 if (islower(*ptr
& 255))
4206 for (ptr
++; *ptr
; ptr
++)
4207 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
4208 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
4212 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4217 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
4218 "characters (RFC 2911 section 4.1.6).",
4219 attr
->name
, attr
->values
[i
].string
.text
);
4224 if ((ptr
- attr
->values
[i
].string
.text
) > 63)
4229 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
4230 "length %d (RFC 2911 section 4.1.6).",
4231 attr
->name
, attr
->values
[i
].string
.text
,
4232 (int)strlen(attr
->values
[i
].string
.text
));
4239 case IPP_TAG_CHARSET
:
4240 for (i
= 0; i
< attr
->num_values
; i
++)
4242 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
4243 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
4244 isspace(*ptr
& 255))
4247 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
4252 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
4253 "characters (RFC 2911 section 4.1.7).",
4254 attr
->name
, attr
->values
[i
].string
.text
);
4259 if ((ptr
- attr
->values
[i
].string
.text
) > 40)
4264 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
4265 "length %d (RFC 2911 section 4.1.7).",
4266 attr
->name
, attr
->values
[i
].string
.text
,
4267 (int)strlen(attr
->values
[i
].string
.text
));
4274 case IPP_TAG_LANGUAGE
:
4276 * The following regular expression is derived from the ABNF for
4277 * language tags in RFC 4646. All I can say is that this is the
4278 * easiest way to check the values...
4281 if ((i
= regcomp(&re
,
4283 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
4285 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
4286 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
4287 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
4288 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
4289 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
4291 "x(-[a-z0-9]{1,8})+" /* privateuse */
4293 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
4295 REG_NOSUB
| REG_EXTENDED
)) != 0)
4297 char temp
[256]; /* Temporary error string */
4299 regerror(i
, &re
, temp
, sizeof(temp
));
4300 print_fatal_error("Unable to compile naturalLanguage regular "
4301 "expression: %s.", temp
);
4304 for (i
= 0; i
< attr
->num_values
; i
++)
4306 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4311 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
4312 "characters (RFC 2911 section 4.1.8).",
4313 attr
->name
, attr
->values
[i
].string
.text
);
4318 if (strlen(attr
->values
[i
].string
.text
) > 63)
4323 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
4324 "length %d (RFC 2911 section 4.1.8).",
4325 attr
->name
, attr
->values
[i
].string
.text
,
4326 (int)strlen(attr
->values
[i
].string
.text
));
4335 case IPP_TAG_MIMETYPE
:
4337 * The following regular expression is derived from the ABNF for
4338 * language tags in RFC 2045 and 4288. All I can say is that this is
4339 * the easiest way to check the values...
4342 if ((i
= regcomp(&re
,
4344 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
4346 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
4347 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
4348 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
4351 REG_NOSUB
| REG_EXTENDED
)) != 0)
4353 char temp
[256]; /* Temporary error string */
4355 regerror(i
, &re
, temp
, sizeof(temp
));
4356 print_fatal_error("Unable to compile mimeMediaType regular "
4357 "expression: %s.", temp
);
4360 for (i
= 0; i
< attr
->num_values
; i
++)
4362 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4367 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
4368 "characters (RFC 2911 section 4.1.9).",
4369 attr
->name
, attr
->values
[i
].string
.text
);
4374 if (strlen(attr
->values
[i
].string
.text
) > 255)
4379 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
4380 "length %d (RFC 2911 section 4.1.9).",
4381 attr
->name
, attr
->values
[i
].string
.text
,
4382 (int)strlen(attr
->values
[i
].string
.text
));
4398 * 'with_value()' - Test a WITH-VALUE predicate.
4401 static int /* O - 1 on match, 0 on non-match */
4402 with_value(char *value
, /* I - Value string */
4403 int regex
, /* I - Value is a regular expression */
4404 ipp_attribute_t
*attr
) /* I - Attribute to compare */
4406 int i
; /* Looping var */
4407 char *valptr
; /* Pointer into value */
4411 * NULL matches everything.
4414 if (!value
|| !*value
)
4418 * Compare the value string to the attribute value.
4421 switch (attr
->value_tag
)
4423 case IPP_TAG_INTEGER
:
4425 for (i
= 0; i
< attr
->num_values
; i
++)
4427 char op
, /* Comparison operator */
4428 *nextptr
; /* Next pointer */
4429 int intvalue
; /* Integer value */
4433 if (!strncmp(valptr
, "no-value,", 9))
4436 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4437 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4438 *valptr
== '=' || *valptr
== '>')
4441 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4443 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4451 intvalue
= strtol(valptr
, &nextptr
, 0);
4452 if (nextptr
== valptr
)
4459 if (attr
->values
[i
].integer
== intvalue
)
4463 if (attr
->values
[i
].integer
< intvalue
)
4467 if (attr
->values
[i
].integer
> intvalue
)
4475 case IPP_TAG_BOOLEAN
:
4476 for (i
= 0; i
< attr
->num_values
; i
++)
4478 if (!strcmp(value
, "true") == attr
->values
[i
].boolean
)
4483 case IPP_TAG_NOVALUE
:
4484 return (!strcmp(value
, "no-value") || !strncmp(value
, "no-value,", 9));
4486 case IPP_TAG_CHARSET
:
4487 case IPP_TAG_KEYWORD
:
4488 case IPP_TAG_LANGUAGE
:
4489 case IPP_TAG_MIMETYPE
:
4491 case IPP_TAG_NAMELANG
:
4493 case IPP_TAG_TEXTLANG
:
4495 case IPP_TAG_URISCHEME
:
4499 * Value is an extended, case-sensitive POSIX regular expression...
4502 regex_t re
; /* Regular expression */
4504 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
4506 char temp
[256]; /* Temporary string */
4508 regerror(i
, &re
, temp
, sizeof(temp
));
4510 print_fatal_error("Unable to compile WITH-VALUE regular expression "
4511 "\"%s\" - %s", value
, temp
);
4516 * See if ALL of the values match the given regular expression.
4519 for (i
= 0; i
< attr
->num_values
; i
++)
4521 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4527 return (i
== attr
->num_values
);
4532 * Value is a literal string, see if at least one value matches the
4536 for (i
= 0; i
< attr
->num_values
; i
++)
4538 if (!strcmp(value
, attr
->values
[i
].string
.text
))