2 * "$Id: ipptest.c 9000 2010-02-24 06:29:38Z mike $"
4 * IPP test 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_fatal_error() - Print a fatal error message.
31 * print_test_error() - Print a test error message.
32 * print_xml_header() - Print a standard XML plist header.
33 * print_xml_string() - Print an XML string with escaping.
34 * print_xml_trailer() - Print the XML trailer with success/fail value.
35 * set_variable() - Set a variable value.
36 * usage() - Show program usage.
37 * validate_attr() - Determine whether an attribute is valid.
38 * with_value() - Test a WITH-VALUE predicate.
42 * Include necessary headers...
45 #include <cups/cups-private.h>
46 #include <cups/file-private.h>
51 #endif /* !O_BINARY */
58 typedef enum /**** How to send request data ****/
60 _CUPS_TRANSFER_AUTO
, /* Chunk for files, length for static */
61 _CUPS_TRANSFER_CHUNKED
, /* Chunk always */
62 _CUPS_TRANSFER_LENGTH
/* Length always */
65 typedef struct _cups_expect_s
/**** Expected attribute info ****/
67 int optional
, /* Optional attribute? */
68 not_expect
; /* Don't expect attribute? */
69 char *name
, /* Attribute name */
70 *of_type
, /* Type name */
71 *same_count_as
, /* Parallel attribute name */
72 *if_defined
, /* Only required if variable defined */
73 *if_undefined
, /* Only required if variable is not defined */
74 *with_value
; /* Attribute must include this value */
75 int with_regex
, /* WITH-VALUE is a regular expression */
76 count
; /* Expected count if > 0 */
77 ipp_tag_t in_group
; /* IN-GROUP value */
80 typedef struct _cups_status_s
/**** Status info ****/
82 ipp_status_t status
; /* Expected status code */
83 char *if_defined
, /* Only if variable is defined */
84 *if_undefined
; /* Only if variable is not defined */
87 typedef struct _cups_var_s
/**** Variable ****/
89 char *name
, /* Name of variable */
90 *value
; /* Value of variable */
93 typedef struct _cups_vars_s
/**** Set of variables ****/
95 const char *uri
, /* URI for printer */
96 *filename
; /* Filename */
97 char scheme
[64], /* Scheme from URI */
98 userpass
[256], /* Username/password from URI */
99 hostname
[256], /* Hostname from URI */
100 resource
[1024]; /* Resource path from URI */
101 int port
; /* Port number from URI */
102 http_encryption_t encryption
; /* Encryption for connection? */
103 cups_array_t
*vars
; /* Array of variables */
111 _cups_transfer_t Transfer
= _CUPS_TRANSFER_AUTO
;
112 /* How to transfer requests */
113 int Verbosity
= 0, /* Show all attributes? */
114 Version
= 11, /* Default IPP version */
115 XML
= 0, /* Produce XML output? */
116 XMLHeader
= 0; /* 1 if header is written */
117 const char * const URIStatusStrings
[] = /* URI status strings */
120 "Bad arguments to function",
121 "Bad resource in URI",
122 "Bad port number in URI",
123 "Bad hostname/address in URI",
124 "Bad username in URI",
128 "Missing scheme in URI",
129 "Unknown scheme in URI",
130 "Missing resource in URI"
138 static int compare_vars(_cups_var_t
*a
, _cups_var_t
*b
);
139 static int do_tests(_cups_vars_t
*vars
, const char *testfile
);
140 static void expand_variables(_cups_vars_t
*vars
, char *dst
, const char *src
,
143 __attribute((nonnull(1,2,3)))
144 #endif /* __GNUC__ */
146 static int expect_matches(_cups_expect_t
*expect
, ipp_tag_t value_tag
);
147 static ipp_t
*get_collection(_cups_vars_t
*vars
, FILE *fp
, int *linenum
);
148 static char *get_filename(const char *testfile
, char *dst
, const char *src
,
150 static char *get_token(FILE *fp
, char *buf
, int buflen
,
152 static char *get_variable(_cups_vars_t
*vars
, const char *name
);
153 static char *iso_date(ipp_uchar_t
*date
);
154 static void print_attr(ipp_attribute_t
*attr
);
155 static void print_col(ipp_t
*col
);
156 static void print_fatal_error(const char *s
, ...)
158 __attribute__ ((__format__ (__printf__
, 1, 2)))
159 #endif /* __GNUC__ */
161 static void print_test_error(const char *s
, ...)
163 __attribute__ ((__format__ (__printf__
, 1, 2)))
164 #endif /* __GNUC__ */
166 static void print_xml_header(void);
167 static void print_xml_string(const char *element
, const char *s
);
168 static void print_xml_trailer(int success
, const char *message
);
169 static void set_variable(_cups_vars_t
*vars
, const char *name
,
171 static void usage(void);
172 static int validate_attr(ipp_attribute_t
*attr
, int print
);
173 static int with_value(char *value
, int regex
, ipp_attribute_t
*attr
);
177 * 'main()' - Parse options and do tests.
180 int /* O - Exit status */
181 main(int argc
, /* I - Number of command-line args */
182 char *argv
[]) /* I - Command-line arguments */
184 int i
; /* Looping var */
185 int status
; /* Status of tests... */
186 char *opt
, /* Current option */
187 name
[1024], /* Name/value buffer */
188 *value
; /* Pointer to value */
189 const char *testfile
; /* Test file to use */
190 int interval
; /* Test interval */
191 _cups_vars_t vars
; /* Variables */
192 http_uri_status_t uri_status
; /* URI separation status */
196 * Initialize the locale and variables...
199 _cupsSetLocale(argv
);
201 memset(&vars
, 0, sizeof(vars
));
202 vars
.vars
= cupsArrayNew((cups_array_func_t
)compare_vars
, NULL
);
207 * ipptest URI testfile
214 for (i
= 1; i
< argc
; i
++)
216 if (argv
[i
][0] == '-')
218 for (opt
= argv
[i
] + 1; *opt
; opt
++)
222 case 'E' : /* Encrypt */
224 vars
.encryption
= HTTP_ENCRYPT_REQUIRED
;
226 _cupsLangPrintf(stderr
,
227 _("%s: Sorry, no encryption support compiled in\n"),
229 #endif /* HAVE_SSL */
232 case 'V' : /* Set IPP version */
237 _cupsLangPuts(stderr
,
238 _("ipptest: Missing version for \"-V\".\n"));
242 if (!strcmp(argv
[i
], "1.0"))
244 else if (!strcmp(argv
[i
], "1.1"))
246 else if (!strcmp(argv
[i
], "2.0"))
248 else if (!strcmp(argv
[i
], "2.1"))
250 else if (!strcmp(argv
[i
], "2.2"))
254 _cupsLangPrintf(stderr
,
255 _("ipptest: Bad version %s for \"-V\".\n"),
261 case 'X' : /* Produce XML output */
266 _cupsLangPuts(stderr
, _("ipptest: \"-i\" is incompatible with "
272 case 'c' : /* Enable HTTP chunking */
273 Transfer
= _CUPS_TRANSFER_CHUNKED
;
276 case 'd' : /* Define a variable */
281 _cupsLangPuts(stderr
,
282 _("ipptest: Missing name=value for \"-d\".\n"));
286 strlcpy(name
, argv
[i
], sizeof(name
));
287 if ((value
= strchr(name
, '=')) != NULL
)
290 value
= name
+ strlen(name
);
292 set_variable(&vars
, name
, value
);
295 case 'f' : /* Set the default test filename */
300 _cupsLangPuts(stderr
,
301 _("ipptest: Missing filename for \"-f\".\n"));
305 vars
.filename
= argv
[i
];
308 case 'i' : /* Test every N seconds */
313 _cupsLangPuts(stderr
,
314 _("ipptest: Missing seconds for \"-i\".\n"));
318 interval
= atoi(argv
[i
]);
322 _cupsLangPuts(stderr
, _("ipptest: \"-i\" is incompatible with "
328 case 'l' : /* Disable HTTP chunking */
329 Transfer
= _CUPS_TRANSFER_LENGTH
;
332 case 'v' : /* Be verbose */
337 _cupsLangPrintf(stderr
, _("ipptest: Unknown option \"-%c\".\n"),
344 else if (!strncmp(argv
[i
], "ipp://", 6) ||
345 !strncmp(argv
[i
], "http://", 7) ||
346 !strncmp(argv
[i
], "https://", 8))
354 _cupsLangPuts(stderr
, _("ipptest: May only specify a single URI.\n"));
359 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
, vars
.uri
,
360 vars
.scheme
, sizeof(vars
.scheme
),
361 vars
.userpass
, sizeof(vars
.userpass
),
362 vars
.hostname
, sizeof(vars
.hostname
),
364 vars
.resource
, sizeof(vars
.resource
));
366 if (uri_status
!= HTTP_URI_OK
)
368 _cupsLangPrintf(stderr
, _("ipptest: Bad URI - %s.\n"),
369 URIStatusStrings
[uri_status
- HTTP_URI_OVERFLOW
]);
373 if (strcmp(vars
.scheme
, "http") && strcmp(vars
.scheme
, "https") &&
374 strcmp(vars
.scheme
, "ipp"))
376 _cupsLangPuts(stderr
, _("ipptest: Only http, https, and ipp URIs are "
389 _cupsLangPuts(stderr
, _("ipptest: URI required before test file."));
395 if (!do_tests(&vars
, testfile
))
400 if (!vars
.uri
|| !testfile
)
404 * Loop if the interval is set...
408 print_xml_trailer(!status
, NULL
);
414 do_tests(&vars
, testfile
);
427 * 'compare_vars()' - Compare two variables.
430 static int /* O - Result of comparison */
431 compare_vars(_cups_var_t
*a
, /* I - First variable */
432 _cups_var_t
*b
) /* I - Second variable */
434 return (strcasecmp(a
->name
, b
->name
));
439 * 'do_tests()' - Do tests as specified in the test file.
442 static int /* 1 = success, 0 = failure */
443 do_tests(_cups_vars_t
*vars
, /* I - Variables */
444 const char *testfile
) /* I - Test file to use */
446 int i
, /* Looping var */
447 linenum
, /* Current line number */
448 pass
, /* Did we pass the test? */
449 request_id
; /* Current request ID */
450 http_t
*http
= NULL
; /* HTTP connection to server */
451 FILE *fp
= NULL
; /* Test file */
452 char resource
[512], /* Resource for request */
453 token
[1024], /* Token from file */
454 *tokenptr
, /* Pointer into token */
455 temp
[1024]; /* Temporary string */
456 ipp_t
*request
= NULL
; /* IPP request */
457 ipp_t
*response
= NULL
; /* IPP response */
458 char attr
[128]; /* Attribute name */
459 ipp_op_t op
; /* Operation */
460 ipp_tag_t group
; /* Current group */
461 ipp_tag_t value
; /* Current value type */
462 ipp_attribute_t
*attrptr
, /* Attribute pointer */
463 *found
, /* Found attribute */
464 *lastcol
= NULL
; /* Last collection attribute */
465 char name
[1024]; /* Name of test */
466 char filename
[1024]; /* Filename */
467 _cups_transfer_t transfer
; /* To chunk or not to chunk */
468 int version
; /* IPP version number to use */
469 int num_statuses
= 0; /* Number of valid status codes */
470 _cups_status_t statuses
[100], /* Valid status codes */
471 *last_status
; /* Last STATUS (for predicates) */
472 int num_expects
= 0; /* Number of expected attributes */
473 _cups_expect_t expects
[200], /* Expected attributes */
474 *expect
, /* Current expected attribute */
475 *last_expect
; /* Last EXPECT (for predicates) */
476 int num_displayed
= 0; /* Number of displayed attributes */
477 char *displayed
[100]; /* Displayed attributes */
481 * Open the test file...
484 if ((fp
= fopen(testfile
, "r")) == NULL
)
486 print_fatal_error("Unable to open test file %s - %s", testfile
,
492 * Connect to the server...
495 if ((http
= httpConnectEncrypt(vars
->hostname
, vars
->port
,
496 vars
->encryption
)) == NULL
)
498 print_fatal_error("Unable to connect to %s on port %d - %s", vars
->hostname
,
499 vars
->port
, strerror(errno
));
510 printf("\"%s\":\n", testfile
);
512 CUPS_SRAND(time(NULL
));
516 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
518 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
521 * Expect an open brace...
524 if (!strcmp(token
, "DEFINE"))
530 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
531 get_token(fp
, temp
, sizeof(temp
), &linenum
))
533 expand_variables(vars
, token
, temp
, sizeof(token
));
534 set_variable(vars
, attr
, token
);
538 print_fatal_error("Missing DEFINE name and/or value on line %d.",
545 else if (!strcmp(token
, "INCLUDE"))
552 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
555 * Map the filename to and then run the tests...
558 if (!do_tests(vars
, get_filename(testfile
, filename
, temp
,
564 print_fatal_error("Missing INCLUDE filename on line %d.", linenum
);
570 else if (!strcmp(token
, "TRANSFER"))
578 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
580 if (!strcmp(temp
, "auto"))
581 Transfer
= _CUPS_TRANSFER_AUTO
;
582 else if (!strcmp(temp
, "chunked"))
583 Transfer
= _CUPS_TRANSFER_CHUNKED
;
584 else if (!strcmp(temp
, "length"))
585 Transfer
= _CUPS_TRANSFER_LENGTH
;
588 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
595 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
601 else if (!strcmp(token
, "VERSION"))
603 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
605 if (!strcmp(temp
, "1.0"))
607 else if (!strcmp(temp
, "1.1"))
609 else if (!strcmp(temp
, "2.0"))
611 else if (!strcmp(temp
, "2.1"))
613 else if (!strcmp(temp
, "2.2"))
617 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
623 print_fatal_error("Missing VERSION number on line %d.", linenum
);
629 else if (strcmp(token
, "{"))
631 print_fatal_error("Unexpected token %s seen on line %d.", token
, linenum
);
636 * Initialize things...
639 strlcpy(resource
, vars
->resource
, sizeof(resource
));
644 group
= IPP_TAG_ZERO
;
651 strlcpy(name
, testfile
, sizeof(name
));
652 if (strrchr(name
, '.') != NULL
)
653 *strrchr(name
, '.') = '\0';
656 * Parse until we see a close brace...
659 while (get_token(fp
, token
, sizeof(token
), &linenum
) != NULL
)
661 if (strcasecmp(token
, "COUNT") &&
662 strcasecmp(token
, "IF-DEFINED") &&
663 strcasecmp(token
, "IF-UNDEFINED") &&
664 strcasecmp(token
, "IN-GROUP") &&
665 strcasecmp(token
, "OF-TYPE") &&
666 strcasecmp(token
, "SAME-COUNT-AS") &&
667 strcasecmp(token
, "WITH-VALUE"))
670 if (strcasecmp(token
, "IF-DEFINED") &&
671 strcasecmp(token
, "IF-UNDEFINED"))
674 if (!strcmp(token
, "}"))
676 else if (!strcmp(token
, "{") && lastcol
)
679 * Another collection value
682 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
683 /* Collection value */
687 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
691 * Reallocate memory...
694 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
695 (lastcol
->num_values
+ 1) *
696 sizeof(ipp_value_t
))) == NULL
)
698 print_fatal_error("Unable to allocate memory on line %d.", linenum
);
702 if (tempcol
!= lastcol
)
705 * Reset pointers in the list...
709 request
->prev
->next
= tempcol
;
711 request
->attrs
= tempcol
;
713 lastcol
= request
->current
= request
->last
= tempcol
;
716 lastcol
->values
[lastcol
->num_values
].collection
= col
;
717 lastcol
->num_values
++;
722 else if (!strcmp(token
, "DEFINE"))
728 if (get_token(fp
, attr
, sizeof(attr
), &linenum
) &&
729 get_token(fp
, temp
, sizeof(temp
), &linenum
))
731 expand_variables(vars
, token
, temp
, sizeof(token
));
732 set_variable(vars
, attr
, token
);
736 print_fatal_error("Missing DEFINE name and/or value on line %d.",
741 else if (!strcasecmp(token
, "NAME"))
747 get_token(fp
, name
, sizeof(name
), &linenum
);
749 else if (!strcmp(token
, "REQUEST-ID"))
756 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
758 if (isdigit(temp
[0] & 255))
759 request_id
= atoi(temp
);
760 else if (!strcasecmp(temp
, "random"))
761 request_id
= (CUPS_RAND() % 1000) * 137 + 1;
764 print_fatal_error("Bad REQUEST-ID value \"%s\" on line %d.", temp
,
771 print_fatal_error("Missing REQUEST-ID value on line %d.", linenum
);
775 else if (!strcmp(token
, "TRANSFER"))
783 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
785 if (!strcmp(temp
, "auto"))
786 transfer
= _CUPS_TRANSFER_AUTO
;
787 else if (!strcmp(temp
, "chunked"))
788 transfer
= _CUPS_TRANSFER_CHUNKED
;
789 else if (!strcmp(temp
, "length"))
790 transfer
= _CUPS_TRANSFER_LENGTH
;
793 print_fatal_error("Bad TRANSFER value \"%s\" on line %d.", temp
,
800 print_fatal_error("Missing TRANSFER value on line %d.", linenum
);
804 else if (!strcasecmp(token
, "VERSION"))
806 if (get_token(fp
, temp
, sizeof(temp
), &linenum
))
808 if (!strcmp(temp
, "0.0"))
810 else if (!strcmp(temp
, "1.0"))
812 else if (!strcmp(temp
, "1.1"))
814 else if (!strcmp(temp
, "2.0"))
816 else if (!strcmp(temp
, "2.1"))
818 else if (!strcmp(temp
, "2.2"))
822 print_fatal_error("Bad VERSION \"%s\" on line %d.", temp
, linenum
);
828 print_fatal_error("Missing VERSION number on line %d.", linenum
);
832 else if (!strcasecmp(token
, "RESOURCE"))
838 if (!get_token(fp
, resource
, sizeof(resource
), &linenum
))
840 print_fatal_error("Missing RESOURCE path on line %d.", linenum
);
844 else if (!strcasecmp(token
, "OPERATION"))
850 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
852 print_fatal_error("Missing OPERATION code on line %d.", linenum
);
856 if ((op
= ippOpValue(token
)) < 0)
858 print_fatal_error("Bad OPERATION code \"%s\" on line %d.", token
,
863 else if (!strcasecmp(token
, "GROUP"))
869 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
871 print_fatal_error("Missing GROUP tag on line %d.", linenum
);
875 if ((value
= ippTagValue(token
)) < 0)
877 print_fatal_error("Bad GROUP tag \"%s\" on line %d.", token
, linenum
);
882 ippAddSeparator(request
);
886 else if (!strcasecmp(token
, "DELAY"))
889 * Delay before operation...
894 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
896 print_fatal_error("Missing DELAY value on line %d.", linenum
);
900 if ((delay
= atoi(token
)) <= 0)
902 print_fatal_error("Bad DELAY value \"%s\" on line %d.", token
,
909 else if (!strcasecmp(token
, "ATTR"))
915 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
917 print_fatal_error("Missing ATTR value tag on line %d.", linenum
);
921 if ((value
= ippTagValue(token
)) == IPP_TAG_ZERO
)
923 print_fatal_error("Bad ATTR value tag \"%s\" on line %d.", token
,
928 if (!get_token(fp
, attr
, sizeof(attr
), &linenum
))
930 print_fatal_error("Missing ATTR name on line %d.", linenum
);
934 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
936 print_fatal_error("Missing ATTR value on line %d.", linenum
);
940 expand_variables(vars
, token
, temp
, sizeof(token
));
944 case IPP_TAG_BOOLEAN
:
945 if (!strcasecmp(token
, "true"))
946 ippAddBoolean(request
, group
, attr
, 1);
948 ippAddBoolean(request
, group
, attr
, atoi(token
));
951 case IPP_TAG_INTEGER
:
953 ippAddInteger(request
, group
, value
, attr
, atoi(token
));
956 case IPP_TAG_RESOLUTION
:
958 int xres
, /* X resolution */
959 yres
; /* Y resolution */
960 char units
[6]; /* Units */
962 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
963 (strcasecmp(units
, "dpi") && strcasecmp(units
, "dpc") &&
964 strcasecmp(units
, "other")))
966 print_fatal_error("Bad resolution value \"%s\" on line %d.",
971 if (!strcasecmp(units
, "dpi"))
972 ippAddResolution(request
, group
, attr
, xres
, yres
,
974 else if (!strcasecmp(units
, "dpc"))
975 ippAddResolution(request
, group
, attr
, xres
, yres
,
978 ippAddResolution(request
, group
, attr
, xres
, yres
,
985 int lowers
[4], /* Lower value */
986 uppers
[4], /* Upper values */
987 num_vals
; /* Number of values */
990 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
991 lowers
+ 0, uppers
+ 0,
992 lowers
+ 1, uppers
+ 1,
993 lowers
+ 2, uppers
+ 2,
994 lowers
+ 3, uppers
+ 3);
996 if ((num_vals
& 1) || num_vals
== 0)
998 print_fatal_error("Bad rangeOfInteger value \"%s\" on line "
999 "%d.", token
, linenum
);
1003 ippAddRanges(request
, group
, attr
, num_vals
/ 2, lowers
,
1008 case IPP_TAG_BEGIN_COLLECTION
:
1009 if (!strcmp(token
, "{"))
1011 ipp_t
*col
= get_collection(vars
, fp
, &linenum
);
1012 /* Collection value */
1015 lastcol
= ippAddCollection(request
, group
, attr
, col
);
1021 print_fatal_error("Bad ATTR collection value on line %d.",
1028 print_fatal_error("Unsupported ATTR value tag %s on line %d.",
1029 ippTagString(value
), linenum
);
1032 case IPP_TAG_TEXTLANG
:
1033 case IPP_TAG_NAMELANG
:
1036 case IPP_TAG_KEYWORD
:
1038 case IPP_TAG_URISCHEME
:
1039 case IPP_TAG_CHARSET
:
1040 case IPP_TAG_LANGUAGE
:
1041 case IPP_TAG_MIMETYPE
:
1042 if (!strchr(token
, ','))
1043 ippAddString(request
, group
, value
, attr
, NULL
, token
);
1047 * Multiple string values...
1050 int num_values
; /* Number of values */
1051 char *values
[100], /* Values */
1052 *ptr
; /* Pointer to next value */
1058 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
1061 values
[num_values
] = ptr
;
1065 ippAddStrings(request
, group
, value
, attr
, num_values
,
1066 NULL
, (const char **)values
);
1071 else if (!strcasecmp(token
, "FILE"))
1077 if (!get_token(fp
, temp
, sizeof(temp
), &linenum
))
1079 print_fatal_error("Missing FILE filename on line %d.", linenum
);
1083 expand_variables(vars
, token
, temp
, sizeof(token
));
1084 get_filename(testfile
, filename
, token
, sizeof(filename
));
1086 else if (!strcasecmp(token
, "STATUS"))
1092 if (num_statuses
>= (int)(sizeof(statuses
) / sizeof(statuses
[0])))
1094 print_fatal_error("Too many STATUS's on line %d.", linenum
);
1098 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1100 print_fatal_error("Missing STATUS code on line %d.", linenum
);
1104 if ((statuses
[num_statuses
].status
= ippErrorValue(token
)) < 0)
1106 print_fatal_error("Bad STATUS code \"%s\" on line %d.", token
,
1111 last_status
= statuses
+ num_statuses
;
1114 last_status
->if_defined
= NULL
;
1115 last_status
->if_undefined
= NULL
;
1117 else if (!strcasecmp(token
, "EXPECT"))
1120 * Expected attributes...
1123 if (num_expects
>= (int)(sizeof(expects
) / sizeof(expects
[0])))
1125 print_fatal_error("Too many EXPECT's on line %d.", linenum
);
1129 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1131 print_fatal_error("Missing EXPECT name on line %d.", linenum
);
1135 last_expect
= expects
+ num_expects
;
1138 memset(last_expect
, 0, sizeof(_cups_expect_t
));
1140 if (token
[0] == '!')
1142 last_expect
->not_expect
= 1;
1143 last_expect
->name
= strdup(token
+ 1);
1145 else if (token
[0] == '?')
1147 last_expect
->optional
= 1;
1148 last_expect
->name
= strdup(token
+ 1);
1151 last_expect
->name
= strdup(token
);
1153 else if (!strcasecmp(token
, "COUNT"))
1155 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1157 print_fatal_error("Missing COUNT number on line %d.", linenum
);
1161 if ((i
= atoi(token
)) <= 0)
1163 print_fatal_error("Bad COUNT \"%s\" on line %d.", token
, linenum
);
1168 last_expect
->count
= i
;
1171 print_fatal_error("COUNT without a preceding EXPECT on line %d.",
1176 else if (!strcasecmp(token
, "OF-TYPE"))
1178 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1180 print_fatal_error("Missing OF-TYPE value tag(s) on line %d.",
1186 last_expect
->of_type
= strdup(token
);
1189 print_fatal_error("OF-TYPE without a preceding EXPECT on line %d.",
1194 else if (!strcasecmp(token
, "IN-GROUP"))
1196 ipp_tag_t in_group
; /* IN-GROUP value */
1199 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1201 print_fatal_error("Missing IN-GROUP group tag on line %d.", linenum
);
1205 if ((in_group
= ippTagValue(token
)) == (ipp_tag_t
)-1)
1208 else if (last_expect
)
1209 last_expect
->in_group
= in_group
;
1212 print_fatal_error("IN-GROUP without a preceding EXPECT on line %d.",
1217 else if (!strcasecmp(token
, "SAME-COUNT-AS"))
1219 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1221 print_fatal_error("Missing SAME-COUNT-AS name on line %d.", linenum
);
1226 last_expect
->same_count_as
= strdup(token
);
1229 print_fatal_error("SAME-COUNT-AS without a preceding EXPECT on line "
1234 else if (!strcasecmp(token
, "IF-DEFINED"))
1236 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1238 print_fatal_error("Missing IF-DEFINED name on line %d.", linenum
);
1243 last_expect
->if_defined
= strdup(token
);
1244 else if (last_status
)
1245 last_status
->if_defined
= strdup(token
);
1248 print_fatal_error("IF-DEFINED without a preceding EXPECT or STATUS "
1249 "on line %d.", linenum
);
1253 else if (!strcasecmp(token
, "IF-UNDEFINED"))
1255 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1257 print_fatal_error("Missing IF-UNDEFINED name on line %d.", linenum
);
1262 last_expect
->if_undefined
= strdup(token
);
1263 else if (last_status
)
1264 last_status
->if_undefined
= strdup(token
);
1267 print_fatal_error("IF-UNDEFINED without a preceding EXPECT or STATUS "
1268 "on line %d.", linenum
);
1272 else if (!strcasecmp(token
, "WITH-VALUE"))
1274 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1276 print_fatal_error("Missing WITH-VALUE value on line %d.", linenum
);
1282 tokenptr
= token
+ strlen(token
) - 1;
1283 if (token
[0] == '/' && tokenptr
> token
&& *tokenptr
== '/')
1286 * WITH-VALUE is a POSIX extended regular expression.
1289 last_expect
->with_value
= calloc(1, tokenptr
- token
);
1290 last_expect
->with_regex
= 1;
1292 if (last_expect
->with_value
)
1293 memcpy(last_expect
->with_value
, token
+ 1, tokenptr
- token
- 1);
1298 * WITH-VALUE is a literal value...
1301 last_expect
->with_value
= strdup(token
);
1306 print_fatal_error("WITH-VALUE without a preceding EXPECT on line %d.",
1311 else if (!strcasecmp(token
, "DISPLAY"))
1314 * Display attributes...
1317 if (num_displayed
>= (int)(sizeof(displayed
) / sizeof(displayed
[0])))
1319 print_fatal_error("Too many DISPLAY's on line %d", linenum
);
1323 if (!get_token(fp
, token
, sizeof(token
), &linenum
))
1325 print_fatal_error("Missing DISPLAY name on line %d.", linenum
);
1329 displayed
[num_displayed
] = strdup(token
);
1334 print_fatal_error("Unexpected token %s seen on line %d.", token
,
1341 * Submit the IPP request...
1344 request
->request
.op
.version
[0] = version
/ 10;
1345 request
->request
.op
.version
[1] = version
% 10;
1346 request
->request
.op
.operation_id
= op
;
1347 request
->request
.op
.request_id
= request_id
;
1352 puts("<key>Name</key>");
1353 print_xml_string("string", name
);
1354 puts("<key>Operation</key>");
1355 print_xml_string("string", ippOpString(op
));
1356 puts("<key>RequestAttributes</key>");
1358 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
1359 print_attr(attrptr
);
1366 printf(" %s:\n", ippOpString(op
));
1368 for (attrptr
= request
->attrs
; attrptr
; attrptr
= attrptr
->next
)
1369 print_attr(attrptr
);
1372 printf(" %-69.69s [", name
);
1376 if (transfer
== _CUPS_TRANSFER_CHUNKED
||
1377 (transfer
== _CUPS_TRANSFER_AUTO
&& filename
[0]))
1380 * Send request using chunking...
1383 http_status_t status
= cupsSendRequest(http
, request
, resource
, 0);
1385 if (status
== HTTP_CONTINUE
&& filename
[0])
1387 int fd
; /* File to send */
1388 char buffer
[8192]; /* Copy buffer */
1389 ssize_t bytes
; /* Bytes read/written */
1391 if ((fd
= open(filename
, O_RDONLY
| O_BINARY
)) >= 0)
1393 while ((bytes
= read(fd
, buffer
, sizeof(buffer
))) > 0)
1394 if ((status
= cupsWriteRequestData(http
, buffer
,
1395 bytes
)) != HTTP_CONTINUE
)
1400 snprintf(buffer
, sizeof(buffer
), "%s: %s", filename
, strerror(errno
));
1401 _cupsSetError(IPP_INTERNAL_ERROR
, buffer
, 0);
1403 status
= HTTP_ERROR
;
1409 if (status
== HTTP_CONTINUE
)
1410 response
= cupsGetResponse(http
, resource
);
1414 else if (filename
[0])
1415 response
= cupsDoFileRequest(http
, request
, resource
, filename
);
1417 response
= cupsDoRequest(http
, request
, resource
);
1425 if (http
->version
!= HTTP_1_1
)
1428 if (response
->request
.status
.version
[0] != (version
/ 10) ||
1429 response
->request
.status
.version
[1] != (version
% 10) ||
1430 response
->request
.status
.request_id
!= request_id
)
1433 if ((attrptr
= ippFindAttribute(response
, "job-id",
1434 IPP_TAG_INTEGER
)) != NULL
)
1436 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
1437 set_variable(vars
, "job-id", temp
);
1440 if ((attrptr
= ippFindAttribute(response
, "job-uri",
1441 IPP_TAG_URI
)) != NULL
)
1442 set_variable(vars
, "job-uri", attrptr
->values
[0].string
.text
);
1444 if ((attrptr
= ippFindAttribute(response
, "notify-subscription-id",
1445 IPP_TAG_INTEGER
)) != NULL
)
1447 snprintf(temp
, sizeof(temp
), "%d", attrptr
->values
[0].integer
);
1448 set_variable(vars
, "notify-subscription-id", temp
);
1451 attrptr
= response
->attrs
;
1452 if (!attrptr
|| !attrptr
->name
||
1453 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
1454 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1455 attrptr
->num_values
!= 1 ||
1456 strcmp(attrptr
->name
, "attributes-charset"))
1461 attrptr
= attrptr
->next
;
1462 if (!attrptr
|| !attrptr
->name
||
1463 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
1464 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1465 attrptr
->num_values
!= 1 ||
1466 strcmp(attrptr
->name
, "attributes-natural-language"))
1470 if ((attrptr
= ippFindAttribute(response
, "status-message",
1471 IPP_TAG_ZERO
)) != NULL
&&
1472 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
1473 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1474 attrptr
->num_values
!= 1 ||
1475 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1476 strlen(attrptr
->values
[0].string
.text
) > 255)))
1479 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
1480 IPP_TAG_ZERO
)) != NULL
&&
1481 (attrptr
->value_tag
!= IPP_TAG_TEXT
||
1482 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1483 attrptr
->num_values
!= 1 ||
1484 (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1485 strlen(attrptr
->values
[0].string
.text
) > 1023)))
1488 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
1490 attrptr
= attrptr
->next
)
1492 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
1498 if (!validate_attr(attrptr
, 0))
1505 for (i
= 0; i
< num_statuses
; i
++)
1507 if (statuses
[i
].if_defined
&&
1508 !get_variable(vars
, statuses
[i
].if_defined
))
1511 if (statuses
[i
].if_undefined
&&
1512 get_variable(vars
, statuses
[i
].if_undefined
))
1515 if (response
->request
.status
.status_code
== statuses
[i
].status
)
1519 if (i
== num_statuses
&& num_statuses
> 0)
1523 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
1525 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
1528 if (expect
->if_undefined
&& get_variable(vars
, expect
->if_undefined
))
1531 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
1533 if ((found
&& expect
->not_expect
) ||
1534 (!found
&& !(expect
->not_expect
|| expect
->optional
)) ||
1535 (found
&& !expect_matches(expect
, found
->value_tag
)) ||
1536 (found
&& expect
->in_group
&&
1537 found
->group_tag
!= expect
->in_group
))
1544 !with_value(expect
->with_value
, expect
->with_regex
, found
))
1550 if (found
&& expect
->count
> 0 && found
->num_values
!= expect
->count
)
1556 if (found
&& expect
->same_count_as
)
1558 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
1561 if (!attrptr
|| attrptr
->num_values
!= found
->num_values
)
1573 puts("<key>Successful</key>");
1574 puts(pass
? "<true />" : "<false />");
1575 puts("<key>StatusCode</key>");
1576 print_xml_string("string", ippErrorString(cupsLastError()));
1577 puts("<key>ResponseAttributes</key>");
1579 for (attrptr
= response
? response
->attrs
: NULL
;
1581 attrptr
= attrptr
->next
)
1582 print_attr(attrptr
);
1587 puts(pass
? "PASS]" : "FAIL]");
1589 if (Verbosity
&& response
)
1591 printf(" RECEIVED: %lu bytes in response\n",
1592 (unsigned long)ippLength(response
));
1593 printf(" status-code = %x (%s)\n", cupsLastError(),
1594 ippErrorString(cupsLastError()));
1596 for (attrptr
= response
->attrs
;
1598 attrptr
= attrptr
->next
)
1600 print_attr(attrptr
);
1605 if (pass
&& !XML
&& !Verbosity
&& num_displayed
> 0)
1607 for (attrptr
= response
->attrs
;
1609 attrptr
= attrptr
->next
)
1611 for (i
= 0; i
< num_displayed
; i
++)
1612 if (!strcmp(displayed
[i
], attrptr
->name
))
1614 print_attr(attrptr
);
1622 puts("<key>Errors</key>");
1626 if (http
->version
!= HTTP_1_1
)
1627 print_test_error("Bad HTTP version (%d.%d)", http
->version
/ 100,
1628 http
->version
% 100);
1631 print_test_error("IPP request failed with status %s (%s)",
1632 ippErrorString(cupsLastError()),
1633 cupsLastErrorString());
1636 if (response
->request
.status
.version
[0] != (version
/ 10) ||
1637 response
->request
.status
.version
[1] != (version
% 10))
1638 print_test_error("Bad version %d.%d in response - expected %d.%d "
1639 "(RFC 2911 section 3.1.8).",
1640 response
->request
.status
.version
[0],
1641 response
->request
.status
.version
[1],
1642 version
/ 10, version
% 10);
1644 if (response
->request
.status
.request_id
!= request_id
)
1645 print_test_error("Bad request ID %d in response - expected %d "
1646 "(RFC 2911 section 3.1.1)",
1647 response
->request
.status
.request_id
, request_id
);
1649 attrptr
= response
->attrs
;
1651 print_test_error("Missing first attribute \"attributes-charset "
1652 "(charset)\" in group operation-attributes-tag "
1653 "(RFC 2911 section 3.1.4).");
1656 if (!attrptr
->name
||
1657 attrptr
->value_tag
!= IPP_TAG_CHARSET
||
1658 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1659 attrptr
->num_values
!= 1 ||
1660 strcmp(attrptr
->name
, "attributes-charset"))
1661 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
1662 "expected \"attributes-charset (charset)\" in "
1663 "group operation-attributes-tag (RFC 2911 section "
1665 attrptr
->name
? attrptr
->name
: "(null)",
1666 attrptr
->num_values
> 1 ? "1setOf " : "",
1667 ippTagString(attrptr
->value_tag
),
1668 ippTagString(attrptr
->group_tag
));
1670 attrptr
= attrptr
->next
;
1672 print_test_error("Missing second attribute \"attributes-natural-"
1673 "language (naturalLanguage)\" in group "
1674 "operation-attributes-tag (RFC 2911 section "
1676 else if (!attrptr
->name
||
1677 attrptr
->value_tag
!= IPP_TAG_LANGUAGE
||
1678 attrptr
->group_tag
!= IPP_TAG_OPERATION
||
1679 attrptr
->num_values
!= 1 ||
1680 strcmp(attrptr
->name
, "attributes-natural-language"))
1681 print_test_error("Bad first attribute \"%s (%s%s)\" in group %s, "
1682 "expected \"attributes-natural-language "
1683 "(naturalLanguage)\" in group "
1684 "operation-attributes-tag (RFC 2911 section "
1686 attrptr
->name
? attrptr
->name
: "(null)",
1687 attrptr
->num_values
> 1 ? "1setOf " : "",
1688 ippTagString(attrptr
->value_tag
),
1689 ippTagString(attrptr
->group_tag
));
1692 if ((attrptr
= ippFindAttribute(response
, "status-message",
1693 IPP_TAG_ZERO
)) != NULL
)
1695 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
1696 print_test_error("status-message (text(255)) has wrong value tag "
1697 "%s (RFC 2911 section 3.1.6.2).",
1698 ippTagString(attrptr
->value_tag
));
1699 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
1700 print_test_error("status-message (text(255)) has wrong group tag "
1701 "%s (RFC 2911 section 3.1.6.2).",
1702 ippTagString(attrptr
->group_tag
));
1703 if (attrptr
->num_values
!= 1)
1704 print_test_error("status-message (text(255)) has %d values "
1705 "(RFC 2911 section 3.1.6.2).",
1706 attrptr
->num_values
);
1707 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1708 strlen(attrptr
->values
[0].string
.text
) > 255)
1709 print_test_error("status-message (text(255)) has bad length %d"
1710 " (RFC 2911 section 3.1.6.2).",
1711 (int)strlen(attrptr
->values
[0].string
.text
));
1714 if ((attrptr
= ippFindAttribute(response
, "detailed-status-message",
1715 IPP_TAG_ZERO
)) != NULL
)
1717 if (attrptr
->value_tag
!= IPP_TAG_TEXT
)
1718 print_test_error("detailed-status-message (text(MAX)) has wrong "
1719 "value tag %s (RFC 2911 section 3.1.6.3).",
1720 ippTagString(attrptr
->value_tag
));
1721 if (attrptr
->group_tag
!= IPP_TAG_OPERATION
)
1722 print_test_error("detailed-status-message (text(MAX)) has wrong "
1723 "group tag %s (RFC 2911 section 3.1.6.3).",
1724 ippTagString(attrptr
->group_tag
));
1725 if (attrptr
->num_values
!= 1)
1726 print_test_error("detailed-status-message (text(MAX)) has %d values"
1727 " (RFC 2911 section 3.1.6.3).",
1728 attrptr
->num_values
);
1729 if (attrptr
->value_tag
== IPP_TAG_TEXT
&&
1730 strlen(attrptr
->values
[0].string
.text
) > 1023)
1731 print_test_error("detailed-status-message (text(MAX)) has bad "
1732 "length %d (RFC 2911 section 3.1.6.3).",
1733 (int)strlen(attrptr
->values
[0].string
.text
));
1736 for (attrptr
= response
->attrs
, group
= attrptr
->group_tag
;
1738 attrptr
= attrptr
->next
)
1740 if (attrptr
->group_tag
< group
&& attrptr
->group_tag
!= IPP_TAG_ZERO
)
1741 print_test_error("Attribute groups out of order (%s < %s)",
1742 ippTagString(attrptr
->group_tag
),
1743 ippTagString(group
));
1745 validate_attr(attrptr
, 1);
1748 for (i
= 0; i
< num_statuses
; i
++)
1750 if (statuses
[i
].if_defined
&&
1751 !get_variable(vars
, statuses
[i
].if_defined
))
1754 if (statuses
[i
].if_undefined
&&
1755 get_variable(vars
, statuses
[i
].if_undefined
))
1758 if (response
->request
.status
.status_code
== statuses
[i
].status
)
1762 if (i
== num_statuses
&& num_statuses
> 0)
1764 print_test_error("Bad status-code (%s)",
1765 ippErrorString(cupsLastError()));
1766 print_test_error("status-message=\"%s\"", cupsLastErrorString());
1769 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
1771 if (expect
->if_defined
&& !get_variable(vars
, expect
->if_defined
))
1774 if (expect
->if_undefined
&& get_variable(vars
, expect
->if_undefined
))
1777 found
= ippFindAttribute(response
, expect
->name
, IPP_TAG_ZERO
);
1779 if (found
&& expect
->not_expect
)
1780 print_test_error("NOT EXPECTED: %s", expect
->name
);
1781 else if (!found
&& !(expect
->not_expect
|| expect
->optional
))
1782 print_test_error("EXPECTED: %s", expect
->name
);
1785 if (!expect_matches(expect
, found
->value_tag
))
1786 print_test_error("EXPECTED: %s OF-TYPE %s (got %s)",
1787 expect
->name
, expect
->of_type
,
1788 ippTagString(found
->value_tag
));
1790 if (expect
->in_group
&& found
->group_tag
!= expect
->in_group
)
1791 print_test_error("EXPECTED: %s IN-GROUP %s (got %s).",
1792 expect
->name
, ippTagString(expect
->in_group
),
1793 ippTagString(found
->group_tag
));
1795 if (!with_value(expect
->with_value
, expect
->with_regex
, found
))
1797 if (expect
->with_regex
)
1798 print_test_error("EXPECTED: %s WITH-VALUE /%s/",
1799 expect
->name
, expect
->with_value
);
1801 print_test_error("EXPECTED: %s WITH-VALUE \"%s\"",
1802 expect
->name
, expect
->with_value
);
1805 if (expect
->count
> 0 && found
->num_values
!= expect
->count
)
1807 print_test_error("EXPECTED: %s COUNT %d (got %d)", expect
->name
,
1808 expect
->count
, found
->num_values
);
1811 if (expect
->same_count_as
)
1813 attrptr
= ippFindAttribute(response
, expect
->same_count_as
,
1817 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1818 "(not returned)", expect
->name
,
1819 found
->num_values
, expect
->same_count_as
);
1820 else if (attrptr
->num_values
!= found
->num_values
)
1821 print_test_error("EXPECTED: %s (%d values) SAME-COUNT-AS %s "
1822 "(%d values)", expect
->name
, found
->num_values
,
1823 expect
->same_count_as
, attrptr
->num_values
);
1836 ippDelete(response
);
1839 for (i
= 0; i
< num_statuses
; i
++)
1841 if (statuses
[i
].if_defined
)
1842 free(statuses
[i
].if_defined
);
1843 if (statuses
[i
].if_undefined
)
1844 free(statuses
[i
].if_undefined
);
1848 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
1851 if (expect
->of_type
)
1852 free(expect
->of_type
);
1853 if (expect
->same_count_as
)
1854 free(expect
->same_count_as
);
1855 if (expect
->if_defined
)
1856 free(expect
->if_defined
);
1857 if (expect
->if_undefined
)
1858 free(expect
->if_undefined
);
1859 if (expect
->with_value
)
1860 free(expect
->with_value
);
1864 for (i
= 0; i
< num_displayed
; i
++)
1878 * If we get here there was a fatal test error...
1888 ippDelete(response
);
1890 for (i
= 0; i
< num_statuses
; i
++)
1892 if (statuses
[i
].if_defined
)
1893 free(statuses
[i
].if_defined
);
1894 if (statuses
[i
].if_undefined
)
1895 free(statuses
[i
].if_undefined
);
1898 for (i
= num_expects
, expect
= expects
; i
> 0; i
--, expect
++)
1901 if (expect
->of_type
)
1902 free(expect
->of_type
);
1903 if (expect
->same_count_as
)
1904 free(expect
->same_count_as
);
1905 if (expect
->if_defined
)
1906 free(expect
->if_defined
);
1907 if (expect
->if_undefined
)
1908 free(expect
->if_undefined
);
1909 if (expect
->with_value
)
1910 free(expect
->with_value
);
1913 for (i
= 0; i
< num_displayed
; i
++)
1921 * 'expand_variables()' - Expand variables in a string.
1925 expand_variables(_cups_vars_t
*vars
, /* I - Variables */
1926 char *dst
, /* I - Destination string buffer */
1927 const char *src
, /* I - Source string */
1928 size_t dstsize
) /* I - Size of destination buffer */
1930 char *dstptr
, /* Pointer into destination */
1931 *dstend
, /* End of destination */
1932 temp
[256], /* Temporary string */
1933 *tempptr
; /* Pointer into temporary string */
1934 const char *value
; /* Value to substitute */
1938 dstend
= dst
+ dstsize
- 1;
1940 while (*src
&& dstptr
< dstend
)
1945 * Substitute a string/number...
1948 if (!strncmp(src
, "$$", 2))
1953 else if (!strncmp(src
, "$ENV[", 5))
1955 strlcpy(temp
, src
+ 5, sizeof(temp
));
1957 for (tempptr
= temp
; *tempptr
; tempptr
++)
1958 if (*tempptr
== ']')
1964 value
= getenv(temp
);
1965 src
+= tempptr
- temp
+ 5;
1969 strlcpy(temp
, src
+ 1, sizeof(temp
));
1971 for (tempptr
= temp
; *tempptr
; tempptr
++)
1972 if (!isalnum(*tempptr
& 255) && *tempptr
!= '-' && *tempptr
!= '_')
1978 if (!strcmp(temp
, "uri"))
1980 else if (!strcmp(temp
, "filename"))
1981 value
= vars
->filename
;
1982 else if (!strcmp(temp
, "scheme") || !strcmp(temp
, "method"))
1983 value
= vars
->scheme
;
1984 else if (!strcmp(temp
, "username"))
1985 value
= vars
->userpass
;
1986 else if (!strcmp(temp
, "hostname"))
1987 value
= vars
->hostname
;
1988 else if (!strcmp(temp
, "port"))
1990 snprintf(temp
, sizeof(temp
), "%d", vars
->port
);
1993 else if (!strcmp(temp
, "resource"))
1994 value
= vars
->resource
;
1995 else if (!strcmp(temp
, "user"))
1998 value
= get_variable(vars
, temp
);
2000 src
+= tempptr
- temp
+ 1;
2010 strlcpy(dstptr
, value
, dstend
- dstptr
+ 1);
2011 dstptr
+= strlen(dstptr
);
2023 * 'expect_matches()' - Return true if the tag matches the specification.
2026 static int /* O - 1 if matches, 0 otherwise */
2028 _cups_expect_t
*expect
, /* I - Expected attribute */
2029 ipp_tag_t value_tag
) /* I - Value tag for attribute */
2031 int match
; /* Match? */
2032 char *of_type
, /* Type name to match */
2033 *next
, /* Next name to match */
2034 sep
; /* Separator character */
2038 * If we don't expect a particular type, return immediately...
2041 if (!expect
->of_type
)
2045 * Parse the "of_type" value since the string can contain multiple attribute
2046 * types separated by "," or "|"...
2049 for (of_type
= expect
->of_type
, match
= 0; !match
&& *of_type
; of_type
= next
)
2052 * Find the next separator, and set it (temporarily) to nul if present.
2055 for (next
= of_type
; *next
&& *next
!= '|' && *next
!= ','; next
++);
2057 if ((sep
= *next
) != '\0')
2061 * Support some meta-types to make it easier to write the test file.
2064 if (!strcmp(of_type
, "text"))
2065 match
= value_tag
== IPP_TAG_TEXTLANG
|| value_tag
== IPP_TAG_TEXT
;
2066 else if (!strcmp(of_type
, "name"))
2067 match
= value_tag
== IPP_TAG_NAMELANG
|| value_tag
== IPP_TAG_NAME
;
2068 else if (!strcmp(of_type
, "collection"))
2069 match
= value_tag
== IPP_TAG_BEGIN_COLLECTION
;
2071 match
= value_tag
== ippTagValue(of_type
);
2074 * Restore the separator if we have one...
2086 * 'get_collection()' - Get a collection value from the current test file.
2089 static ipp_t
* /* O - Collection value */
2090 get_collection(_cups_vars_t
*vars
, /* I - Variables */
2091 FILE *fp
, /* I - File to read from */
2092 int *linenum
) /* IO - Line number */
2094 char token
[1024], /* Token from file */
2095 temp
[1024], /* Temporary string */
2096 attr
[128]; /* Attribute name */
2097 ipp_tag_t value
; /* Current value type */
2098 ipp_t
*col
= ippNew(); /* Collection value */
2099 ipp_attribute_t
*lastcol
= NULL
; /* Last collection attribute */
2102 while (get_token(fp
, token
, sizeof(token
), linenum
) != NULL
)
2104 if (!strcmp(token
, "}"))
2106 else if (!strcmp(token
, "{") && lastcol
)
2109 * Another collection value
2112 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
2113 /* Collection value */
2117 ipp_attribute_t
*tempcol
; /* Pointer to new buffer */
2121 * Reallocate memory...
2124 if ((tempcol
= realloc(lastcol
, sizeof(ipp_attribute_t
) +
2125 (lastcol
->num_values
+ 1) *
2126 sizeof(ipp_value_t
))) == NULL
)
2128 print_fatal_error("Unable to allocate memory on line %d.", *linenum
);
2132 if (tempcol
!= lastcol
)
2135 * Reset pointers in the list...
2139 col
->prev
->next
= tempcol
;
2141 col
->attrs
= tempcol
;
2143 lastcol
= col
->current
= col
->last
= tempcol
;
2146 lastcol
->values
[lastcol
->num_values
].collection
= subcol
;
2147 lastcol
->num_values
++;
2152 else if (!strcasecmp(token
, "MEMBER"))
2160 if (!get_token(fp
, token
, sizeof(token
), linenum
))
2162 print_fatal_error("Missing MEMBER value tag on line %d.", *linenum
);
2166 if ((value
= ippTagValue(token
)) < 0)
2168 print_fatal_error("Bad MEMBER value tag \"%s\" on line %d.", token
,
2173 if (!get_token(fp
, attr
, sizeof(attr
), linenum
))
2175 print_fatal_error("Missing MEMBER name on line %d.", *linenum
);
2179 if (!get_token(fp
, temp
, sizeof(temp
), linenum
))
2181 print_fatal_error("Missing MEMBER value on line %d.", *linenum
);
2185 expand_variables(vars
, token
, temp
, sizeof(token
));
2189 case IPP_TAG_BOOLEAN
:
2190 if (!strcasecmp(token
, "true"))
2191 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, 1);
2193 ippAddBoolean(col
, IPP_TAG_ZERO
, attr
, atoi(token
));
2196 case IPP_TAG_INTEGER
:
2198 ippAddInteger(col
, IPP_TAG_ZERO
, value
, attr
, atoi(token
));
2201 case IPP_TAG_RESOLUTION
:
2203 int xres
, /* X resolution */
2204 yres
; /* Y resolution */
2205 char units
[6]; /* Units */
2207 if (sscanf(token
, "%dx%d%5s", &xres
, &yres
, units
) != 3 ||
2208 (strcasecmp(units
, "dpi") && strcasecmp(units
, "dpc") &&
2209 strcasecmp(units
, "other")))
2211 print_fatal_error("Bad resolution value \"%s\" on line %d.",
2216 if (!strcasecmp(units
, "dpi"))
2217 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2219 else if (!strcasecmp(units
, "dpc"))
2220 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2223 ippAddResolution(col
, IPP_TAG_ZERO
, attr
, xres
, yres
,
2228 case IPP_TAG_RANGE
:
2230 int lowers
[4], /* Lower value */
2231 uppers
[4], /* Upper values */
2232 num_vals
; /* Number of values */
2235 num_vals
= sscanf(token
, "%d-%d,%d-%d,%d-%d,%d-%d",
2236 lowers
+ 0, uppers
+ 0,
2237 lowers
+ 1, uppers
+ 1,
2238 lowers
+ 2, uppers
+ 2,
2239 lowers
+ 3, uppers
+ 3);
2241 if ((num_vals
& 1) || num_vals
== 0)
2243 print_fatal_error("Bad rangeOfInteger value \"%s\" on line %d.",
2248 ippAddRanges(col
, IPP_TAG_ZERO
, attr
, num_vals
/ 2, lowers
,
2253 case IPP_TAG_BEGIN_COLLECTION
:
2254 if (!strcmp(token
, "{"))
2256 ipp_t
*subcol
= get_collection(vars
, fp
, linenum
);
2257 /* Collection value */
2260 lastcol
= ippAddCollection(col
, IPP_TAG_ZERO
, attr
, subcol
);
2266 print_fatal_error("Bad collection value on line %d.", *linenum
);
2272 if (!strchr(token
, ','))
2273 ippAddString(col
, IPP_TAG_ZERO
, value
, attr
, NULL
, token
);
2277 * Multiple string values...
2280 int num_values
; /* Number of values */
2281 char *values
[100], /* Values */
2282 *ptr
; /* Pointer to next value */
2288 for (ptr
= strchr(token
, ','); ptr
; ptr
= strchr(ptr
, ','))
2291 values
[num_values
] = ptr
;
2295 ippAddStrings(col
, IPP_TAG_ZERO
, value
, attr
, num_values
,
2296 NULL
, (const char **)values
);
2306 * If we get here there was a parse error; free memory and return.
2318 * 'get_filename()' - Get a filename based on the current test file.
2321 static char * /* O - Filename */
2322 get_filename(const char *testfile
, /* I - Current test file */
2323 char *dst
, /* I - Destination filename */
2324 const char *src
, /* I - Source filename */
2325 size_t dstsize
) /* I - Size of destination buffer */
2327 char *dstptr
; /* Pointer into destination */
2328 _cups_globals_t
*cg
= _cupsGlobals();
2332 if (*src
== '<' && src
[strlen(src
) - 1] == '>')
2335 * Map <filename> to CUPS_DATADIR/ipptest/filename...
2338 snprintf(dst
, dstsize
, "%s/ipptest/%s", cg
->cups_datadir
, src
+ 1);
2339 dstptr
= dst
+ strlen(dst
) - 1;
2343 else if (*src
== '/' || !strchr(testfile
, '/'))
2346 * Use the path as-is...
2349 strlcpy(dst
, src
, dstsize
);
2354 * Make path relative to testfile...
2357 strlcpy(dst
, testfile
, dstsize
);
2358 if ((dstptr
= strrchr(dst
, '/')) != NULL
)
2361 dstptr
= dst
; /* Should never happen */
2363 strlcpy(dstptr
, src
, dstsize
- (dstptr
- dst
));
2371 * 'get_token()' - Get a token from a file.
2374 static char * /* O - Token from file or NULL on EOF */
2375 get_token(FILE *fp
, /* I - File to read from */
2376 char *buf
, /* I - Buffer to read into */
2377 int buflen
, /* I - Length of buffer */
2378 int *linenum
) /* IO - Current line number */
2380 int ch
, /* Character from file */
2381 quote
; /* Quoting character */
2382 char *bufptr
, /* Pointer into buffer */
2383 *bufend
; /* End of buffer */
2389 * Skip whitespace...
2392 while (isspace(ch
= getc(fp
)))
2404 else if (ch
== '\'' || ch
== '\"')
2407 * Quoted text or regular expression...
2412 bufend
= buf
+ buflen
- 1;
2414 while ((ch
= getc(fp
)) != EOF
)
2419 * Escape next character...
2422 if (bufptr
< bufend
)
2425 if ((ch
= getc(fp
)) != EOF
&& bufptr
< bufend
)
2428 else if (ch
== quote
)
2430 else if (bufptr
< bufend
)
2444 while ((ch
= getc(fp
)) != EOF
)
2453 * Whitespace delimited text...
2459 bufend
= buf
+ buflen
- 1;
2461 while ((ch
= getc(fp
)) != EOF
)
2462 if (isspace(ch
) || ch
== '#')
2464 else if (bufptr
< bufend
)
2469 else if (ch
== '\n')
2481 * 'get_variable()' - Get the value of a variable.
2484 static char * /* O - Value or NULL */
2485 get_variable(_cups_vars_t
*vars
, /* I - Variables */
2486 const char *name
) /* I - Variable name */
2488 _cups_var_t key
, /* Search key */
2489 *match
; /* Matching variable, if any */
2492 key
.name
= (char *)name
;
2493 match
= cupsArrayFind(vars
->vars
, &key
);
2495 return (match
? match
->value
: NULL
);
2500 * 'iso_date()' - Return an ISO 8601 date/time string for the given IPP dateTime
2504 static char * /* O - ISO 8601 date/time string */
2505 iso_date(ipp_uchar_t
*date
) /* I - IPP (RFC 1903) date/time value */
2507 unsigned year
= (date
[0] << 8) + date
[1];
2509 static char buffer
[255]; /* String buffer */
2512 if (date
[9] == 0 && date
[10] == 0)
2513 snprintf(buffer
, sizeof(buffer
), "%04u-%02u-%02uT%02u:%02u:%02uZ",
2514 year
, date
[2], date
[3], date
[4], date
[5], date
[6]);
2516 snprintf(buffer
, sizeof(buffer
), "%04u-%02u-%02uT%02u:%02u:%02u%c%02u%02u",
2517 year
, date
[2], date
[3], date
[4], date
[5], date
[6],
2518 date
[8], date
[9], date
[10]);
2525 * 'print_attr()' - Print an attribute on the screen.
2529 print_attr(ipp_attribute_t
*attr
) /* I - Attribute to print */
2531 int i
; /* Looping var */
2532 ipp_attribute_t
*colattr
; /* Collection attribute */
2539 printf("<key>%s</key>\n<true />\n", ippTagString(attr
->group_tag
));
2543 print_xml_string("key", attr
->name
);
2544 if (attr
->num_values
> 1)
2551 puts(" -- separator --");
2555 printf(" %s (%s%s) = ", attr
->name
,
2556 attr
->num_values
> 1 ? "1setOf " : "",
2557 ippTagString(attr
->value_tag
));
2560 switch (attr
->value_tag
)
2562 case IPP_TAG_INTEGER
:
2564 for (i
= 0; i
< attr
->num_values
; i
++)
2566 printf("<integer>%d</integer>\n", attr
->values
[i
].integer
);
2568 printf("%d ", attr
->values
[i
].integer
);
2571 case IPP_TAG_BOOLEAN
:
2572 for (i
= 0; i
< attr
->num_values
; i
++)
2574 puts(attr
->values
[i
].boolean
? "<true />" : "<false />");
2575 else if (attr
->values
[i
].boolean
)
2576 fputs("true ", stdout
);
2578 fputs("false ", stdout
);
2581 case IPP_TAG_RANGE
:
2582 for (i
= 0; i
< attr
->num_values
; i
++)
2584 printf("<dict><key>lower</key><integer>%d</integer>"
2585 "<key>upper</key><integer>%d</integer></dict>\n",
2586 attr
->values
[i
].range
.lower
, attr
->values
[i
].range
.upper
);
2588 printf("%d-%d ", attr
->values
[i
].range
.lower
,
2589 attr
->values
[i
].range
.upper
);
2592 case IPP_TAG_RESOLUTION
:
2593 for (i
= 0; i
< attr
->num_values
; i
++)
2595 printf("<dict><key>xres</key><integer>%d</integer>"
2596 "<key>yres</key><integer>%d</integer>"
2597 "<key>units</key><string>%s</string></dict>\n",
2598 attr
->values
[i
].resolution
.xres
,
2599 attr
->values
[i
].resolution
.yres
,
2600 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2603 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
2604 attr
->values
[i
].resolution
.yres
,
2605 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2610 for (i
= 0; i
< attr
->num_values
; i
++)
2612 printf("<date>%s</date>\n", iso_date(attr
->values
[i
].date
));
2614 printf("%s ", iso_date(attr
->values
[i
].date
));
2617 case IPP_TAG_STRING
:
2620 case IPP_TAG_KEYWORD
:
2621 case IPP_TAG_CHARSET
:
2623 case IPP_TAG_MIMETYPE
:
2624 case IPP_TAG_LANGUAGE
:
2625 for (i
= 0; i
< attr
->num_values
; i
++)
2627 print_xml_string("string", attr
->values
[i
].string
.text
);
2629 printf("\"%s\" ", attr
->values
[i
].string
.text
);
2632 case IPP_TAG_TEXTLANG
:
2633 case IPP_TAG_NAMELANG
:
2634 for (i
= 0; i
< attr
->num_values
; i
++)
2637 fputs("<dict><key>language</key><string>", stdout
);
2638 print_xml_string(NULL
, attr
->values
[i
].string
.charset
);
2639 fputs("</string><key>string</key><string>", stdout
);
2640 print_xml_string(NULL
, attr
->values
[i
].string
.text
);
2641 puts("</string></dict>");
2644 printf("\"%s\",%s ", attr
->values
[i
].string
.text
,
2645 attr
->values
[i
].string
.charset
);
2648 case IPP_TAG_BEGIN_COLLECTION
:
2649 for (i
= 0; i
< attr
->num_values
; i
++)
2654 for (colattr
= attr
->values
[i
].collection
->attrs
;
2656 colattr
= colattr
->next
)
2657 print_attr(colattr
);
2665 print_col(attr
->values
[i
].collection
);
2672 printf("<string><<%s>></string>\n",
2673 ippTagString(attr
->value_tag
));
2675 fputs(ippTagString(attr
->value_tag
), stdout
);
2681 if (attr
->num_values
> 1)
2690 * 'print_col()' - Print a collection attribute on the screen.
2694 print_col(ipp_t
*col
) /* I - Collection attribute to print */
2696 int i
; /* Looping var */
2697 ipp_attribute_t
*attr
; /* Current attribute in collection */
2700 fputs("{ ", stdout
);
2701 for (attr
= col
->attrs
; attr
; attr
= attr
->next
)
2703 printf("%s (%s%s) = ", attr
->name
, attr
->num_values
> 1 ? "1setOf " : "",
2704 ippTagString(attr
->value_tag
));
2706 switch (attr
->value_tag
)
2708 case IPP_TAG_INTEGER
:
2710 for (i
= 0; i
< attr
->num_values
; i
++)
2711 printf("%d ", attr
->values
[i
].integer
);
2714 case IPP_TAG_BOOLEAN
:
2715 for (i
= 0; i
< attr
->num_values
; i
++)
2716 if (attr
->values
[i
].boolean
)
2722 case IPP_TAG_NOVALUE
:
2726 case IPP_TAG_RANGE
:
2727 for (i
= 0; i
< attr
->num_values
; i
++)
2728 printf("%d-%d ", attr
->values
[i
].range
.lower
,
2729 attr
->values
[i
].range
.upper
);
2732 case IPP_TAG_RESOLUTION
:
2733 for (i
= 0; i
< attr
->num_values
; i
++)
2734 printf("%dx%d%s ", attr
->values
[i
].resolution
.xres
,
2735 attr
->values
[i
].resolution
.yres
,
2736 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
2740 case IPP_TAG_STRING
:
2743 case IPP_TAG_KEYWORD
:
2744 case IPP_TAG_CHARSET
:
2746 case IPP_TAG_MIMETYPE
:
2747 case IPP_TAG_LANGUAGE
:
2748 for (i
= 0; i
< attr
->num_values
; i
++)
2749 printf("\"%s\" ", attr
->values
[i
].string
.text
);
2752 case IPP_TAG_TEXTLANG
:
2753 case IPP_TAG_NAMELANG
:
2754 for (i
= 0; i
< attr
->num_values
; i
++)
2755 printf("\"%s\",%s ", attr
->values
[i
].string
.text
,
2756 attr
->values
[i
].string
.charset
);
2759 case IPP_TAG_BEGIN_COLLECTION
:
2760 for (i
= 0; i
< attr
->num_values
; i
++)
2762 print_col(attr
->values
[i
].collection
);
2768 break; /* anti-compiler-warning-code */
2777 * 'print_fatal_error()' - Print a fatal error message.
2781 print_fatal_error(const char *s
, /* I - Printf-style format string */
2782 ...) /* I - Additional arguments as needed */
2784 char buffer
[10240]; /* Format buffer */
2785 va_list ap
; /* Pointer to arguments */
2789 * Format the error message...
2793 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
2803 print_xml_trailer(0, buffer
);
2806 _cupsLangPrintf(stderr
, "ipptest: %s\n", buffer
);
2811 * 'print_test_error()' - Print a test error message.
2815 print_test_error(const char *s
, /* I - Printf-style format string */
2816 ...) /* I - Additional arguments as needed */
2818 char buffer
[10240]; /* Format buffer */
2819 va_list ap
; /* Pointer to arguments */
2823 * Format the error message...
2827 vsnprintf(buffer
, sizeof(buffer
), s
, ap
);
2835 print_xml_string("string", buffer
);
2837 printf(" %s\n", buffer
);
2842 * 'print_xml_header()' - Print a standard XML plist header.
2846 print_xml_header(void)
2850 puts("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
2851 puts("<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" "
2852 "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
2853 puts("<plist version=\"1.0\">");
2855 puts("<key>Transfer</key>");
2856 printf("<string>%s</string>\n",
2857 Transfer
== _CUPS_TRANSFER_AUTO
? "auto" :
2858 Transfer
== _CUPS_TRANSFER_CHUNKED
? "chunked" : "length");
2859 puts("<key>Tests</key>");
2868 * 'print_xml_string()' - Print an XML string with escaping.
2872 print_xml_string(const char *element
, /* I - Element name or NULL */
2873 const char *s
) /* I - String to print */
2876 printf("<%s>", element
);
2881 fputs("&", stdout
);
2883 fputs("<", stdout
);
2885 fputs(">", stdout
);
2893 printf("</%s>\n", element
);
2898 * 'print_xml_trailer()' - Print the XML trailer with success/fail value.
2902 print_xml_trailer(int success
, /* I - 1 on success, 0 on failure */
2903 const char *message
) /* I - Error message or NULL */
2908 puts("<key>Successful</key>");
2909 puts(success
? "<true />" : "<false />");
2912 puts("<key>ErrorMessage</key>");
2913 print_xml_string("string", message
);
2924 * 'set_variable()' - Set a variable value.
2928 set_variable(_cups_vars_t
*vars
, /* I - Variables */
2929 const char *name
, /* I - Variable name */
2930 const char *value
) /* I - Value string */
2932 _cups_var_t key
, /* Search key */
2933 *var
; /* New variable */
2936 key
.name
= (char *)name
;
2937 if ((var
= cupsArrayFind(vars
->vars
, &key
)) != NULL
)
2940 var
->value
= strdup(value
);
2942 else if ((var
= malloc(sizeof(_cups_var_t
))) == NULL
)
2944 print_fatal_error("Unable to allocate memory for variable \"%s\".", name
);
2949 var
->name
= strdup(name
);
2950 var
->value
= strdup(value
);
2952 cupsArrayAdd(vars
->vars
, var
);
2958 * 'usage()' - Show program usage.
2964 _cupsLangPuts(stderr
,
2965 _("Usage: ipptest [options] URI filename.test [ ... "
2966 "filenameN.test ]\n"
2970 "-E Test with encryption.\n"
2971 "-V version Set default IPP version.\n"
2972 "-X Produce XML instead of plain text.\n"
2973 "-c Send requests using chunking (default)\n"
2974 "-d name=value Define variable.\n"
2975 "-f filename Set default test file.\n"
2976 "-i seconds Repeat the last test file with the given "
2978 "-l Send requests using content-length\n"
2979 "-v Show all attributes sent and received.\n"));
2986 * 'validate_attr()' - Determine whether an attribute is valid.
2989 static int /* O - 1 if valid, 0 otherwise */
2990 validate_attr(ipp_attribute_t
*attr
, /* I - Attribute to validate */
2991 int print
) /* I - 1 = report issues to stdout */
2993 int i
; /* Looping var */
2994 char scheme
[64], /* Scheme from URI */
2995 userpass
[256], /* Username/password from URI */
2996 hostname
[256], /* Hostname from URI */
2997 resource
[1024]; /* Resource from URI */
2998 int port
, /* Port number from URI */
2999 uri_status
, /* URI separation status */
3000 valid
= 1; /* Is the attribute valid? */
3001 const char *ptr
; /* Pointer into string */
3002 ipp_attribute_t
*colattr
; /* Collection attribute */
3003 regex_t re
; /* Regular expression */
3004 ipp_uchar_t
*date
; /* Current date value */
3015 * Validate the attribute name.
3018 for (ptr
= attr
->name
; *ptr
; ptr
++)
3019 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' && *ptr
!= '_')
3022 if (*ptr
|| ptr
== attr
->name
)
3027 print_test_error("\"%s\": Bad attribute name - invalid character (RFC "
3028 "2911 section 4.1.3).", attr
->name
);
3031 if ((ptr
- attr
->name
) > 255)
3036 print_test_error("\"%s\": Bad attribute name - bad length (RFC 2911 "
3037 "section 4.1.3).", attr
->name
);
3040 switch (attr
->value_tag
)
3042 case IPP_TAG_INTEGER
:
3045 case IPP_TAG_BOOLEAN
:
3046 for (i
= 0; i
< attr
->num_values
; i
++)
3048 if (attr
->values
[i
].boolean
!= 0 &&
3049 attr
->values
[i
].boolean
!= 1)
3054 print_test_error("\"%s\": Bad boolen value %d (RFC 2911 section "
3055 "4.1.10).", attr
->name
, attr
->values
[i
].boolean
);
3063 for (i
= 0; i
< attr
->num_values
; i
++)
3065 if (attr
->values
[i
].integer
< 1)
3070 print_test_error("\"%s\": Bad enum value %d - out of range "
3071 "(RFC 2911 section 4.1.4).", attr
->name
,
3072 attr
->values
[i
].integer
);
3079 case IPP_TAG_STRING
:
3080 for (i
= 0; i
< attr
->num_values
; i
++)
3082 if (attr
->values
[i
].unknown
.length
> 1023)
3087 print_test_error("\"%s\": Bad octetString value - bad length %d "
3088 "(RFC 2911 section 4.1.10).", attr
->name
,
3089 attr
->values
[i
].unknown
.length
);
3097 for (i
= 0; i
< attr
->num_values
; i
++)
3099 date
= attr
->values
[i
].date
;
3101 if (date
[2] < 1 || date
[2] > 12)
3106 print_test_error("\"%s\": Bad dateTime month %u (RFC 2911 "
3107 "section 4.1.13).", attr
->name
, date
[2]);
3112 if (date
[3] < 1 || date
[3] > 31)
3117 print_test_error("\"%s\": Bad dateTime day %u (RFC 2911 "
3118 "section 4.1.13).", attr
->name
, date
[3]);
3128 print_test_error("\"%s\": Bad dateTime hours %u (RFC 2911 "
3129 "section 4.1.13).", attr
->name
, date
[4]);
3139 print_test_error("\"%s\": Bad dateTime minutes %u (RFC 2911 "
3140 "section 4.1.13).", attr
->name
, date
[5]);
3150 print_test_error("\"%s\": Bad dateTime seconds %u (RFC 2911 "
3151 "section 4.1.13).", attr
->name
, date
[6]);
3161 print_test_error("\"%s\": Bad dateTime deciseconds %u (RFC 2911 "
3162 "section 4.1.13).", attr
->name
, date
[7]);
3167 if (date
[8] != '-' && date
[8] != '+')
3172 print_test_error("\"%s\": Bad dateTime UTC sign '%c' (RFC 2911 "
3173 "section 4.1.13).", attr
->name
, date
[8]);
3183 print_test_error("\"%s\": Bad dateTime UTC hours %u (RFC 2911 "
3184 "section 4.1.13).", attr
->name
, date
[9]);
3194 print_test_error("\"%s\": Bad dateTime UTC minutes %u (RFC 2911 "
3195 "section 4.1.13).", attr
->name
, date
[10]);
3202 case IPP_TAG_RESOLUTION
:
3203 for (i
= 0; i
< attr
->num_values
; i
++)
3205 if (attr
->values
[i
].resolution
.xres
<= 0)
3210 print_test_error("\"%s\": Bad resolution value %dx%d%s - cross "
3211 "feed resolution must be positive (RFC 2911 "
3212 "section 4.1.13).", attr
->name
,
3213 attr
->values
[i
].resolution
.xres
,
3214 attr
->values
[i
].resolution
.yres
,
3215 attr
->values
[i
].resolution
.units
==
3216 IPP_RES_PER_INCH
? "dpi" :
3217 attr
->values
[i
].resolution
.units
==
3218 IPP_RES_PER_CM
? "dpc" : "unknown");
3223 if (attr
->values
[i
].resolution
.yres
<= 0)
3228 print_test_error("\"%s\": Bad resolution value %dx%d%s - feed "
3229 "resolution must be positive (RFC 2911 section "
3230 "4.1.13).", attr
->name
,
3231 attr
->values
[i
].resolution
.xres
,
3232 attr
->values
[i
].resolution
.yres
,
3233 attr
->values
[i
].resolution
.units
==
3234 IPP_RES_PER_INCH
? "dpi" :
3235 attr
->values
[i
].resolution
.units
==
3236 IPP_RES_PER_CM
? "dpc" : "unknown");
3241 if (attr
->values
[i
].resolution
.units
!= IPP_RES_PER_INCH
&&
3242 attr
->values
[i
].resolution
.units
!= IPP_RES_PER_CM
)
3247 print_test_error("\"%s\": Bad resolution value %dx%d%s - bad "
3248 "units value (RFC 2911 section 4.1.13).",
3249 attr
->name
, attr
->values
[i
].resolution
.xres
,
3250 attr
->values
[i
].resolution
.yres
,
3251 attr
->values
[i
].resolution
.units
==
3252 IPP_RES_PER_INCH
? "dpi" :
3253 attr
->values
[i
].resolution
.units
==
3254 IPP_RES_PER_CM
? "dpc" : "unknown");
3261 case IPP_TAG_RANGE
:
3262 for (i
= 0; i
< attr
->num_values
; i
++)
3264 if (attr
->values
[i
].range
.lower
> attr
->values
[i
].range
.upper
)
3269 print_test_error("\"%s\": Bad rangeOfInteger value %d-%d - lower "
3270 "greater than upper (RFC 2911 section 4.1.13).",
3271 attr
->name
, attr
->values
[i
].range
.lower
,
3272 attr
->values
[i
].range
.upper
);
3279 case IPP_TAG_BEGIN_COLLECTION
:
3280 for (i
= 0; i
< attr
->num_values
; i
++)
3282 for (colattr
= attr
->values
[i
].collection
->attrs
;
3284 colattr
= colattr
->next
)
3286 if (!validate_attr(colattr
, 0))
3293 if (colattr
&& print
)
3295 print_test_error("\"%s\": Bad collection value.", attr
->name
);
3299 validate_attr(colattr
, print
);
3300 colattr
= colattr
->next
;
3307 case IPP_TAG_TEXTLANG
:
3308 for (i
= 0; i
< attr
->num_values
; i
++)
3310 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3312 if ((*ptr
& 0xe0) == 0xc0)
3315 if ((*ptr
& 0xc0) != 0x80)
3318 else if ((*ptr
& 0xf0) == 0xe0)
3321 if ((*ptr
& 0xc0) != 0x80)
3324 if ((*ptr
& 0xc0) != 0x80)
3327 else if ((*ptr
& 0xf8) == 0xf0)
3330 if ((*ptr
& 0xc0) != 0x80)
3333 if ((*ptr
& 0xc0) != 0x80)
3336 if ((*ptr
& 0xc0) != 0x80)
3339 else if (*ptr
& 0x80)
3348 print_test_error("\"%s\": Bad text value \"%s\" - bad UTF-8 "
3349 "sequence (RFC 2911 section 4.1.1).", attr
->name
,
3350 attr
->values
[i
].string
.text
);
3355 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
3360 print_test_error("\"%s\": Bad text value \"%s\" - bad length %d "
3361 "(RFC 2911 section 4.1.1).", attr
->name
,
3362 attr
->values
[i
].string
.text
,
3363 (int)strlen(attr
->values
[i
].string
.text
));
3371 case IPP_TAG_NAMELANG
:
3372 for (i
= 0; i
< attr
->num_values
; i
++)
3374 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3376 if ((*ptr
& 0xe0) == 0xc0)
3379 if ((*ptr
& 0xc0) != 0x80)
3382 else if ((*ptr
& 0xf0) == 0xe0)
3385 if ((*ptr
& 0xc0) != 0x80)
3388 if ((*ptr
& 0xc0) != 0x80)
3391 else if ((*ptr
& 0xf8) == 0xf0)
3394 if ((*ptr
& 0xc0) != 0x80)
3397 if ((*ptr
& 0xc0) != 0x80)
3400 if ((*ptr
& 0xc0) != 0x80)
3403 else if (*ptr
& 0x80)
3412 print_test_error("\"%s\": Bad name value \"%s\" - bad UTF-8 "
3413 "sequence (RFC 2911 section 4.1.2).", attr
->name
,
3414 attr
->values
[i
].string
.text
);
3419 if ((ptr
- attr
->values
[i
].string
.text
) > 1023)
3424 print_test_error("\"%s\": Bad name value \"%s\" - bad length %d "
3425 "(RFC 2911 section 4.1.2).", attr
->name
,
3426 attr
->values
[i
].string
.text
,
3427 (int)strlen(attr
->values
[i
].string
.text
));
3434 case IPP_TAG_KEYWORD
:
3435 for (i
= 0; i
< attr
->num_values
; i
++)
3437 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3438 if (!isalnum(*ptr
& 255) && *ptr
!= '-' && *ptr
!= '.' &&
3442 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
3447 print_test_error("\"%s\": Bad keyword value \"%s\" - invalid "
3448 "character (RFC 2911 section 4.1.3).",
3449 attr
->name
, attr
->values
[i
].string
.text
);
3454 if ((ptr
- attr
->values
[i
].string
.text
) > 255)
3459 print_test_error("\"%s\": Bad keyword value \"%s\" - bad "
3460 "length %d (RFC 2911 section 4.1.3).",
3461 attr
->name
, attr
->values
[i
].string
.text
,
3462 (int)strlen(attr
->values
[i
].string
.text
));
3470 for (i
= 0; i
< attr
->num_values
; i
++)
3472 uri_status
= httpSeparateURI(HTTP_URI_CODING_ALL
,
3473 attr
->values
[i
].string
.text
,
3474 scheme
, sizeof(scheme
),
3475 userpass
, sizeof(userpass
),
3476 hostname
, sizeof(hostname
),
3477 &port
, resource
, sizeof(resource
));
3479 if (uri_status
< HTTP_URI_OK
)
3484 print_test_error("\"%s\": Bad URI value \"%s\" - %s "
3485 "(RFC 2911 section 4.1.5).", attr
->name
,
3486 attr
->values
[i
].string
.text
,
3487 URIStatusStrings
[uri_status
-
3488 HTTP_URI_OVERFLOW
]);
3493 if (strlen(attr
->values
[i
].string
.text
) > 1023)
3498 print_test_error("\"%s\": Bad URI value \"%s\" - bad length %d "
3499 "(RFC 2911 section 4.1.5).", attr
->name
,
3500 attr
->values
[i
].string
.text
,
3501 (int)strlen(attr
->values
[i
].string
.text
));
3508 case IPP_TAG_URISCHEME
:
3509 for (i
= 0; i
< attr
->num_values
; i
++)
3511 ptr
= attr
->values
[i
].string
.text
;
3512 if (islower(*ptr
& 255))
3514 for (ptr
++; *ptr
; ptr
++)
3515 if (!islower(*ptr
& 255) && !isdigit(*ptr
& 255) &&
3516 *ptr
!= '+' && *ptr
!= '-' && *ptr
!= '.')
3520 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
3525 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
3526 "characters (RFC 2911 section 4.1.6).",
3527 attr
->name
, attr
->values
[i
].string
.text
);
3532 if ((ptr
- attr
->values
[i
].string
.text
) > 63)
3537 print_test_error("\"%s\": Bad uriScheme value \"%s\" - bad "
3538 "length %d (RFC 2911 section 4.1.6).",
3539 attr
->name
, attr
->values
[i
].string
.text
,
3540 (int)strlen(attr
->values
[i
].string
.text
));
3547 case IPP_TAG_CHARSET
:
3548 for (i
= 0; i
< attr
->num_values
; i
++)
3550 for (ptr
= attr
->values
[i
].string
.text
; *ptr
; ptr
++)
3551 if (!isprint(*ptr
& 255) || isupper(*ptr
& 255) ||
3552 isspace(*ptr
& 255))
3555 if (*ptr
|| ptr
== attr
->values
[i
].string
.text
)
3560 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
3561 "characters (RFC 2911 section 4.1.7).",
3562 attr
->name
, attr
->values
[i
].string
.text
);
3567 if ((ptr
- attr
->values
[i
].string
.text
) > 40)
3572 print_test_error("\"%s\": Bad charset value \"%s\" - bad "
3573 "length %d (RFC 2911 section 4.1.7).",
3574 attr
->name
, attr
->values
[i
].string
.text
,
3575 (int)strlen(attr
->values
[i
].string
.text
));
3582 case IPP_TAG_LANGUAGE
:
3584 * The following regular expression is derived from the ABNF for
3585 * language tags in RFC 4646. All I can say is that this is the
3586 * easiest way to check the values...
3589 if ((i
= regcomp(&re
,
3591 "(([a-z]{2,3}(-[a-z][a-z][a-z]){0,3})|[a-z]{4,8})"
3593 "(-[a-z][a-z][a-z][a-z]){0,1}" /* script */
3594 "(-([a-z][a-z]|[0-9][0-9][0-9])){0,1}" /* region */
3595 "(-([a-z]{5,8}|[0-9][0-9][0-9]))*" /* variant */
3596 "(-[a-wy-z](-[a-z0-9]{2,8})+)*" /* extension */
3597 "(-x(-[a-z0-9]{1,8})+)*" /* privateuse */
3599 "x(-[a-z0-9]{1,8})+" /* privateuse */
3601 "[a-z]{1,3}(-[a-z][0-9]{2,8}){1,2}" /* grandfathered */
3603 REG_NOSUB
| REG_EXTENDED
)) != 0)
3605 char temp
[256]; /* Temporary error string */
3607 regerror(i
, &re
, temp
, sizeof(temp
));
3608 print_fatal_error("Unable to compile naturalLanguage regular "
3609 "expression: %s.", temp
);
3612 for (i
= 0; i
< attr
->num_values
; i
++)
3614 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
3619 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
3620 "characters (RFC 2911 section 4.1.8).",
3621 attr
->name
, attr
->values
[i
].string
.text
);
3626 if (strlen(attr
->values
[i
].string
.text
) > 63)
3631 print_test_error("\"%s\": Bad naturalLanguage value \"%s\" - bad "
3632 "length %d (RFC 2911 section 4.1.8).",
3633 attr
->name
, attr
->values
[i
].string
.text
,
3634 (int)strlen(attr
->values
[i
].string
.text
));
3643 case IPP_TAG_MIMETYPE
:
3645 * The following regular expression is derived from the ABNF for
3646 * language tags in RFC 2045 and 4288. All I can say is that this is
3647 * the easiest way to check the values...
3650 if ((i
= regcomp(&re
,
3652 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* type-name */
3654 "[-a-zA-Z0-9!#$&.+^_]{1,127}" /* subtype-name */
3655 "(;[-a-zA-Z0-9!#$&.+^_]{1,127}=" /* parameter= */
3656 "([-a-zA-Z0-9!#$&.+^_]{1,127}|\"[^\"]*\"))*"
3659 REG_NOSUB
| REG_EXTENDED
)) != 0)
3661 char temp
[256]; /* Temporary error string */
3663 regerror(i
, &re
, temp
, sizeof(temp
));
3664 print_fatal_error("Unable to compile mimeMediaType regular "
3665 "expression: %s.", temp
);
3668 for (i
= 0; i
< attr
->num_values
; i
++)
3670 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
3675 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
3676 "characters (RFC 2911 section 4.1.9).",
3677 attr
->name
, attr
->values
[i
].string
.text
);
3682 if (strlen(attr
->values
[i
].string
.text
) > 255)
3687 print_test_error("\"%s\": Bad mimeMediaType value \"%s\" - bad "
3688 "length %d (RFC 2911 section 4.1.9).",
3689 attr
->name
, attr
->values
[i
].string
.text
,
3690 (int)strlen(attr
->values
[i
].string
.text
));
3706 * 'with_value()' - Test a WITH-VALUE predicate.
3709 static int /* O - 1 on match, 0 on non-match */
3710 with_value(char *value
, /* I - Value string */
3711 int regex
, /* I - Value is a regular expression */
3712 ipp_attribute_t
*attr
) /* I - Attribute to compare */
3714 int i
; /* Looping var */
3715 char *valptr
; /* Pointer into value */
3719 * NULL matches everything.
3722 if (!value
|| !*value
)
3726 * Compare the value string to the attribute value.
3729 switch (attr
->value_tag
)
3731 case IPP_TAG_INTEGER
:
3733 for (i
= 0; i
< attr
->num_values
; i
++)
3735 char op
, /* Comparison operator */
3736 *nextptr
; /* Next pointer */
3737 int intvalue
; /* Integer value */
3741 if (!strncmp(valptr
, "no-value,", 9))
3744 while (isspace(*valptr
& 255) || isdigit(*valptr
& 255) ||
3745 *valptr
== '-' || *valptr
== ',' || *valptr
== '<' ||
3746 *valptr
== '=' || *valptr
== '>')
3749 while (*valptr
&& !isdigit(*valptr
& 255) && *valptr
!= '-')
3751 if (*valptr
== '<' || *valptr
== '>' || *valptr
== '=')
3759 intvalue
= strtol(valptr
, &nextptr
, 0);
3760 if (nextptr
== valptr
)
3767 if (attr
->values
[i
].integer
== intvalue
)
3771 if (attr
->values
[i
].integer
< intvalue
)
3775 if (attr
->values
[i
].integer
> intvalue
)
3783 case IPP_TAG_BOOLEAN
:
3784 for (i
= 0; i
< attr
->num_values
; i
++)
3786 if (!strcmp(value
, "true") == attr
->values
[i
].boolean
)
3791 case IPP_TAG_NOVALUE
:
3792 return (!strcmp(value
, "no-value") || !strncmp(value
, "no-value,", 9));
3794 case IPP_TAG_CHARSET
:
3795 case IPP_TAG_KEYWORD
:
3796 case IPP_TAG_LANGUAGE
:
3797 case IPP_TAG_MIMETYPE
:
3799 case IPP_TAG_NAMELANG
:
3801 case IPP_TAG_TEXTLANG
:
3803 case IPP_TAG_URISCHEME
:
3807 * Value is an extended, case-sensitive POSIX regular expression...
3810 regex_t re
; /* Regular expression */
3812 if ((i
= regcomp(&re
, value
, REG_EXTENDED
| REG_NOSUB
)) != 0)
3814 char temp
[256]; /* Temporary string */
3816 regerror(i
, &re
, temp
, sizeof(temp
));
3818 print_fatal_error("Unable to compile WITH-VALUE regular expression "
3819 "\"%s\" - %s", value
, temp
);
3824 * See if ALL of the values match the given regular expression.
3827 for (i
= 0; i
< attr
->num_values
; i
++)
3829 if (regexec(&re
, attr
->values
[i
].string
.text
, 0, NULL
, 0))
3835 return (i
== attr
->num_values
);
3840 * Value is a literal string, see if at least one value matches the
3844 for (i
= 0; i
< attr
->num_values
; i
++)
3846 if (!strcmp(value
, attr
->values
[i
].string
.text
))
3861 * End of "$Id: ipptest.c 9000 2010-02-24 06:29:38Z mike $".