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 int with_regex
, /* WITH-VALUE is a regular expression */
87 count
; /* Expected count if > 0 */
88 ipp_tag_t in_group
; /* IN-GROUP value */
91 typedef struct _cups_status_s
/**** Status info ****/
93 ipp_status_t status
; /* Expected status code */
94 char *if_defined
, /* Only if variable is defined */
95 *if_undefined
; /* Only if variable is not defined */
98 typedef struct _cups_var_s
/**** Variable ****/
100 char *name
, /* Name of variable */
101 *value
; /* Value of variable */
104 typedef struct _cups_vars_s
/**** Set of variables ****/
106 const char *uri
, /* URI for printer */
107 *filename
; /* Filename */
108 char scheme
[64], /* Scheme from URI */
109 userpass
[256], /* Username/password from URI */
110 hostname
[256], /* Hostname from URI */
111 resource
[1024]; /* Resource path from URI */
112 int port
; /* Port number from URI */
113 http_encryption_t encryption
; /* Encryption for connection? */
114 cups_array_t
*vars
; /* Array of variables */
122 _cups_transfer_t Transfer
= _CUPS_TRANSFER_AUTO
;
123 /* How to transfer requests */
124 _cups_output_t Output
= _CUPS_OUTPUT_LIST
;
126 int Verbosity
= 0, /* Show all attributes? */
127 Version
= 11, /* Default IPP version */
128 XMLHeader
= 0; /* 1 if header is written */
129 const char * const URIStatusStrings
[] = /* URI status strings */
132 "Bad arguments to function",
133 "Bad resource in URI",
134 "Bad port number in URI",
135 "Bad hostname/address in URI",
136 "Bad username in URI",
140 "Missing scheme in URI",
141 "Unknown scheme in URI",
142 "Missing resource in URI"
150 static int compare_vars(_cups_var_t
*a
, _cups_var_t
*b
);
151 static int do_tests(_cups_vars_t
*vars
, const char *testfile
);
152 static void expand_variables(_cups_vars_t
*vars
, char *dst
, const char *src
,
155 __attribute((nonnull(1,2,3)))
156 #endif /* __GNUC__ */
158 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
159 static ipp_t
*get_collection(_cups_vars_t
*vars
, FILE *fp
, int *linenum
);
160 static char *get_filename(const char *testfile
, char *dst
, const char *src
,
162 static char *get_token(FILE *fp
, char *buf
, int buflen
,
164 static char *get_variable(_cups_vars_t
*vars
, const char *name
);
165 static char *iso_date(ipp_uchar_t
*date
);
166 static void print_attr(ipp_attribute_t
*attr
);
167 static void print_col(ipp_t
*col
);
168 static void print_csv(ipp_attribute_t
*attr
, int num_displayed
,
169 char **displayed
, size_t *widths
);
170 static void print_fatal_error(const char *s
, ...)
172 __attribute__ ((__format__ (__printf__
, 1, 2)))
173 #endif /* __GNUC__ */
175 static void print_line(ipp_attribute_t
*attr
, int num_displayed
,
176 char **displayed
, size_t *widths
);
177 static void print_test_error(const char *s
, ...)
179 __attribute__ ((__format__ (__printf__
, 1, 2)))
180 #endif /* __GNUC__ */
182 static void print_xml_header(void);
183 static void print_xml_string(const char *element
, const char *s
);
184 static void print_xml_trailer(int success
, const char *message
);
185 static void set_variable(_cups_vars_t
*vars
, const char *name
,
187 static void usage(void);
188 static int validate_attr(ipp_attribute_t
*attr
, int print
);
189 static int with_value(char *value
, int regex
, ipp_attribute_t
*attr
);
193 * 'main()' - Parse options and do tests.
196 int /* O - Exit status */
197 main(int argc
, /* I - Number of command-line args */
198 char *argv
[]) /* I - Command-line arguments */
200 int i
; /* Looping var */
201 int status
; /* Status of tests... */
202 char *opt
, /* Current option */
203 name
[1024], /* Name/value buffer */
204 *value
, /* Pointer to value */
205 filename
[1024], /* Real filename */
206 testname
[1024]; /* Real test filename */
207 const char *testfile
; /* Test file to use */
208 int interval
, /* Test interval */
209 repeat
; /* Repeat count */
210 _cups_vars_t vars
; /* Variables */
211 http_uri_status_t uri_status
; /* URI separation status */
212 _cups_globals_t
*cg
= _cupsGlobals();
218 * Initialize the locale and variables...
221 _cupsSetLocale(argv
);
223 memset(&vars
, 0, sizeof(vars
));
224 vars
.vars
= cupsArrayNew((cups_array_func_t
)compare_vars
, NULL
);
229 * ipptool URI testfile
237 for (i
= 1; i
< argc
; i
++)
239 if (argv
[i
][0] == '-')
241 for (opt
= argv
[i
] + 1; *opt
; opt
++)
245 case 'C' : /* Enable HTTP chunking */
246 Transfer
= _CUPS_TRANSFER_CHUNKED
;
249 case 'E' : /* Encrypt with TLS */
251 vars
.encryption
= HTTP_ENCRYPT_REQUIRED
;
253 _cupsLangPrintf(stderr
,
254 _("%s: Sorry, no encryption support compiled in\n"),
256 #endif /* HAVE_SSL */
259 case 'L' : /* Disable HTTP chunking */
260 Transfer
= _CUPS_TRANSFER_LENGTH
;
263 case 'S' : /* Encrypt with SSL */
265 vars
.encryption
= HTTP_ENCRYPT_ALWAYS
;
267 _cupsLangPrintf(stderr
,
268 _("%s: Sorry, no encryption support compiled in\n"),
270 #endif /* HAVE_SSL */
273 case 'V' : /* Set IPP version */
278 _cupsLangPuts(stderr
,
279 _("ipptool: Missing version for \"-V\".\n"));
283 if (!strcmp(argv
[i
], "1.0"))
285 else if (!strcmp(argv
[i
], "1.1"))
287 else if (!strcmp(argv
[i
], "2.0"))
289 else if (!strcmp(argv
[i
], "2.1"))
291 else if (!strcmp(argv
[i
], "2.2"))
295 _cupsLangPrintf(stderr
,
296 _("ipptool: Bad version %s for \"-V\".\n"),
302 case 'X' : /* Produce XML output */
303 Output
= _CUPS_OUTPUT_PLIST
;
305 if (interval
|| repeat
)
307 _cupsLangPuts(stderr
, _("ipptool: \"-i\" and \"-n\" are "
308 "incompatible with -X\".\n"));
313 case 'c' : /* CSV output */
314 Output
= _CUPS_OUTPUT_CSV
;
317 case 'd' : /* Define a variable */
322 _cupsLangPuts(stderr
,
323 _("ipptool: Missing name=value for \"-d\".\n"));
327 strlcpy(name
, argv
[i
], sizeof(name
));
328 if ((value
= strchr(name
, '=')) != NULL
)
331 value
= name
+ strlen(name
);
333 set_variable(&vars
, name
, value
);
336 case 'f' : /* Set the default test filename */
341 _cupsLangPuts(stderr
,
342 _("ipptool: Missing filename for \"-f\".\n"));
346 if (access(argv
[i
], 0) && argv
[i
][0] != '/')
348 snprintf(filename
, sizeof(filename
), "%s/ipptool/%s",
349 cg
->cups_datadir
, argv
[i
]);
350 if (access(argv
[i
], 0))
351 vars
.filename
= argv
[i
];
353 vars
.filename
= filename
;
356 vars
.filename
= argv
[i
];
359 case 'i' : /* Test every N seconds */
364 _cupsLangPuts(stderr
,
365 _("ipptool: Missing seconds for \"-i\".\n"));
369 interval
= atoi(argv
[i
]);
371 if (Output
== _CUPS_OUTPUT_PLIST
&& interval
)
373 _cupsLangPuts(stderr
, _("ipptool: \"-i\" is incompatible with "
379 case 'l' : /* List as a table */
380 Output
= _CUPS_OUTPUT_LIST
;
383 case 'n' : /* Repeat count */
388 _cupsLangPuts(stderr
,
389 _("ipptool: Missing count for \"-n\".\n"));
393 repeat
= atoi(argv
[i
]);
395 if (Output
== _CUPS_OUTPUT_PLIST
&& repeat
)
397 _cupsLangPuts(stderr
, _("ipptool: \"-n\" is incompatible with "
403 case 'q' : /* Be quiet */
404 Output
= _CUPS_OUTPUT_QUIET
;
407 case 't' : /* CUPS test output */
408 Output
= _CUPS_OUTPUT_TEST
;
411 case 'v' : /* Be verbose */
416 _cupsLangPrintf(stderr
, _("ipptool: Unknown option \"-%c\".\n"),
423 else if (!strncmp(argv
[i
], "ipp://", 6) ||
424 !strncmp(argv
[i
], "http://", 7) ||
425 !strncmp(argv
[i
], "https://", 8))
433 _cupsLangPuts(stderr
, _("ipptool: May only specify a single URI.\n"));
438 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
, vars
.uri
,
439 vars
.scheme
, sizeof(vars
.scheme
),
440 vars
.userpass
, sizeof(vars
.userpass
),
441 vars
.hostname
, sizeof(vars
.hostname
),
443 vars
.resource
, sizeof(vars
.resource
));
445 if (uri_status
!= HTTP_URI_OK
)
447 _cupsLangPrintf(stderr
, _("ipptool: Bad URI - %s.\n"),
448 URIStatusStrings
[uri_status
- HTTP_URI_OVERFLOW
]);
452 if (strcmp(vars
.scheme
, "http") && strcmp(vars
.scheme
, "https") &&
453 strcmp(vars
.scheme
, "ipp"))
455 _cupsLangPuts(stderr
, _("ipptool: Only http, https, and ipp URIs are "
468 _cupsLangPuts(stderr
, _("ipptool: URI required before test file."));
472 if (access(argv
[i
], 0) && argv
[i
][0] != '/')
474 snprintf(testname
, sizeof(testname
), "%s/ipptool/%s", cg
->cups_datadir
,
476 if (access(testname
, 0))
484 if (!do_tests(&vars
, testfile
))
489 if (!vars
.uri
|| !testfile
)
493 * Loop if the interval is set...
496 if (Output
== _CUPS_OUTPUT_PLIST
)
497 print_xml_trailer(!status
, NULL
);
498 else if (interval
&& repeat
> 0)
503 do_tests(&vars
, testfile
);
512 do_tests(&vars
, testfile
);
525 * 'compare_vars()' - Compare two variables.
528 static int /* O - Result of comparison */
529 compare_vars(_cups_var_t
*a
, /* I - First variable */
530 _cups_var_t
*b
) /* I - Second variable */
532 return (strcasecmp(a
->name
, b
->name
));
537 * 'do_tests()' - Do tests as specified in the test file.
540 static int /* 1 = success, 0 = failure */
541 do_tests(_cups_vars_t
*vars
, /* I - Variables */
542 const char *testfile
) /* I - Test file to use */
544 int i
, /* Looping var */
545 linenum
, /* Current line number */
546 pass
, /* Did we pass the test? */
547 request_id
; /* Current request ID */
548 http_t
*http
= NULL
; /* HTTP connection to server */
549 FILE *fp
= NULL
; /* Test file */
550 char resource
[512], /* Resource for request */
551 token
[1024], /* Token from file */
552 *tokenptr
, /* Pointer into token */
553 temp
[1024]; /* Temporary string */
554 ipp_t
*request
= NULL
; /* IPP request */
555 ipp_t
*response
= NULL
; /* IPP response */
556 char attr
[128]; /* Attribute name */
557 ipp_op_t op
; /* Operation */
558 ipp_tag_t group
; /* Current group */
559 ipp_tag_t value
; /* Current value type */
560 ipp_attribute_t
*attrptr
, /* Attribute pointer */
561 *found
, /* Found attribute */
562 *lastcol
= NULL
; /* Last collection attribute */
563 char name
[1024]; /* Name of test */
564 char filename
[1024]; /* Filename */
565 _cups_transfer_t transfer
; /* To chunk or not to chunk */
566 int version
; /* IPP version number to use */
567 int num_statuses
= 0; /* Number of valid status codes */
568 _cups_status_t statuses
[100], /* Valid status codes */
569 *last_status
; /* Last STATUS (for predicates) */
570 int num_expects
= 0; /* Number of expected attributes */
571 _cups_expect_t expects
[200], /* Expected attributes */
572 *expect
, /* Current expected attribute */
573 *last_expect
; /* Last EXPECT (for predicates) */
574 int num_displayed
= 0; /* Number of displayed attributes */
575 char *displayed
[200]; /* Displayed attributes */
576 size_t widths
[200]; /* Width of columns */
580 * Open the test file...
583 if ((fp
= fopen(testfile
, "r")) == NULL
)
585 print_fatal_error("Unable to open test file %s - %s", testfile
,
591 * Connect to the server...
594 if ((http
= httpConnectEncrypt(vars
->hostname
, vars
->port
,
595 vars
->encryption
)) == NULL
)
597 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
598 vars
->port
, strerror(errno
));
606 if (Output
== _CUPS_OUTPUT_PLIST
)
608 else if (Output
== _CUPS_OUTPUT_TEST
)
609 printf("\"%s\":\n", testfile
);
611 CUPS_SRAND(time(NULL
));
615 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
617 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
620 * Expect an open brace...
623 if (!strcmp(token
, "DEFINE"))
629 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
630 get_token(fp
, temp
, sizeof(temp
), &linenum
))
632 expand_variables(vars
, token
, temp
, sizeof(token
));
633 set_variable(vars
, attr
, token
);
637 print_fatal_error("Missing DEFINE name and/or value on line %d.",
644 else if (!strcmp(token
, "INCLUDE"))
651 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
654 * Map the filename to and then run the tests...
657 if (!do_tests(vars
, get_filename(testfile
, filename
, temp
,
663 print_fatal_error("Missing INCLUDE filename on line %d.", linenum
);
669 else if (!strcmp(token
, "TRANSFER"))
677 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
679 if (!strcmp(temp
, "auto"))
680 Transfer
= _CUPS_TRANSFER_AUTO
;
681 else if (!strcmp(temp
, "chunked"))
682 Transfer
= _CUPS_TRANSFER_CHUNKED
;
683 else if (!strcmp(temp
, "length"))
684 Transfer
= _CUPS_TRANSFER_LENGTH
;
687 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
694 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
700 else if (!strcmp(token
, "VERSION"))
702 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
704 if (!strcmp(temp
, "1.0"))
706 else if (!strcmp(temp
, "1.1"))
708 else if (!strcmp(temp
, "2.0"))
710 else if (!strcmp(temp
, "2.1"))
712 else if (!strcmp(temp
, "2.2"))
716 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
722 print_fatal_error("Missing VERSION number on line %d.", linenum
);
728 else if (strcmp(token
, "{"))
730 print_fatal_error("Unexpected token %s seen on line %d.", token
, linenum
);
735 * Initialize things...
738 strlcpy(resource
, vars
->resource
, sizeof(resource
));
743 group
= IPP_TAG_ZERO
;
750 strlcpy(name
, testfile
, sizeof(name
));
751 if (strrchr(name
, '.') != NULL
)
752 *strrchr(name
, '.') = '\0';
755 * Parse until we see a close brace...
758 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
760 if (strcasecmp(token
, "COUNT") &&
761 strcasecmp(token
, "IF-DEFINED") &&
762 strcasecmp(token
, "IF-UNDEFINED") &&
763 strcasecmp(token
, "IN-GROUP") &&
764 strcasecmp(token
, "OF-TYPE") &&
765 strcasecmp(token
, "SAME-COUNT-AS") &&
766 strcasecmp(token
, "WITH-VALUE"))
769 if (strcasecmp(token
, "IF-DEFINED") &&
770 strcasecmp(token
, "IF-UNDEFINED"))
773 if (!strcmp(token
, "}"))
775 else if (!strcmp(token
, "{") && lastcol
)
778 * Another collection value
781 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
782 /* Collection value */
786 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
790 * Reallocate memory...
793 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
794 (lastcol
->num_values
+ 1) *
795 sizeof(ipp_value_t
))) == NULL
)
797 print_fatal_error("Unable to allocate memory on line %d.", linenum
);
801 if (tempcol
!= lastcol
)
804 * Reset pointers in the list...
808 request
->prev
->next
= tempcol
;
810 request
->attrs
= tempcol
;
812 lastcol
= request
->current
= request
->last
= tempcol
;
815 lastcol
->values
[lastcol
->num_values
].collection
= col
;
816 lastcol
->num_values
++;
821 else if (!strcmp(token
, "DEFINE"))
827 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
828 get_token(fp
, temp
, sizeof(temp
), &linenum
))
830 expand_variables(vars
, token
, temp
, sizeof(token
));
831 set_variable(vars
, attr
, token
);
835 print_fatal_error("Missing DEFINE name and/or value on line %d.",
840 else if (!strcasecmp(token
, "NAME"))
846 get_token(fp
, name
, sizeof(name
), &linenum
);
848 else if (!strcmp(token
, "REQUEST-ID"))
855 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
857 if (isdigit(temp
[0] & 255))
858 request_id
= atoi(temp
);
859 else if (!strcasecmp(temp
, "random"))
860 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
863 print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp
,
870 print_fatal_error("Missing REQUEST-ID value on line %d.", linenum
);
874 else if (!strcmp(token
, "TRANSFER"))
882 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
884 if (!strcmp(temp
, "auto"))
885 transfer
= _CUPS_TRANSFER_AUTO
;
886 else if (!strcmp(temp
, "chunked"))
887 transfer
= _CUPS_TRANSFER_CHUNKED
;
888 else if (!strcmp(temp
, "length"))
889 transfer
= _CUPS_TRANSFER_LENGTH
;
892 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
899 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
903 else if (!strcasecmp(token
, "VERSION"))
905 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
907 if (!strcmp(temp
, "0.0"))
909 else if (!strcmp(temp
, "1.0"))
911 else if (!strcmp(temp
, "1.1"))
913 else if (!strcmp(temp
, "2.0"))
915 else if (!strcmp(temp
, "2.1"))
917 else if (!strcmp(temp
, "2.2"))
921 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
927 print_fatal_error("Missing VERSION number on line %d.", linenum
);
931 else if (!strcasecmp(token
, "RESOURCE"))
937 if (!get_token(fp
, resource
, sizeof(resource
), &linenum
))
939 print_fatal_error("Missing RESOURCE path on line %d.", linenum
);
943 else if (!strcasecmp(token
, "OPERATION"))
949 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
951 print_fatal_error("Missing OPERATION code on line %d.", linenum
);
955 if ((op
= ippOpValue(token
)) < 0 && (op
= strtol(token
, NULL
, 0)) == 0)
957 print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token
,
962 else if (!strcasecmp(token
, "GROUP"))
968 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
970 print_fatal_error("Missing GROUP tag on line %d.", linenum
);
974 if ((value
= ippTagValue(token
)) < 0)
976 print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token
, linenum
);
981 ippAddSeparator(request
);
985 else if (!strcasecmp(token
, "DELAY"))
988 * Delay before operation...
993 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
995 print_fatal_error("Missing DELAY value on line %d.", linenum
);
999 if ((delay
= atoi(token
)) <= 0)
1001 print_fatal_error("Bad DELAY value \"%s\" on line %d.", token
,
1008 else if (!strcasecmp(token
, "ATTR"))
1014 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1016 print_fatal_error("Missing ATTR value tag on line %d.", linenum
);
1020 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
1022 print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token
,
1027 if (!get_token(fp
, attr
, sizeof(attr
), &linenum
))
1029 print_fatal_error("Missing ATTR name on line %d.", linenum
);
1033 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1035 print_fatal_error("Missing ATTR value on line %d.", linenum
);
1039 expand_variables(vars
, token
, temp
, sizeof(token
));
1043 case IPP_TAG_BOOLEAN
:
1044 if (!strcasecmp(token
, "true"))
1045 ippAddBoolean(request
, group
, attr
, 1);
1047 ippAddBoolean(request
, group
, attr
, atoi(token
));
1050 case IPP_TAG_INTEGER
:
1052 ippAddInteger(request
, group
, value
, attr
, atoi(token
));
1055 case IPP_TAG_RESOLUTION
:
1057 int xres
, /* X resolution */
1058 yres
; /* Y resolution */
1059 char units
[6]; /* Units */
1061 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
1062 (strcasecmp(units
, "dpi") && strcasecmp(units
, "dpc") &&
1063 strcasecmp(units
, "other")))
1065 print_fatal_error("Bad resolution value \"%s\" on line %d.",
1070 if (!strcasecmp(units
, "dpi"))
1071 ippAddResolution(request
, group
, attr
, xres
, yres
,
1073 else if (!strcasecmp(units
, "dpc"))
1074 ippAddResolution(request
, group
, attr
, xres
, yres
,
1077 ippAddResolution(request
, group
, attr
, xres
, yres
,
1082 case IPP_TAG_RANGE
:
1084 int lowers
[4], /* Lower value */
1085 uppers
[4], /* Upper values */
1086 num_vals
; /* Number of values */
1089 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
1090 lowers
+ 0, uppers
+ 0,
1091 lowers
+ 1, uppers
+ 1,
1092 lowers
+ 2, uppers
+ 2,
1093 lowers
+ 3, uppers
+ 3);
1095 if ((num_vals
& 1) || num_vals
== 0)
1097 print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
1098 "%d.", token
, linenum
);
1102 ippAddRanges(request
, group
, attr
, num_vals
/ 2, lowers
,
1107 case IPP_TAG_BEGIN_COLLECTION
:
1108 if (!strcmp(token
, "{"))
1110 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1111 /* Collection value */
1115 lastcol
= ippAddCollection(request
, group
, attr
, col
);
1123 print_fatal_error("Bad ATTR collection value on line %d.",
1130 print_fatal_error("Unsupported ATTR value tag %s on line %d.",
1131 ippTagString(value
), linenum
);
1134 case IPP_TAG_TEXTLANG
:
1135 case IPP_TAG_NAMELANG
:
1138 case IPP_TAG_KEYWORD
:
1140 case IPP_TAG_URISCHEME
:
1141 case IPP_TAG_CHARSET
:
1142 case IPP_TAG_LANGUAGE
:
1143 case IPP_TAG_MIMETYPE
:
1144 if (!strchr(token
, ','))
1145 ippAddString(request
, group
, value
, attr
, NULL
, token
);
1149 * Multiple string values...
1152 int num_values
; /* Number of values */
1153 char *values
[100], /* Values */
1154 *ptr
; /* Pointer to next value */
1160 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
1163 values
[num_values
] = ptr
;
1167 ippAddStrings(request
, group
, value
, attr
, num_values
,
1168 NULL
, (const char **)values
);
1173 else if (!strcasecmp(token
, "FILE"))
1179 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1181 print_fatal_error("Missing FILE filename on line %d.", linenum
);
1185 expand_variables(vars
, token
, temp
, sizeof(token
));
1186 get_filename(testfile
, filename
, token
, sizeof(filename
));
1188 else if (!strcasecmp(token
, "STATUS"))
1194 if (num_statuses
>= (int)(sizeof(statuses
) / sizeof(statuses
[0])))
1196 print_fatal_error("Too many STATUS's on line %d.", linenum
);
1200 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1202 print_fatal_error("Missing STATUS code on line %d.", linenum
);
1206 if ((statuses
[num_statuses
].status
= ippErrorValue(token
)) < 0)
1208 print_fatal_error("Bad STATUS code \"%s\" on line %d.", token
,
1213 last_status
= statuses
+ num_statuses
;
1216 last_status
->if_defined
= NULL
;
1217 last_status
->if_undefined
= NULL
;
1219 else if (!strcasecmp(token
, "EXPECT"))
1222 * Expected attributes...
1225 if (num_expects
>= (int)(sizeof(expects
) / sizeof(expects
[0])))
1227 print_fatal_error("Too many EXPECT's on line %d.", linenum
);
1231 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1233 print_fatal_error("Missing EXPECT name on line %d.", linenum
);
1237 last_expect
= expects
+ num_expects
;
1240 memset(last_expect
, 0, sizeof(_cups_expect_t
));
1242 if (token
[0] == '!')
1244 last_expect
->not_expect
= 1;
1245 last_expect
->name
= strdup(token
+ 1);
1247 else if (token
[0] == '?')
1249 last_expect
->optional
= 1;
1250 last_expect
->name
= strdup(token
+ 1);
1253 last_expect
->name
= strdup(token
);
1255 else if (!strcasecmp(token
, "COUNT"))
1257 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1259 print_fatal_error("Missing COUNT number on line %d.", linenum
);
1263 if ((i
= atoi(token
)) <= 0)
1265 print_fatal_error("Bad COUNT \"%s\" on line %d.", token
, linenum
);
1270 last_expect
->count
= i
;
1273 print_fatal_error("COUNT without a preceding EXPECT on line %d.",
1278 else if (!strcasecmp(token
, "OF-TYPE"))
1280 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1282 print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
1288 last_expect
->of_type
= strdup(token
);
1291 print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
1296 else if (!strcasecmp(token
, "IN-GROUP"))
1298 ipp_tag_t in_group
; /* IN-GROUP value */
1301 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1303 print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum
);
1307 if ((in_group
= ippTagValue(token
)) == (ipp_tag_t
)-1)
1310 else if (last_expect
)
1311 last_expect
->in_group
= in_group
;
1314 print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
1319 else if (!strcasecmp(token
, "SAME-COUNT-AS"))
1321 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1323 print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum
);
1328 last_expect
->same_count_as
= strdup(token
);
1331 print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
1336 else if (!strcasecmp(token
, "IF-DEFINED"))
1338 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1340 print_fatal_error("Missing IF-DEFINED name on line %d.", linenum
);
1345 last_expect
->if_defined
= strdup(token
);
1346 else if (last_status
)
1347 last_status
->if_defined
= strdup(token
);
1350 print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
1351 "on line %d.", linenum
);
1355 else if (!strcasecmp(token
, "IF-UNDEFINED"))
1357 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1359 print_fatal_error("Missing IF-UNDEFINED name on line %d.", linenum
);
1364 last_expect
->if_undefined
= strdup(token
);
1365 else if (last_status
)
1366 last_status
->if_undefined
= strdup(token
);
1369 print_fatal_error("IF-UNDEFINED without a preceding EXPECT or STATUS "
1370 "on line %d.", linenum
);
1374 else if (!strcasecmp(token
, "WITH-VALUE"))
1376 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1378 print_fatal_error("Missing WITH-VALUE value on line %d.", linenum
);
1384 tokenptr
= token
+ strlen(token
) - 1;
1385 if (token
[0] == '/' && tokenptr
> token
&& *tokenptr
== '/')
1388 * WITH-VALUE is a POSIX extended regular expression.
1391 last_expect
->with_value
= calloc(1, tokenptr
- token
);
1392 last_expect
->with_regex
= 1;
1394 if (last_expect
->with_value
)
1395 memcpy(last_expect
->with_value
, token
+ 1, tokenptr
- token
- 1);
1400 * WITH-VALUE is a literal value...
1403 last_expect
->with_value
= strdup(token
);
1408 print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
1413 else if (!strcasecmp(token
, "DISPLAY"))
1416 * Display attributes...
1419 if (num_displayed
>= (int)(sizeof(displayed
) / sizeof(displayed
[0])))
1421 print_fatal_error("Too many DISPLAY's on line %d", linenum
);
1425 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1427 print_fatal_error("Missing DISPLAY name on line %d.", linenum
);
1431 displayed
[num_displayed
] = strdup(token
);
1436 print_fatal_error("Unexpected token %s seen on line %d.", token
,
1443 * Submit the IPP request...
1446 request
->request
.op
.version
[0] = version
/ 10;
1447 request
->request
.op
.version
[1] = version
% 10;
1448 request
->request
.op
.operation_id
= op
;
1449 request
->request
.op
.request_id
= request_id
;
1451 if (Output
== _CUPS_OUTPUT_PLIST
)
1454 puts("<key>Name</key>");
1455 print_xml_string("string", name
);
1456 puts("<key>Operation</key>");
1457 print_xml_string("string", ippOpString(op
));
1458 puts("<key>RequestAttributes</key>");
1460 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
1461 print_attr(attrptr
);
1464 else if (Output
== _CUPS_OUTPUT_TEST
)
1468 printf(" %s:\n", ippOpString(op
));
1470 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
1471 print_attr(attrptr
);
1474 printf(" %-69.69s [", name
);
1478 if (transfer
== _CUPS_TRANSFER_CHUNKED
||
1479 (transfer
== _CUPS_TRANSFER_AUTO
&& filename
[0]))
1482 * Send request using chunking...
1485 http_status_t status
= cupsSendRequest(http
, request
, resource
, 0);
1487 if (status
== HTTP_CONTINUE
&& filename
[0])
1489 int fd
; /* File to send */
1490 char buffer
[8192]; /* Copy buffer */
1491 ssize_t bytes
; /* Bytes read/written */
1493 if ((fd
= open(filename
, O_RDONLY
| O_BINARY
)) >= 0)
1495 while ((bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
1496 if ((status
= cupsWriteRequestData(http
, buffer
,
1497 bytes
)) != HTTP_CONTINUE
)
1502 snprintf(buffer
, sizeof(buffer
), "%s: %s", filename
, strerror(errno
));
1503 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
1505 status
= HTTP_ERROR
;
1511 if (status
== HTTP_CONTINUE
)
1512 response
= cupsGetResponse(http
, resource
);
1516 else if (filename
[0])
1517 response
= cupsDoFileRequest(http
, request
, resource
, filename
);
1519 response
= cupsDoRequest(http
, request
, resource
);
1527 if (http
->version
!= HTTP_1_1
)
1530 if (response
->request
.status
.version
[0] != (version
/ 10) ||
1531 response
->request
.status
.version
[1] != (version
% 10) ||
1532 response
->request
.status
.request_id
!= request_id
)
1535 if ((attrptr
= ippFindAttribute(response
, "job-id",
1536 IPP_TAG_INTEGER
)) != NULL
)
1538 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
1539 set_variable(vars
, "job-id", temp
);
1542 if ((attrptr
= ippFindAttribute(response
, "job-uri",
1543 IPP_TAG_URI
)) != NULL
)
1544 set_variable(vars
, "job-uri", attrptr
->values
[0].string
.text
);
1546 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id",
1547 IPP_TAG_INTEGER
)) != NULL
)
1549 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
1550 set_variable(vars
, "notify-subscription-id", temp
);
1553 attrptr
= response
->attrs
;
1554 if (!attrptr
|| !attrptr
->name
||
1555 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
1556 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1557 attrptr
->num_values
!= 1 ||
1558 strcmp(attrptr
->name
, "attributes-charset"))
1563 attrptr
= attrptr
->next
;
1564 if (!attrptr
|| !attrptr
->name
||
1565 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
1566 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1567 attrptr
->num_values
!= 1 ||
1568 strcmp(attrptr
->name
, "attributes-natural-language"))
1572 if ((attrptr
= ippFindAttribute(response
, "status-message",
1573 IPP_TAG_ZERO
)) != NULL
&&
1574 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
1575 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1576 attrptr
->num_values
!= 1 ||
1577 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1578 strlen(attrptr
->values
[0].string
.text
) > 255)))
1581 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
1582 IPP_TAG_ZERO
)) != NULL
&&
1583 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
1584 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1585 attrptr
->num_values
!= 1 ||
1586 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1587 strlen(attrptr
->values
[0].string
.text
) > 1023)))
1590 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
1592 attrptr
= attrptr
->next
)
1594 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
1600 if (!validate_attr(attrptr
, 0))
1607 for (i
= 0; i
< num_statuses
; i
++)
1609 if (statuses
[i
].if_defined
&&
1610 !get_variable(vars
, statuses
[i
].if_defined
))
1613 if (statuses
[i
].if_undefined
&&
1614 get_variable(vars
, statuses
[i
].if_undefined
))
1617 if (response
->request
.status
.status_code
== statuses
[i
].status
)
1621 if (i
== num_statuses
&& num_statuses
> 0)
1625 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
1627 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
1630 if (expect
->if_undefined
&& get_variable(vars
, expect
->if_undefined
))
1633 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
1635 if ((found
&& expect
->not_expect
) ||
1636 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
1637 (found
&& !expect_matches(expect
, found
->value_tag
)) ||
1638 (found
&& expect
->in_group
&&
1639 found
->group_tag
!= expect
->in_group
))
1646 !with_value(expect
->with_value
, expect
->with_regex
, found
))
1652 if (found
&& expect
->count
> 0 && found
->num_values
!= expect
->count
)
1658 if (found
&& expect
->same_count_as
)
1660 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
1663 if (!attrptr
|| attrptr
->num_values
!= found
->num_values
)
1673 if (Output
== _CUPS_OUTPUT_PLIST
)
1675 puts("<key>Successful</key>");
1676 puts(pass
? "<true />" : "<false />");
1677 puts("<key>StatusCode</key>");
1678 print_xml_string("string", ippErrorString(cupsLastError()));
1679 puts("<key>ResponseAttributes</key>");
1681 for (attrptr
= response
? response
->attrs
: NULL
;
1683 attrptr
= attrptr
->next
)
1684 print_attr(attrptr
);
1687 else if (Output
== _CUPS_OUTPUT_TEST
)
1689 puts(pass
? "PASS]" : "FAIL]");
1691 if (Verbosity
&& response
)
1693 printf(" RECEIVED: %lu bytes in response\n",
1694 (unsigned long)ippLength(response
));
1695 printf(" status-code = %x (%s)\n", cupsLastError(),
1696 ippErrorString(cupsLastError()));
1698 for (attrptr
= response
->attrs
;
1700 attrptr
= attrptr
->next
)
1702 print_attr(attrptr
);
1707 fprintf(stderr
, "%s\n", cupsLastErrorString());
1709 if (pass
&& Output
!= _CUPS_OUTPUT_PLIST
&& Output
!= _CUPS_OUTPUT_QUIET
&&
1710 !Verbosity
&& num_displayed
> 0)
1712 if (Output
>= _CUPS_OUTPUT_LIST
)
1714 size_t width
; /* Length of value */
1717 for (i
= 0; i
< num_displayed
; i
++)
1719 widths
[i
] = strlen(displayed
[i
]);
1721 for (attrptr
= ippFindAttribute(response
, displayed
[i
], IPP_TAG_ZERO
);
1723 attrptr
= ippFindNextAttribute(response
, displayed
[i
],
1726 width
= _ippAttrString(attrptr
, NULL
, 0);
1727 if (width
> widths
[i
])
1732 if (Output
== _CUPS_OUTPUT_CSV
)
1733 print_csv(NULL
, num_displayed
, displayed
, widths
);
1735 print_line(NULL
, num_displayed
, displayed
, widths
);
1737 attrptr
= response
->attrs
;
1741 while (attrptr
&& attrptr
->group_tag
<= IPP_TAG_OPERATION
)
1742 attrptr
= attrptr
->next
;
1746 if (Output
== _CUPS_OUTPUT_CSV
)
1747 print_csv(attrptr
, num_displayed
, displayed
, widths
);
1749 print_line(attrptr
, num_displayed
, displayed
, widths
);
1751 while (attrptr
&& attrptr
->group_tag
> IPP_TAG_OPERATION
)
1752 attrptr
= attrptr
->next
;
1758 for (attrptr
= response
->attrs
;
1760 attrptr
= attrptr
->next
)
1764 for (i
= 0; i
< num_displayed
; i
++)
1766 if (!strcmp(displayed
[i
], attrptr
->name
))
1768 print_attr(attrptr
);
1778 if (Output
== _CUPS_OUTPUT_PLIST
)
1780 puts("<key>Errors</key>");
1784 if (http
->version
!= HTTP_1_1
)
1785 print_test_error("Bad HTTP version (%d.%d)", http
->version
/ 100,
1786 http
->version
% 100);
1789 print_test_error("IPP request failed with status %s (%s)",
1790 ippErrorString(cupsLastError()),
1791 cupsLastErrorString());
1794 if (response
->request
.status
.version
[0] != (version
/ 10) ||
1795 response
->request
.status
.version
[1] != (version
% 10))
1796 print_test_error("Bad version %d.%d in response - expected %d.%d "
1797 "(RFC 2911 section 3.1.8).",
1798 response
->request
.status
.version
[0],
1799 response
->request
.status
.version
[1],
1800 version
/ 10, version
% 10);
1802 if (response
->request
.status
.request_id
!= request_id
)
1803 print_test_error("Bad request ID %d in response - expected %d "
1804 "(RFC 2911 section 3.1.1)",
1805 response
->request
.status
.request_id
, request_id
);
1807 attrptr
= response
->attrs
;
1809 print_test_error("Missing first attribute \"attributes-charset "
1810 "(charset)\" in group operation-attributes-tag "
1811 "(RFC 2911 section 3.1.4).");
1814 if (!attrptr
->name
||
1815 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
1816 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1817 attrptr
->num_values
!= 1 ||
1818 strcmp(attrptr
->name
, "attributes-charset"))
1819 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
1820 "expected \"attributes-charset (charset)\" in "
1821 "group operation-attributes-tag (RFC 2911 section "
1823 attrptr
->name
? attrptr
->name
: "(null)",
1824 attrptr
->num_values
> 1 ? "1setOf " : "",
1825 ippTagString(attrptr
->value_tag
),
1826 ippTagString(attrptr
->group_tag
));
1828 attrptr
= attrptr
->next
;
1830 print_test_error("Missing second attribute \"attributes-natural-"
1831 "language (naturalLanguage)\" in group "
1832 "operation-attributes-tag (RFC 2911 section "
1834 else if (!attrptr
->name
||
1835 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
1836 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1837 attrptr
->num_values
!= 1 ||
1838 strcmp(attrptr
->name
, "attributes-natural-language"))
1839 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
1840 "expected \"attributes-natural-language "
1841 "(naturalLanguage)\" in group "
1842 "operation-attributes-tag (RFC 2911 section "
1844 attrptr
->name
? attrptr
->name
: "(null)",
1845 attrptr
->num_values
> 1 ? "1setOf " : "",
1846 ippTagString(attrptr
->value_tag
),
1847 ippTagString(attrptr
->group_tag
));
1850 if ((attrptr
= ippFindAttribute(response
, "status-message",
1851 IPP_TAG_ZERO
)) != NULL
)
1853 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
1854 print_test_error("status-message (text(255)) has wrong value tag "
1855 "%s (RFC 2911 section 3.1.6.2).",
1856 ippTagString(attrptr
->value_tag
));
1857 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
1858 print_test_error("status-message (text(255)) has wrong group tag "
1859 "%s (RFC 2911 section 3.1.6.2).",
1860 ippTagString(attrptr
->group_tag
));
1861 if (attrptr
->num_values
!= 1)
1862 print_test_error("status-message (text(255)) has %d values "
1863 "(RFC 2911 section 3.1.6.2).",
1864 attrptr
->num_values
);
1865 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1866 strlen(attrptr
->values
[0].string
.text
) > 255)
1867 print_test_error("status-message (text(255)) has bad length %d"
1868 " (RFC 2911 section 3.1.6.2).",
1869 (int)strlen(attrptr
->values
[0].string
.text
));
1872 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
1873 IPP_TAG_ZERO
)) != NULL
)
1875 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
1876 print_test_error("detailed-status-message (text(MAX)) has wrong "
1877 "value tag %s (RFC 2911 section 3.1.6.3).",
1878 ippTagString(attrptr
->value_tag
));
1879 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
1880 print_test_error("detailed-status-message (text(MAX)) has wrong "
1881 "group tag %s (RFC 2911 section 3.1.6.3).",
1882 ippTagString(attrptr
->group_tag
));
1883 if (attrptr
->num_values
!= 1)
1884 print_test_error("detailed-status-message (text(MAX)) has %d values"
1885 " (RFC 2911 section 3.1.6.3).",
1886 attrptr
->num_values
);
1887 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1888 strlen(attrptr
->values
[0].string
.text
) > 1023)
1889 print_test_error("detailed-status-message (text(MAX)) has bad "
1890 "length %d (RFC 2911 section 3.1.6.3).",
1891 (int)strlen(attrptr
->values
[0].string
.text
));
1894 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
1896 attrptr
= attrptr
->next
)
1898 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
1899 print_test_error("Attribute groups out of order (%s < %s)",
1900 ippTagString(attrptr
->group_tag
),
1901 ippTagString(group
));
1903 validate_attr(attrptr
, 1);
1906 for (i
= 0; i
< num_statuses
; i
++)
1908 if (statuses
[i
].if_defined
&&
1909 !get_variable(vars
, statuses
[i
].if_defined
))
1912 if (statuses
[i
].if_undefined
&&
1913 get_variable(vars
, statuses
[i
].if_undefined
))
1916 if (response
->request
.status
.status_code
== statuses
[i
].status
)
1920 if (i
== num_statuses
&& num_statuses
> 0)
1922 print_test_error("Bad status-code (%s)",
1923 ippErrorString(cupsLastError()));
1924 print_test_error("status-message=\"%s\"", cupsLastErrorString());
1927 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
1929 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
1932 if (expect
->if_undefined
&& get_variable(vars
, expect
->if_undefined
))
1935 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
1937 if (found
&& expect
->not_expect
)
1938 print_test_error("NOT EXPECTED: %s", expect
->name
);
1939 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
1940 print_test_error("EXPECTED: %s", expect
->name
);
1943 if (!expect_matches(expect
, found
->value_tag
))
1944 print_test_error("EXPECTED: %s OF-TYPE %s (got %s)",
1945 expect
->name
, expect
->of_type
,
1946 ippTagString(found
->value_tag
));
1948 if (expect
->in_group
&& found
->group_tag
!= expect
->in_group
)
1949 print_test_error("EXPECTED: %s IN-GROUP %s (got %s).",
1950 expect
->name
, ippTagString(expect
->in_group
),
1951 ippTagString(found
->group_tag
));
1953 if (!with_value(expect
->with_value
, expect
->with_regex
, found
))
1955 if (expect
->with_regex
)
1956 print_test_error("EXPECTED: %s WITH-VALUE /%s/",
1957 expect
->name
, expect
->with_value
);
1959 print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
1960 expect
->name
, expect
->with_value
);
1963 if (expect
->count
> 0 && found
->num_values
!= expect
->count
)
1965 print_test_error("EXPECTED: %s COUNT %d (got %d)", expect
->name
,
1966 expect
->count
, found
->num_values
);
1969 if (expect
->same_count_as
)
1971 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
1975 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1976 "(not returned)", expect
->name
,
1977 found
->num_values
, expect
->same_count_as
);
1978 else if (attrptr
->num_values
!= found
->num_values
)
1979 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1980 "(%d values)", expect
->name
, found
->num_values
,
1981 expect
->same_count_as
, attrptr
->num_values
);
1987 if (Output
== _CUPS_OUTPUT_PLIST
)
1991 if (Output
== _CUPS_OUTPUT_PLIST
)
1994 ippDelete(response
);
1997 for (i
= 0; i
< num_statuses
; i
++)
1999 if (statuses
[i
].if_defined
)
2000 free(statuses
[i
].if_defined
);
2001 if (statuses
[i
].if_undefined
)
2002 free(statuses
[i
].if_undefined
);
2006 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2009 if (expect
->of_type
)
2010 free(expect
->of_type
);
2011 if (expect
->same_count_as
)
2012 free(expect
->same_count_as
);
2013 if (expect
->if_defined
)
2014 free(expect
->if_defined
);
2015 if (expect
->if_undefined
)
2016 free(expect
->if_undefined
);
2017 if (expect
->with_value
)
2018 free(expect
->with_value
);
2022 for (i
= 0; i
< num_displayed
; i
++)
2036 * If we get here there was a fatal test error...
2046 ippDelete(response
);
2048 for (i
= 0; i
< num_statuses
; i
++)
2050 if (statuses
[i
].if_defined
)
2051 free(statuses
[i
].if_defined
);
2052 if (statuses
[i
].if_undefined
)
2053 free(statuses
[i
].if_undefined
);
2056 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
2059 if (expect
->of_type
)
2060 free(expect
->of_type
);
2061 if (expect
->same_count_as
)
2062 free(expect
->same_count_as
);
2063 if (expect
->if_defined
)
2064 free(expect
->if_defined
);
2065 if (expect
->if_undefined
)
2066 free(expect
->if_undefined
);
2067 if (expect
->with_value
)
2068 free(expect
->with_value
);
2071 for (i
= 0; i
< num_displayed
; i
++)
2079 * 'expand_variables()' - Expand variables in a string.
2083 expand_variables(_cups_vars_t
*vars
, /* I - Variables */
2084 char *dst
, /* I - Destination string buffer */
2085 const char *src
, /* I - Source string */
2086 size_t dstsize
) /* I - Size of destination buffer */
2088 char *dstptr
, /* Pointer into destination */
2089 *dstend
, /* End of destination */
2090 temp
[256], /* Temporary string */
2091 *tempptr
; /* Pointer into temporary string */
2092 const char *value
; /* Value to substitute */
2096 dstend
= dst
+ dstsize
- 1;
2098 while (*src
&& dstptr
< dstend
)
2103 * Substitute a string/number...
2106 if (!strncmp(src
, "$$", 2))
2111 else if (!strncmp(src
, "$ENV[", 5))
2113 strlcpy(temp
, src
+ 5, sizeof(temp
));
2115 for (tempptr
= temp
; *tempptr
; tempptr
++)
2116 if (*tempptr
== ']')
2122 value
= getenv(temp
);
2123 src
+= tempptr
- temp
+ 5;
2127 strlcpy(temp
, src
+ 1, sizeof(temp
));
2129 for (tempptr
= temp
; *tempptr
; tempptr
++)
2130 if (!isalnum(*tempptr
& 255) && *tempptr
!= '-' && *tempptr
!= '_')
2136 if (!strcmp(temp
, "uri"))
2138 else if (!strcmp(temp
, "filename"))
2139 value
= vars
->filename
;
2140 else if (!strcmp(temp
, "scheme") || !strcmp(temp
, "method"))
2141 value
= vars
->scheme
;
2142 else if (!strcmp(temp
, "username"))
2143 value
= vars
->userpass
;
2144 else if (!strcmp(temp
, "hostname"))
2145 value
= vars
->hostname
;
2146 else if (!strcmp(temp
, "port"))
2148 snprintf(temp
, sizeof(temp
), "%d", vars
->port
);
2151 else if (!strcmp(temp
, "resource"))
2152 value
= vars
->resource
;
2153 else if (!strcmp(temp
, "user"))
2156 value
= get_variable(vars
, temp
);
2158 src
+= tempptr
- temp
+ 1;
2168 strlcpy(dstptr
, value
, dstend
- dstptr
+ 1);
2169 dstptr
+= strlen(dstptr
);
2181 * 'expect_matches()' - Return true if the tag matches the specification.
2184 static int /* O - 1 if matches, 0 otherwise */
2186 _cups_expect_t
*expect
, /* I - Expected attribute */
2187 ipp_tag_t value_tag
) /* I - Value tag for attribute */
2189 int match
; /* Match? */
2190 char *of_type
, /* Type name to match */
2191 *next
, /* Next name to match */
2192 sep
; /* Separator character */
2196 * If we don't expect a particular type, return immediately...
2199 if (!expect
->of_type
)
2203 * Parse the "of_type" value since the string can contain multiple attribute
2204 * types separated by "," or "|"...
2207 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
2210 * Find the next separator, and set it (temporarily) to nul if present.
2213 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
2215 if ((sep
= *next
) != '\0')
2219 * Support some meta-types to make it easier to write the test file.
2222 if (!strcmp(of_type
, "text"))
2223 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
2224 else if (!strcmp(of_type
, "name"))
2225 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
2226 else if (!strcmp(of_type
, "collection"))
2227 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
2229 match
= value_tag
== ippTagValue(of_type
);
2232 * Restore the separator if we have one...
2244 * 'get_collection()' - Get a collection value from the current test file.
2247 static ipp_t
* /* O - Collection value */
2248 get_collection(_cups_vars_t
*vars
, /* I - Variables */
2249 FILE *fp
, /* I - File to read from */
2250 int *linenum
) /* IO - Line number */
2252 char token
[1024], /* Token from file */
2253 temp
[1024], /* Temporary string */
2254 attr
[128]; /* Attribute name */
2255 ipp_tag_t value
; /* Current value type */
2256 ipp_t
*col
= ippNew(); /* Collection value */
2257 ipp_attribute_t
*lastcol
= NULL
; /* Last collection attribute */
2260 while (get_token(fp
, token
, sizeof(token
), linenum
) != NULL
)
2262 if (!strcmp(token
, "}"))
2264 else if (!strcmp(token
, "{") && lastcol
)
2267 * Another collection value
2270 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
2271 /* Collection value */
2275 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
2279 * Reallocate memory...
2282 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
2283 (lastcol
->num_values
+ 1) *
2284 sizeof(ipp_value_t
))) == NULL
)
2286 print_fatal_error("Unable to allocate memory on line %d.", *linenum
);
2290 if (tempcol
!= lastcol
)
2293 * Reset pointers in the list...
2297 col
->prev
->next
= tempcol
;
2299 col
->attrs
= tempcol
;
2301 lastcol
= col
->current
= col
->last
= tempcol
;
2304 lastcol
->values
[lastcol
->num_values
].collection
= subcol
;
2305 lastcol
->num_values
++;
2310 else if (!strcasecmp(token
, "MEMBER"))
2318 if (!get_token(fp
, token
, sizeof(token
), linenum
))
2320 print_fatal_error("Missing MEMBER value tag on line %d.", *linenum
);
2324 if ((value
= ippTagValue(token
)) < 0)
2326 print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token
,
2331 if (!get_token(fp
, attr
, sizeof(attr
), linenum
))
2333 print_fatal_error("Missing MEMBER name on line %d.", *linenum
);
2337 if (!get_token(fp
, temp
, sizeof(temp
), linenum
))
2339 print_fatal_error("Missing MEMBER value on line %d.", *linenum
);
2343 expand_variables(vars
, token
, temp
, sizeof(token
));
2347 case IPP_TAG_BOOLEAN
:
2348 if (!strcasecmp(token
, "true"))
2349 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, 1);
2351 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, atoi(token
));
2354 case IPP_TAG_INTEGER
:
2356 ippAddInteger(col
, IPP_TAG_ZERO
, value
, attr
, atoi(token
));
2359 case IPP_TAG_RESOLUTION
:
2361 int xres
, /* X resolution */
2362 yres
; /* Y resolution */
2363 char units
[6]; /* Units */
2365 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
2366 (strcasecmp(units
, "dpi") && strcasecmp(units
, "dpc") &&
2367 strcasecmp(units
, "other")))
2369 print_fatal_error("Bad resolution value \"%s\" on line %d.",
2374 if (!strcasecmp(units
, "dpi"))
2375 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2377 else if (!strcasecmp(units
, "dpc"))
2378 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2381 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2386 case IPP_TAG_RANGE
:
2388 int lowers
[4], /* Lower value */
2389 uppers
[4], /* Upper values */
2390 num_vals
; /* Number of values */
2393 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
2394 lowers
+ 0, uppers
+ 0,
2395 lowers
+ 1, uppers
+ 1,
2396 lowers
+ 2, uppers
+ 2,
2397 lowers
+ 3, uppers
+ 3);
2399 if ((num_vals
& 1) || num_vals
== 0)
2401 print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
2406 ippAddRanges(col
, IPP_TAG_ZERO
, attr
, num_vals
/ 2, lowers
,
2411 case IPP_TAG_BEGIN_COLLECTION
:
2412 if (!strcmp(token
, "{"))
2414 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
2415 /* Collection value */
2419 lastcol
= ippAddCollection(col
, IPP_TAG_ZERO
, attr
, subcol
);
2427 print_fatal_error("Bad collection value on line %d.", *linenum
);
2433 if (!strchr(token
, ','))
2434 ippAddString(col
, IPP_TAG_ZERO
, value
, attr
, NULL
, token
);
2438 * Multiple string values...
2441 int num_values
; /* Number of values */
2442 char *values
[100], /* Values */
2443 *ptr
; /* Pointer to next value */
2449 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
2452 values
[num_values
] = ptr
;
2456 ippAddStrings(col
, IPP_TAG_ZERO
, value
, attr
, num_values
,
2457 NULL
, (const char **)values
);
2467 * If we get here there was a parse error; free memory and return.
2479 * 'get_filename()' - Get a filename based on the current test file.
2482 static char * /* O - Filename */
2483 get_filename(const char *testfile
, /* I - Current test file */
2484 char *dst
, /* I - Destination filename */
2485 const char *src
, /* I - Source filename */
2486 size_t dstsize
) /* I - Size of destination buffer */
2488 char *dstptr
; /* Pointer into destination */
2489 _cups_globals_t
*cg
= _cupsGlobals();
2493 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
2496 * Map <filename> to CUPS_DATADIR/ipptool/filename...
2499 snprintf(dst
, dstsize
, "%s/ipptool/%s", cg
->cups_datadir
, src
+ 1);
2500 dstptr
= dst
+ strlen(dst
) - 1;
2504 else if (*src
== '/' || !strchr(testfile
, '/'))
2507 * Use the path as-is...
2510 strlcpy(dst
, src
, dstsize
);
2515 * Make path relative to testfile...
2518 strlcpy(dst
, testfile
, dstsize
);
2519 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
2522 dstptr
= dst
; /* Should never happen */
2524 strlcpy(dstptr
, src
, dstsize
- (dstptr
- dst
));
2532 * 'get_token()' - Get a token from a file.
2535 static char * /* O - Token from file or NULL on EOF */
2536 get_token(FILE *fp
, /* I - File to read from */
2537 char *buf
, /* I - Buffer to read into */
2538 int buflen
, /* I - Length of buffer */
2539 int *linenum
) /* IO - Current line number */
2541 int ch
, /* Character from file */
2542 quote
; /* Quoting character */
2543 char *bufptr
, /* Pointer into buffer */
2544 *bufend
; /* End of buffer */
2550 * Skip whitespace...
2553 while (isspace(ch
= getc(fp
)))
2565 else if (ch
== '\'' || ch
== '\"')
2568 * Quoted text or regular expression...
2573 bufend
= buf
+ buflen
- 1;
2575 while ((ch
= getc(fp
)) != EOF
)
2580 * Escape next character...
2583 if (bufptr
< bufend
)
2586 if ((ch
= getc(fp
)) != EOF
&& bufptr
< bufend
)
2589 else if (ch
== quote
)
2591 else if (bufptr
< bufend
)
2605 while ((ch
= getc(fp
)) != EOF
)
2614 * Whitespace delimited text...
2620 bufend
= buf
+ buflen
- 1;
2622 while ((ch
= getc(fp
)) != EOF
)
2623 if (isspace(ch
) || ch
== '#')
2625 else if (bufptr
< bufend
)
2630 else if (ch
== '\n')
2642 * 'get_variable()' - Get the value of a variable.
2645 static char * /* O - Value or NULL */
2646 get_variable(_cups_vars_t
*vars
, /* I - Variables */
2647 const char *name
) /* I - Variable name */
2649 _cups_var_t key
, /* Search key */
2650 *match
; /* Matching variable, if any */
2653 key
.name
= (char *)name
;
2654 match
= cupsArrayFind(vars
->vars
, &key
);
2656 return (match
? match
->value
: NULL
);
2661 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
2665 static char * /* O - ISO 8601 date/time string */
2666 iso_date(ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
2668 unsigned year
= (date
[0] << 8) + date
[1];
2670 static char buffer
[255]; /* String buffer */
2673 if (date
[9] == 0 && date
[10] == 0)
2674 snprintf(buffer
, sizeof(buffer
), "%04u-%02u-%02uT%02u:%02u:%02uZ",
2675 year
, date
[2], date
[3], date
[4], date
[5], date
[6]);
2677 snprintf(buffer
, sizeof(buffer
), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
2678 year
, date
[2], date
[3], date
[4], date
[5], date
[6],
2679 date
[8], date
[9], date
[10]);
2686 * 'print_attr()' - Print an attribute on the screen.
2690 print_attr(ipp_attribute_t
*attr
) /* I - Attribute to print */
2692 int i
; /* Looping var */
2693 ipp_attribute_t
*colattr
; /* Collection attribute */
2696 if (Output
== _CUPS_OUTPUT_PLIST
)
2700 printf("<key>%s</key>\n<true />\n", ippTagString(attr
->group_tag
));
2704 print_xml_string("key", attr
->name
);
2705 if (attr
->num_values
> 1)
2708 else if (Output
== _CUPS_OUTPUT_TEST
)
2712 puts(" -- separator --");
2716 printf(" %s (%s%s) = ", attr
->name
,
2717 attr
->num_values
> 1 ? "1setOf " : "",
2718 ippTagString(attr
->value_tag
));
2721 switch (attr
->value_tag
)
2723 case IPP_TAG_INTEGER
:
2725 for (i
= 0; i
< attr
->num_values
; i
++)
2726 if (Output
== _CUPS_OUTPUT_PLIST
)
2727 printf("<integer>%d</integer>\n", attr
->values
[i
].integer
);
2729 printf("%d ", attr
->values
[i
].integer
);
2732 case IPP_TAG_BOOLEAN
:
2733 for (i
= 0; i
< attr
->num_values
; i
++)
2734 if (Output
== _CUPS_OUTPUT_PLIST
)
2735 puts(attr
->values
[i
].boolean
? "<true />" : "<false />");
2736 else if (attr
->values
[i
].boolean
)
2737 fputs("true ", stdout
);
2739 fputs("false ", stdout
);
2742 case IPP_TAG_RANGE
:
2743 for (i
= 0; i
< attr
->num_values
; i
++)
2744 if (Output
== _CUPS_OUTPUT_PLIST
)
2745 printf("<dict><key>lower</key><integer>%d</integer>"
2746 "<key>upper</key><integer>%d</integer></dict>\n",
2747 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
2749 printf("%d-%d ", attr
->values
[i
].range
.lower
,
2750 attr
->values
[i
].range
.upper
);
2753 case IPP_TAG_RESOLUTION
:
2754 for (i
= 0; i
< attr
->num_values
; i
++)
2755 if (Output
== _CUPS_OUTPUT_PLIST
)
2756 printf("<dict><key>xres</key><integer>%d</integer>"
2757 "<key>yres</key><integer>%d</integer>"
2758 "<key>units</key><string>%s</string></dict>\n",
2759 attr
->values
[i
].resolution
.xres
,
2760 attr
->values
[i
].resolution
.yres
,
2761 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2764 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
2765 attr
->values
[i
].resolution
.yres
,
2766 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2771 for (i
= 0; i
< attr
->num_values
; i
++)
2772 if (Output
== _CUPS_OUTPUT_PLIST
)
2773 printf("<date>%s</date>\n", iso_date(attr
->values
[i
].date
));
2775 printf("%s ", iso_date(attr
->values
[i
].date
));
2778 case IPP_TAG_STRING
:
2781 case IPP_TAG_KEYWORD
:
2782 case IPP_TAG_CHARSET
:
2784 case IPP_TAG_MIMETYPE
:
2785 case IPP_TAG_LANGUAGE
:
2786 for (i
= 0; i
< attr
->num_values
; i
++)
2787 if (Output
== _CUPS_OUTPUT_PLIST
)
2788 print_xml_string("string", attr
->values
[i
].string
.text
);
2790 printf("\"%s\" ", attr
->values
[i
].string
.text
);
2793 case IPP_TAG_TEXTLANG
:
2794 case IPP_TAG_NAMELANG
:
2795 for (i
= 0; i
< attr
->num_values
; i
++)
2796 if (Output
== _CUPS_OUTPUT_PLIST
)
2798 fputs("<dict><key>language</key><string>", stdout
);
2799 print_xml_string(NULL
, attr
->values
[i
].string
.charset
);
2800 fputs("</string><key>string</key><string>", stdout
);
2801 print_xml_string(NULL
, attr
->values
[i
].string
.text
);
2802 puts("</string></dict>");
2805 printf("\"%s\",%s ", attr
->values
[i
].string
.text
,
2806 attr
->values
[i
].string
.charset
);
2809 case IPP_TAG_BEGIN_COLLECTION
:
2810 for (i
= 0; i
< attr
->num_values
; i
++)
2812 if (Output
== _CUPS_OUTPUT_PLIST
)
2815 for (colattr
= attr
->values
[i
].collection
->attrs
;
2817 colattr
= colattr
->next
)
2818 print_attr(colattr
);
2826 print_col(attr
->values
[i
].collection
);
2832 if (Output
== _CUPS_OUTPUT_PLIST
)
2833 printf("<string><<%s>></string>\n",
2834 ippTagString(attr
->value_tag
));
2836 fputs(ippTagString(attr
->value_tag
), stdout
);
2840 if (Output
== _CUPS_OUTPUT_PLIST
)
2842 if (attr
->num_values
> 1)
2851 * 'print_col()' - Print a collection attribute on the screen.
2855 print_col(ipp_t
*col
) /* I - Collection attribute to print */
2857 int i
; /* Looping var */
2858 ipp_attribute_t
*attr
; /* Current attribute in collection */
2861 fputs("{ ", stdout
);
2862 for (attr
= col
->attrs
; attr
; attr
= attr
->next
)
2864 printf("%s (%s%s) = ", attr
->name
, attr
->num_values
> 1 ? "1setOf " : "",
2865 ippTagString(attr
->value_tag
));
2867 switch (attr
->value_tag
)
2869 case IPP_TAG_INTEGER
:
2871 for (i
= 0; i
< attr
->num_values
; i
++)
2872 printf("%d ", attr
->values
[i
].integer
);
2875 case IPP_TAG_BOOLEAN
:
2876 for (i
= 0; i
< attr
->num_values
; i
++)
2877 if (attr
->values
[i
].boolean
)
2883 case IPP_TAG_NOVALUE
:
2887 case IPP_TAG_RANGE
:
2888 for (i
= 0; i
< attr
->num_values
; i
++)
2889 printf("%d-%d ", attr
->values
[i
].range
.lower
,
2890 attr
->values
[i
].range
.upper
);
2893 case IPP_TAG_RESOLUTION
:
2894 for (i
= 0; i
< attr
->num_values
; i
++)
2895 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
2896 attr
->values
[i
].resolution
.yres
,
2897 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2901 case IPP_TAG_STRING
:
2904 case IPP_TAG_KEYWORD
:
2905 case IPP_TAG_CHARSET
:
2907 case IPP_TAG_MIMETYPE
:
2908 case IPP_TAG_LANGUAGE
:
2909 for (i
= 0; i
< attr
->num_values
; i
++)
2910 printf("\"%s\" ", attr
->values
[i
].string
.text
);
2913 case IPP_TAG_TEXTLANG
:
2914 case IPP_TAG_NAMELANG
:
2915 for (i
= 0; i
< attr
->num_values
; i
++)
2916 printf("\"%s\",%s ", attr
->values
[i
].string
.text
,
2917 attr
->values
[i
].string
.charset
);
2920 case IPP_TAG_BEGIN_COLLECTION
:
2921 for (i
= 0; i
< attr
->num_values
; i
++)
2923 print_col(attr
->values
[i
].collection
);
2929 break; /* anti-compiler-warning-code */
2938 * 'print_csv()' - Print a line of CSV text.
2943 ipp_attribute_t
*attr
, /* I - First attribute for line */
2944 int num_displayed
, /* I - Number of attributes to display */
2945 char **displayed
, /* I - Attributes to display */
2946 size_t *widths
) /* I - Column widths */
2948 int i
; /* Looping var */
2949 size_t maxlength
; /* Max length of all columns */
2950 char *buffer
, /* String buffer */
2951 *bufptr
; /* Pointer into buffer */
2952 ipp_attribute_t
*current
; /* Current attribute */
2956 * Get the maximum string length we have to show and allocate...
2959 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
2960 if (widths
[i
] > maxlength
)
2961 maxlength
= widths
[i
];
2965 if ((buffer
= malloc(maxlength
)) == NULL
)
2969 * Loop through the attributes to display...
2974 for (i
= 0; i
< num_displayed
; i
++)
2981 for (current
= attr
; current
; current
= current
->next
)
2985 else if (!strcmp(current
->name
, displayed
[i
]))
2987 _ippAttrString(current
, buffer
, maxlength
);
2992 if (strchr(buffer
, ',') != NULL
|| strchr(buffer
, '\"') != NULL
||
2993 strchr(buffer
, '\\') != NULL
)
2996 for (bufptr
= buffer
; *bufptr
; bufptr
++)
2998 if (*bufptr
== '\\' || *bufptr
== '\"')
3005 fputs(buffer
, stdout
);
3011 for (i
= 0; i
< num_displayed
; i
++)
3016 fputs(displayed
[i
], stdout
);
3026 * 'print_fatal_error()' - Print a fatal error message.
3030 print_fatal_error(const char *s
, /* I - Printf-style format string */
3031 ...) /* I - Additional arguments as needed */
3033 char buffer
[10240]; /* Format buffer */
3034 va_list ap
; /* Pointer to arguments */
3038 * Format the error message...
3042 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
3049 if (Output
== _CUPS_OUTPUT_PLIST
)
3052 print_xml_trailer(0, buffer
);
3055 _cupsLangPrintf(stderr
, "ipptool: %s\n", buffer
);
3060 * 'print_line()' - Print a line of formatted or CSV text.
3065 ipp_attribute_t
*attr
, /* I - First attribute for line */
3066 int num_displayed
, /* I - Number of attributes to display */
3067 char **displayed
, /* I - Attributes to display */
3068 size_t *widths
) /* I - Column widths */
3070 int i
; /* Looping var */
3071 size_t maxlength
; /* Max length of all columns */
3072 char *buffer
; /* String buffer */
3073 ipp_attribute_t
*current
; /* Current attribute */
3077 * Get the maximum string length we have to show and allocate...
3080 for (i
= 1, maxlength
= widths
[0]; i
< num_displayed
; i
++)
3081 if (widths
[i
] > maxlength
)
3082 maxlength
= widths
[i
];
3086 if ((buffer
= malloc(maxlength
)) == NULL
)
3090 * Loop through the attributes to display...
3095 for (i
= 0; i
< num_displayed
; i
++)
3102 for (current
= attr
; current
; current
= current
->next
)
3106 else if (!strcmp(current
->name
, displayed
[i
]))
3108 _ippAttrString(current
, buffer
, maxlength
);
3113 printf("%*s", (int)-widths
[i
], buffer
);
3119 for (i
= 0; i
< num_displayed
; i
++)
3124 printf("%*s", (int)-widths
[i
], displayed
[i
]);
3128 for (i
= 0; i
< num_displayed
; i
++)
3133 memset(buffer
, '-', widths
[i
]);
3134 buffer
[widths
[i
]] = '\0';
3135 fputs(buffer
, stdout
);
3145 * 'print_test_error()' - Print a test error message.
3149 print_test_error(const char *s
, /* I - Printf-style format string */
3150 ...) /* I - Additional arguments as needed */
3152 char buffer
[10240]; /* Format buffer */
3153 va_list ap
; /* Pointer to arguments */
3157 * Format the error message...
3161 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
3168 if (Output
== _CUPS_OUTPUT_PLIST
)
3169 print_xml_string("string", buffer
);
3171 printf(" %s\n", buffer
);
3176 * 'print_xml_header()' - Print a standard XML plist header.
3180 print_xml_header(void)
3184 puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
3185 puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
3186 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
3187 puts("<plist version=\"1.0\">");
3189 puts("<key>Transfer</key>");
3190 printf("<string>%s</string>\n",
3191 Transfer
== _CUPS_TRANSFER_AUTO
? "auto" :
3192 Transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
3193 puts("<key>Tests</key>");
3202 * 'print_xml_string()' - Print an XML string with escaping.
3206 print_xml_string(const char *element
, /* I - Element name or NULL */
3207 const char *s
) /* I - String to print */
3210 printf("<%s>", element
);
3215 fputs("&", stdout
);
3217 fputs("<", stdout
);
3219 fputs(">", stdout
);
3227 printf("</%s>\n", element
);
3232 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
3236 print_xml_trailer(int success
, /* I - 1 on success, 0 on failure */
3237 const char *message
) /* I - Error message or NULL */
3242 puts("<key>Successful</key>");
3243 puts(success
? "<true />" : "<false />");
3246 puts("<key>ErrorMessage</key>");
3247 print_xml_string("string", message
);
3258 * 'set_variable()' - Set a variable value.
3262 set_variable(_cups_vars_t
*vars
, /* I - Variables */
3263 const char *name
, /* I - Variable name */
3264 const char *value
) /* I - Value string */
3266 _cups_var_t key
, /* Search key */
3267 *var
; /* New variable */
3270 key
.name
= (char *)name
;
3271 if ((var
= cupsArrayFind(vars
->vars
, &key
)) != NULL
)
3274 var
->value
= strdup(value
);
3276 else if ((var
= malloc(sizeof(_cups_var_t
))) == NULL
)
3278 print_fatal_error("Unable to allocate memory for variable \"%s\".", name
);
3283 var
->name
= strdup(name
);
3284 var
->value
= strdup(value
);
3286 cupsArrayAdd(vars
->vars
, var
);
3292 * 'usage()' - Show program usage.
3298 _cupsLangPuts(stderr
,
3299 _("Usage: ipptool [options] URI filename [ ... "
3304 "-C Send requests using chunking (default)\n"
3305 "-E Test with TLS encryption.\n"
3306 "-L Send requests using content-length\n"
3307 "-S Test with SSL encryption.\n"
3308 "-V version Set default IPP version.\n"
3309 "-X Produce XML plist instead of plain text.\n"
3310 "-d name=value Define variable.\n"
3311 "-f filename Set default request filename.\n"
3312 "-i seconds Repeat the last file with the given time "
3314 "-n count Repeat the last file the given number of "
3316 "-q Be quiet - no output except errors.\n"
3317 "-t Produce a test report.\n"
3318 "-v Show all attributes sent and received.\n"));
3325 * 'validate_attr()' - Determine whether an attribute is valid.
3328 static int /* O - 1 if valid, 0 otherwise */
3329 validate_attr(ipp_attribute_t
*attr
, /* I - Attribute to validate */
3330 int print
) /* I - 1 = report issues to stdout */
3332 int i
; /* Looping var */
3333 char scheme
[64], /* Scheme from URI */
3334 userpass
[256], /* Username/password from URI */
3335 hostname
[256], /* Hostname from URI */
3336 resource
[1024]; /* Resource from URI */
3337 int port
, /* Port number from URI */
3338 uri_status
, /* URI separation status */
3339 valid
= 1; /* Is the attribute valid? */
3340 const char *ptr
; /* Pointer into string */
3341 ipp_attribute_t
*colattr
; /* Collection attribute */
3342 regex_t re
; /* Regular expression */
3343 ipp_uchar_t
*date
; /* Current date value */
3354 * Validate the attribute name.
3357 for (ptr
= attr
->name
; *ptr
; ptr
++)
3358 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
3361 if (*ptr
|| ptr
== attr
->name
)
3366 print_test_error("\"%s\": Bad attribute name - invalid character (RFC "
3367 "2911 section 4.1.3).", attr
->name
);
3370 if ((ptr
- attr
->name
) > 255)
3375 print_test_error("\"%s\": Bad attribute name - bad length (RFC 2911 "
3376 "section 4.1.3).", attr
->name
);
3379 switch (attr
->value_tag
)
3381 case IPP_TAG_INTEGER
:
3384 case IPP_TAG_BOOLEAN
:
3385 for (i
= 0; i
< attr
->num_values
; i
++)
3387 if (attr
->values
[i
].boolean
!= 0 &&
3388 attr
->values
[i
].boolean
!= 1)
3393 print_test_error("\"%s\": Bad boolen value %d (RFC 2911 section "
3394 "4.1.10).", attr
->name
, attr
->values
[i
].boolean
);
3402 for (i
= 0; i
< attr
->num_values
; i
++)
3404 if (attr
->values
[i
].integer
< 1)
3409 print_test_error("\"%s\": Bad enum value %d - out of range "
3410 "(RFC 2911 section 4.1.4).", attr
->name
,
3411 attr
->values
[i
].integer
);
3418 case IPP_TAG_STRING
:
3419 for (i
= 0; i
< attr
->num_values
; i
++)
3421 if (attr
->values
[i
].unknown
.length
> 1023)
3426 print_test_error("\"%s\": Bad octetString value - bad length %d "
3427 "(RFC 2911 section 4.1.10).", attr
->name
,
3428 attr
->values
[i
].unknown
.length
);
3436 for (i
= 0; i
< attr
->num_values
; i
++)
3438 date
= attr
->values
[i
].date
;
3440 if (date
[2] < 1 || date
[2] > 12)
3445 print_test_error("\"%s\": Bad dateTime month %u (RFC 2911 "
3446 "section 4.1.13).", attr
->name
, date
[2]);
3451 if (date
[3] < 1 || date
[3] > 31)
3456 print_test_error("\"%s\": Bad dateTime day %u (RFC 2911 "
3457 "section 4.1.13).", attr
->name
, date
[3]);
3467 print_test_error("\"%s\": Bad dateTime hours %u (RFC 2911 "
3468 "section 4.1.13).", attr
->name
, date
[4]);
3478 print_test_error("\"%s\": Bad dateTime minutes %u (RFC 2911 "
3479 "section 4.1.13).", attr
->name
, date
[5]);
3489 print_test_error("\"%s\": Bad dateTime seconds %u (RFC 2911 "
3490 "section 4.1.13).", attr
->name
, date
[6]);
3500 print_test_error("\"%s\": Bad dateTime deciseconds %u (RFC 2911 "
3501 "section 4.1.13).", attr
->name
, date
[7]);
3506 if (date
[8] != '-' && date
[8] != '+')
3511 print_test_error("\"%s\": Bad dateTime UTC sign '%c' (RFC 2911 "
3512 "section 4.1.13).", attr
->name
, date
[8]);
3522 print_test_error("\"%s\": Bad dateTime UTC hours %u (RFC 2911 "
3523 "section 4.1.13).", attr
->name
, date
[9]);
3533 print_test_error("\"%s\": Bad dateTime UTC minutes %u (RFC 2911 "
3534 "section 4.1.13).", attr
->name
, date
[10]);
3541 case IPP_TAG_RESOLUTION
:
3542 for (i
= 0; i
< attr
->num_values
; i
++)
3544 if (attr
->values
[i
].resolution
.xres
<= 0)
3549 print_test_error("\"%s\": Bad resolution value %dx%d%s - cross "
3550 "feed resolution must be positive (RFC 2911 "
3551 "section 4.1.13).", attr
->name
,
3552 attr
->values
[i
].resolution
.xres
,
3553 attr
->values
[i
].resolution
.yres
,
3554 attr
->values
[i
].resolution
.units
==
3555 IPP_RES_PER_INCH
? "dpi" :
3556 attr
->values
[i
].resolution
.units
==
3557 IPP_RES_PER_CM
? "dpc" : "unknown");
3562 if (attr
->values
[i
].resolution
.yres
<= 0)
3567 print_test_error("\"%s\": Bad resolution value %dx%d%s - feed "
3568 "resolution must be positive (RFC 2911 section "
3569 "4.1.13).", attr
->name
,
3570 attr
->values
[i
].resolution
.xres
,
3571 attr
->values
[i
].resolution
.yres
,
3572 attr
->values
[i
].resolution
.units
==
3573 IPP_RES_PER_INCH
? "dpi" :
3574 attr
->values
[i
].resolution
.units
==
3575 IPP_RES_PER_CM
? "dpc" : "unknown");
3580 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
3581 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
3586 print_test_error("\"%s\": Bad resolution value %dx%d%s - bad "
3587 "units value (RFC 2911 section 4.1.13).",
3588 attr
->name
, attr
->values
[i
].resolution
.xres
,
3589 attr
->values
[i
].resolution
.yres
,
3590 attr
->values
[i
].resolution
.units
==
3591 IPP_RES_PER_INCH
? "dpi" :
3592 attr
->values
[i
].resolution
.units
==
3593 IPP_RES_PER_CM
? "dpc" : "unknown");
3600 case IPP_TAG_RANGE
:
3601 for (i
= 0; i
< attr
->num_values
; i
++)
3603 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3608 print_test_error("\"%s\": Bad rangeOfInteger value %d-%d - lower "
3609 "greater than upper (RFC 2911 section 4.1.13).",
3610 attr
->name
, attr
->values
[i
].range
.lower
,
3611 attr
->values
[i
].range
.upper
);
3618 case IPP_TAG_BEGIN_COLLECTION
:
3619 for (i
= 0; i
< attr
->num_values
; i
++)
3621 for (colattr
= attr
->values
[i
].collection
->attrs
;
3623 colattr
= colattr
->next
)
3625 if (!validate_attr(colattr
, 0))
3632 if (colattr
&& print
)
3634 print_test_error("\"%s\": Bad collection value.", attr
->name
);
3638 validate_attr(colattr
, print
);
3639 colattr
= colattr
->next
;
3646 case IPP_TAG_TEXTLANG
:
3647 for (i
= 0; i
< attr
->num_values
; i
++)
3649 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3651 if ((*ptr
& 0xe0) == 0xc0)
3654 if ((*ptr
& 0xc0) != 0x80)
3657 else if ((*ptr
& 0xf0) == 0xe0)
3660 if ((*ptr
& 0xc0) != 0x80)
3663 if ((*ptr
& 0xc0) != 0x80)
3666 else if ((*ptr
& 0xf8) == 0xf0)
3669 if ((*ptr
& 0xc0) != 0x80)
3672 if ((*ptr
& 0xc0) != 0x80)
3675 if ((*ptr
& 0xc0) != 0x80)
3678 else if (*ptr
& 0x80)
3687 print_test_error("\"%s\": Bad text value \"%s\" - bad UTF-8 "
3688 "sequence (RFC 2911 section 4.1.1).", attr
->name
,
3689 attr
->values
[i
].string
.text
);
3694 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
3699 print_test_error("\"%s\": Bad text value \"%s\" - bad length %d "
3700 "(RFC 2911 section 4.1.1).", attr
->name
,
3701 attr
->values
[i
].string
.text
,
3702 (int)strlen(attr
->values
[i
].string
.text
));
3710 case IPP_TAG_NAMELANG
:
3711 for (i
= 0; i
< attr
->num_values
; i
++)
3713 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3715 if ((*ptr
& 0xe0) == 0xc0)
3718 if ((*ptr
& 0xc0) != 0x80)
3721 else if ((*ptr
& 0xf0) == 0xe0)
3724 if ((*ptr
& 0xc0) != 0x80)
3727 if ((*ptr
& 0xc0) != 0x80)
3730 else if ((*ptr
& 0xf8) == 0xf0)
3733 if ((*ptr
& 0xc0) != 0x80)
3736 if ((*ptr
& 0xc0) != 0x80)
3739 if ((*ptr
& 0xc0) != 0x80)
3742 else if (*ptr
& 0x80)
3751 print_test_error("\"%s\": Bad name value \"%s\" - bad UTF-8 "
3752 "sequence (RFC 2911 section 4.1.2).", attr
->name
,
3753 attr
->values
[i
].string
.text
);
3758 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
3763 print_test_error("\"%s\": Bad name value \"%s\" - bad length %d "
3764 "(RFC 2911 section 4.1.2).", attr
->name
,
3765 attr
->values
[i
].string
.text
,
3766 (int)strlen(attr
->values
[i
].string
.text
));
3773 case IPP_TAG_KEYWORD
:
3774 for (i
= 0; i
< attr
->num_values
; i
++)
3776 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3777 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
3781 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
3786 print_test_error("\"%s\": Bad keyword value \"%s\" - invalid "
3787 "character (RFC 2911 section 4.1.3).",
3788 attr
->name
, attr
->values
[i
].string
.text
);
3793 if ((ptr
- attr
->values
[i
].string
.text
) > 255)
3798 print_test_error("\"%s\": Bad keyword value \"%s\" - bad "
3799 "length %d (RFC 2911 section 4.1.3).",
3800 attr
->name
, attr
->values
[i
].string
.text
,
3801 (int)strlen(attr
->values
[i
].string
.text
));
3809 for (i
= 0; i
< attr
->num_values
; i
++)
3811 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
3812 attr
->values
[i
].string
.text
,
3813 scheme
, sizeof(scheme
),
3814 userpass
, sizeof(userpass
),
3815 hostname
, sizeof(hostname
),
3816 &port
, resource
, sizeof(resource
));
3818 if (uri_status
< HTTP_URI_OK
)
3823 print_test_error("\"%s\": Bad URI value \"%s\" - %s "
3824 "(RFC 2911 section 4.1.5).", attr
->name
,
3825 attr
->values
[i
].string
.text
,
3826 URIStatusStrings
[uri_status
-
3827 HTTP_URI_OVERFLOW
]);
3832 if (strlen(attr
->values
[i
].string
.text
) > 1023)
3837 print_test_error("\"%s\": Bad URI value \"%s\" - bad length %d "
3838 "(RFC 2911 section 4.1.5).", attr
->name
,
3839 attr
->values
[i
].string
.text
,
3840 (int)strlen(attr
->values
[i
].string
.text
));
3847 case IPP_TAG_URISCHEME
:
3848 for (i
= 0; i
< attr
->num_values
; i
++)
3850 ptr
= attr
->values
[i
].string
.text
;
3851 if (islower(*ptr
& 255))
3853 for (ptr
++; *ptr
; ptr
++)
3854 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
3855 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
3859 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
3864 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
3865 "characters (RFC 2911 section 4.1.6).",
3866 attr
->name
, attr
->values
[i
].string
.text
);
3871 if ((ptr
- attr
->values
[i
].string
.text
) > 63)
3876 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
3877 "length %d (RFC 2911 section 4.1.6).",
3878 attr
->name
, attr
->values
[i
].string
.text
,
3879 (int)strlen(attr
->values
[i
].string
.text
));
3886 case IPP_TAG_CHARSET
:
3887 for (i
= 0; i
< attr
->num_values
; i
++)
3889 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3890 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
3891 isspace(*ptr
& 255))
3894 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
3899 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
3900 "characters (RFC 2911 section 4.1.7).",
3901 attr
->name
, attr
->values
[i
].string
.text
);
3906 if ((ptr
- attr
->values
[i
].string
.text
) > 40)
3911 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
3912 "length %d (RFC 2911 section 4.1.7).",
3913 attr
->name
, attr
->values
[i
].string
.text
,
3914 (int)strlen(attr
->values
[i
].string
.text
));
3921 case IPP_TAG_LANGUAGE
:
3923 * The following regular expression is derived from the ABNF for
3924 * language tags in RFC 4646. All I can say is that this is the
3925 * easiest way to check the values...
3928 if ((i
= regcomp(&re
,
3930 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
3932 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
3933 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
3934 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
3935 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
3936 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
3938 "x(-[a-z0-9]{1,8})+" /* privateuse */
3940 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
3942 REG_NOSUB
| REG_EXTENDED
)) != 0)
3944 char temp
[256]; /* Temporary error string */
3946 regerror(i
, &re
, temp
, sizeof(temp
));
3947 print_fatal_error("Unable to compile naturalLanguage regular "
3948 "expression: %s.", temp
);
3951 for (i
= 0; i
< attr
->num_values
; i
++)
3953 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
3958 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
3959 "characters (RFC 2911 section 4.1.8).",
3960 attr
->name
, attr
->values
[i
].string
.text
);
3965 if (strlen(attr
->values
[i
].string
.text
) > 63)
3970 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
3971 "length %d (RFC 2911 section 4.1.8).",
3972 attr
->name
, attr
->values
[i
].string
.text
,
3973 (int)strlen(attr
->values
[i
].string
.text
));
3982 case IPP_TAG_MIMETYPE
:
3984 * The following regular expression is derived from the ABNF for
3985 * language tags in RFC 2045 and 4288. All I can say is that this is
3986 * the easiest way to check the values...
3989 if ((i
= regcomp(&re
,
3991 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
3993 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
3994 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
3995 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
3998 REG_NOSUB
| REG_EXTENDED
)) != 0)
4000 char temp
[256]; /* Temporary error string */
4002 regerror(i
, &re
, temp
, sizeof(temp
));
4003 print_fatal_error("Unable to compile mimeMediaType regular "
4004 "expression: %s.", temp
);
4007 for (i
= 0; i
< attr
->num_values
; i
++)
4009 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4014 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
4015 "characters (RFC 2911 section 4.1.9).",
4016 attr
->name
, attr
->values
[i
].string
.text
);
4021 if (strlen(attr
->values
[i
].string
.text
) > 255)
4026 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
4027 "length %d (RFC 2911 section 4.1.9).",
4028 attr
->name
, attr
->values
[i
].string
.text
,
4029 (int)strlen(attr
->values
[i
].string
.text
));
4045 * 'with_value()' - Test a WITH-VALUE predicate.
4048 static int /* O - 1 on match, 0 on non-match */
4049 with_value(char *value
, /* I - Value string */
4050 int regex
, /* I - Value is a regular expression */
4051 ipp_attribute_t
*attr
) /* I - Attribute to compare */
4053 int i
; /* Looping var */
4054 char *valptr
; /* Pointer into value */
4058 * NULL matches everything.
4061 if (!value
|| !*value
)
4065 * Compare the value string to the attribute value.
4068 switch (attr
->value_tag
)
4070 case IPP_TAG_INTEGER
:
4072 for (i
= 0; i
< attr
->num_values
; i
++)
4074 char op
, /* Comparison operator */
4075 *nextptr
; /* Next pointer */
4076 int intvalue
; /* Integer value */
4080 if (!strncmp(valptr
, "no-value,", 9))
4083 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
4084 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
4085 *valptr
== '=' || *valptr
== '>')
4088 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
4090 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
4098 intvalue
= strtol(valptr
, &nextptr
, 0);
4099 if (nextptr
== valptr
)
4106 if (attr
->values
[i
].integer
== intvalue
)
4110 if (attr
->values
[i
].integer
< intvalue
)
4114 if (attr
->values
[i
].integer
> intvalue
)
4122 case IPP_TAG_BOOLEAN
:
4123 for (i
= 0; i
< attr
->num_values
; i
++)
4125 if (!strcmp(value
, "true") == attr
->values
[i
].boolean
)
4130 case IPP_TAG_NOVALUE
:
4131 return (!strcmp(value
, "no-value") || !strncmp(value
, "no-value,", 9));
4133 case IPP_TAG_CHARSET
:
4134 case IPP_TAG_KEYWORD
:
4135 case IPP_TAG_LANGUAGE
:
4136 case IPP_TAG_MIMETYPE
:
4138 case IPP_TAG_NAMELANG
:
4140 case IPP_TAG_TEXTLANG
:
4142 case IPP_TAG_URISCHEME
:
4146 * Value is an extended, case-sensitive POSIX regular expression...
4149 regex_t re
; /* Regular expression */
4151 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
4153 char temp
[256]; /* Temporary string */
4155 regerror(i
, &re
, temp
, sizeof(temp
));
4157 print_fatal_error("Unable to compile WITH-VALUE regular expression "
4158 "\"%s\" - %s", value
, temp
);
4163 * See if ALL of the values match the given regular expression.
4166 for (i
= 0; i
< attr
->num_values
; i
++)
4168 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
4174 return (i
== attr
->num_values
);
4179 * Value is a literal string, see if at least one value matches the
4183 for (i
= 0; i
< attr
->num_values
; i
++)
4185 if (!strcmp(value
, attr
->values
[i
].string
.text
))