]> git.ipfire.org Git - thirdparty/cups.git/blob - test/ipptest.c
Merge changes from CUPS 1.5svn-r8933.
[thirdparty/cups.git] / test / ipptest.c
1 /*
2 * "$Id: ipptest.c 7847 2008-08-19 04:22:14Z mike $"
3 *
4 * IPP test command for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
8 *
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/".
14 *
15 * Contents:
16 *
17 * main() - Parse options and do tests.
18 * do_tests() - Do tests as specified in the test file.
19 * expect_matches() - Return true if the tag matches the specification.
20 * get_token() - Get a token from a file.
21 * print_attr() - Print an attribute on the screen.
22 * print_col() - Print a collection attribute on the screen.
23 * usage() - Show program usage.
24 */
25
26 /*
27 * Include necessary headers...
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <cups/string.h>
33 #include <errno.h>
34 #include <ctype.h>
35
36 #include <cups/cups.h>
37 #include <cups/language.h>
38 #include <cups/http-private.h>
39 #ifndef O_BINARY
40 # define O_BINARY 0
41 #endif /* !O_BINARY */
42
43
44 /*
45 * Types...
46 */
47
48 typedef struct _cups_expect_s /**** Expected attribute info ****/
49 {
50 int not_expect; /* Don't expect attribute? */
51 char *name, /* Attribute name */
52 *of_type, /* Type name */
53 *same_count_as, /* Parallel attribute name */
54 *if_defined; /* Only required if variable defined */
55 } _cups_expect_t;
56
57
58 /*
59 * Globals...
60 */
61
62 int Chunking = 0; /* Use chunked requests */
63 int Verbosity = 0; /* Show all attributes? */
64
65
66 /*
67 * Local functions...
68 */
69
70 static int do_tests(const char *uri, const char *testfile);
71 static int expect_matches(_cups_expect_t *expect, ipp_tag_t value_tag);
72 static char *get_token(FILE *fp, char *buf, int buflen,
73 int *linenum);
74 static void print_attr(ipp_attribute_t *attr);
75 static void print_col(ipp_t *col);
76 static void usage(void);
77
78
79 /*
80 * 'main()' - Parse options and do tests.
81 */
82
83 int /* O - Exit status */
84 main(int argc, /* I - Number of command-line args */
85 char *argv[]) /* I - Command-line arguments */
86 {
87 int i; /* Looping var */
88 int status; /* Status of tests... */
89 char *opt; /* Current option */
90 const char *uri, /* URI to use */
91 *testfile; /* Test file to use */
92 int interval; /* Test interval */
93
94
95 /*
96 * We need at least:
97 *
98 * testipp URL testfile
99 */
100
101 uri = NULL;
102 testfile = NULL;
103 status = 0;
104 interval = 0;
105
106 for (i = 1; i < argc; i ++)
107 {
108 if (argv[i][0] == '-')
109 {
110 for (opt = argv[i] + 1; *opt; opt ++)
111 {
112 switch (*opt)
113 {
114 case 'c' : /* Enable HTTP chunking */
115 Chunking = 1;
116 break;
117
118 case 'd' : /* Define a variable */
119 i ++;
120
121 if (i >= argc)
122 {
123 fputs("ipptest: Missing name=value for \"-d\"!\n", stderr);
124 usage();
125 }
126 else
127 putenv(argv[i]);
128 break;
129
130 case 'i' : /* Test every N seconds */
131 i++;
132
133 if (i >= argc)
134 {
135 fputs("ipptest: Missing seconds for \"-i\"!\n", stderr);
136 usage();
137 }
138 else
139 interval = atoi(argv[i]);
140 break;
141
142 case 'v' : /* Be verbose */
143 Verbosity ++;
144 break;
145
146 default :
147 fprintf(stderr, "ipptest: Unknown option \"-%c\"!\n", *opt);
148 usage();
149 break;
150 }
151 }
152 }
153 else if (!strncmp(argv[i], "ipp://", 6) ||
154 !strncmp(argv[i], "http://", 7) ||
155 !strncmp(argv[i], "https://", 8))
156 {
157 /*
158 * Set URI...
159 */
160
161 if (!testfile && uri)
162 {
163 fputs("ipptest: May only specify a single URI before a test!\n",
164 stderr);
165 usage();
166 }
167
168 uri = argv[i];
169 testfile = NULL;
170 }
171 else
172 {
173 /*
174 * Run test...
175 */
176
177 testfile = argv[i];
178
179 if (!do_tests(uri, testfile))
180 status ++;
181 }
182 }
183
184 if (!uri || !testfile)
185 usage();
186
187 /*
188 * Loop if the interval is set...
189 */
190
191 if (interval)
192 {
193 for (;;)
194 {
195 sleep(interval);
196 do_tests(uri, testfile);
197 }
198 }
199
200 /*
201 * Exit...
202 */
203
204 return (status);
205 }
206
207
208 /*
209 * 'do_tests()' - Do tests as specified in the test file.
210 */
211
212 static int /* 1 = success, 0 = failure */
213 do_tests(const char *uri, /* I - URI to connect on */
214 const char *testfile) /* I - Test file to use */
215 {
216 int i; /* Looping var */
217 int linenum; /* Current line number */
218 int version; /* IPP version number to use */
219 http_t *http; /* HTTP connection to server */
220 char scheme[HTTP_MAX_URI], /* URI scheme */
221 userpass[HTTP_MAX_URI], /* username:password */
222 server[HTTP_MAX_URI], /* Server */
223 resource[HTTP_MAX_URI]; /* Resource path */
224 int port; /* Port number */
225 FILE *fp; /* Test file */
226 char token[1024], /* Token from file */
227 *tokenptr, /* Pointer into token */
228 temp[1024], /* Temporary string */
229 *tempptr; /* Pointer into temp string */
230 ipp_t *request; /* IPP request */
231 ipp_t *response; /* IPP response */
232 ipp_op_t op; /* Operation */
233 ipp_tag_t group; /* Current group */
234 ipp_tag_t value; /* Current value type */
235 ipp_attribute_t *attrptr, /* Attribute pointer */
236 *found; /* Found attribute */
237 char attr[128]; /* Attribute name */
238 int num_statuses; /* Number of valid status codes */
239 ipp_status_t statuses[100]; /* Valid status codes */
240 int num_expects; /* Number of expected attributes */
241 _cups_expect_t expects[100], /* Expected attributes */
242 *expect, /* Current expected attribute */
243 *last_expect; /* Last EXPECT (for predicates) */
244 int num_displayed; /* Number of displayed attributes */
245 char *displayed[100]; /* Displayed attributes */
246 char name[1024]; /* Name of test */
247 char filename[1024]; /* Filename */
248 int pass; /* Did we pass the test? */
249 int job_id; /* Job ID from last operation */
250 int subscription_id; /* Subscription ID from last operation */
251
252
253 /*
254 * Open the test file...
255 */
256
257 if ((fp = fopen(testfile, "r")) == NULL)
258 {
259 printf("Unable to open test file %s - %s\n", testfile, strerror(errno));
260 return (0);
261 }
262
263 /*
264 * Connect to the server...
265 */
266
267 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
268 sizeof(userpass), server, sizeof(server), &port, resource,
269 sizeof(resource));
270 if ((http = httpConnect(server, port)) == NULL)
271 {
272 printf("Unable to connect to %s on port %d - %s\n", server, port,
273 strerror(errno));
274 fclose(fp);
275 return (0);
276 }
277
278 /*
279 * Loop on tests...
280 */
281
282 printf("\"%s\":\n", testfile);
283 pass = 1;
284 job_id = 0;
285 subscription_id = 0;
286 version = 11;
287 linenum = 1;
288
289 while (get_token(fp, token, sizeof(token), &linenum) != NULL)
290 {
291 /*
292 * Expect an open brace...
293 */
294
295 if (strcmp(token, "{"))
296 {
297 printf("Unexpected token %s seen on line %d - aborting test!\n", token,
298 linenum);
299 httpClose(http);
300 return (0);
301 }
302
303 /*
304 * Initialize things...
305 */
306
307 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
308 sizeof(userpass), server, sizeof(server), &port, resource,
309 sizeof(resource));
310
311 request = ippNew();
312 op = (ipp_op_t)0;
313 group = IPP_TAG_ZERO;
314 num_statuses = 0;
315 num_expects = 0;
316 num_displayed = 0;
317 last_expect = NULL;
318 filename[0] = '\0';
319
320 strcpy(name, testfile);
321 if (strrchr(name, '.') != NULL)
322 *strrchr(name, '.') = '\0';
323
324 /*
325 * Parse until we see a close brace...
326 */
327
328 while (get_token(fp, token, sizeof(token), &linenum) != NULL)
329 {
330 if (strcasecmp(token, "EXPECT") &&
331 strcasecmp(token, "IF-DEFINED") &&
332 strcasecmp(token, "OF-TYPE") &&
333 strcasecmp(token, "SAME-COUNT-AS"))
334 last_expect = NULL;
335
336 if (!strcmp(token, "}"))
337 break;
338 else if (!strcasecmp(token, "NAME"))
339 {
340 /*
341 * Name of test...
342 */
343
344 get_token(fp, name, sizeof(name), &linenum);
345 }
346 else if (!strcasecmp(token, "VERSION"))
347 {
348 /*
349 * IPP version number for test...
350 */
351
352 int major, minor; /* Major/minor IPP version */
353
354
355 get_token(fp, temp, sizeof(temp), &linenum);
356 if (sscanf(temp, "%d.%d", &major, &minor) == 2 &&
357 major >= 0 && minor >= 0 && minor < 10)
358 version = major * 10 + minor;
359 else
360 {
361 printf("Bad version %s seen on line %d - aborting test!\n", token,
362 linenum);
363 httpClose(http);
364 ippDelete(request);
365 return (0);
366 }
367 }
368 else if (!strcasecmp(token, "RESOURCE"))
369 {
370 /*
371 * Resource name...
372 */
373
374 get_token(fp, resource, sizeof(resource), &linenum);
375 }
376 else if (!strcasecmp(token, "OPERATION"))
377 {
378 /*
379 * Operation...
380 */
381
382 get_token(fp, token, sizeof(token), &linenum);
383 op = ippOpValue(token);
384 }
385 else if (!strcasecmp(token, "GROUP"))
386 {
387 /*
388 * Attribute group...
389 */
390
391 get_token(fp, token, sizeof(token), &linenum);
392 value = ippTagValue(token);
393
394 if (value == group)
395 ippAddSeparator(request);
396
397 group = value;
398 }
399 else if (!strcasecmp(token, "DELAY"))
400 {
401 /*
402 * Delay before operation...
403 */
404
405 int delay;
406
407 get_token(fp, token, sizeof(token), &linenum);
408 if ((delay = atoi(token)) > 0)
409 sleep(delay);
410 }
411 else if (!strcasecmp(token, "ATTR"))
412 {
413 /*
414 * Attribute...
415 */
416
417 get_token(fp, token, sizeof(token), &linenum);
418 value = ippTagValue(token);
419 get_token(fp, attr, sizeof(attr), &linenum);
420 get_token(fp, temp, sizeof(temp), &linenum);
421
422 token[sizeof(token) - 1] = '\0';
423
424 for (tempptr = temp, tokenptr = token;
425 *tempptr && tokenptr < (token + sizeof(token) - 1);)
426 if (*tempptr == '$')
427 {
428 /*
429 * Substitute a string/number...
430 */
431
432 if (!strncasecmp(tempptr + 1, "uri", 3))
433 {
434 strlcpy(tokenptr, uri, sizeof(token) - (tokenptr - token));
435 tempptr += 4;
436 }
437 else if (!strncasecmp(tempptr + 1, "scheme", 6) ||
438 !strncasecmp(tempptr + 1, "method", 6))
439 {
440 strlcpy(tokenptr, scheme, sizeof(token) - (tokenptr - token));
441 tempptr += 7;
442 }
443 else if (!strncasecmp(tempptr + 1, "username", 8))
444 {
445 strlcpy(tokenptr, userpass, sizeof(token) - (tokenptr - token));
446 tempptr += 9;
447 }
448 else if (!strncasecmp(tempptr + 1, "hostname", 8))
449 {
450 strlcpy(tokenptr, server, sizeof(token) - (tokenptr - token));
451 tempptr += 9;
452 }
453 else if (!strncasecmp(tempptr + 1, "port", 4))
454 {
455 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
456 "%d", port);
457 tempptr += 5;
458 }
459 else if (!strncasecmp(tempptr + 1, "resource", 8))
460 {
461 strlcpy(tokenptr, resource, sizeof(token) - (tokenptr - token));
462 tempptr += 9;
463 }
464 else if (!strncasecmp(tempptr + 1, "job-id", 6))
465 {
466 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
467 "%d", job_id);
468 tempptr += 7;
469 }
470 else if (!strncasecmp(tempptr + 1, "notify-subscription-id", 22))
471 {
472 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
473 "%d", subscription_id);
474 tempptr += 23;
475 }
476 else if (!strncasecmp(tempptr + 1, "user", 4))
477 {
478 strlcpy(tokenptr, cupsUser(), sizeof(token) - (tokenptr - token));
479 tempptr += 5;
480 }
481 else if (!strncasecmp(tempptr + 1, "ENV[", 4))
482 {
483 char *end; /* End of $ENV[name] */
484
485
486 if ((end = strchr(tempptr + 5, ']')) != NULL)
487 {
488 *end++ = '\0';
489 strlcpy(tokenptr,
490 getenv(tempptr + 5) ? getenv(tempptr + 5) : tempptr + 5,
491 sizeof(token) - (tokenptr - token));
492 tempptr = end;
493 }
494 else
495 {
496 *tokenptr++ = *tempptr++;
497 *tokenptr = '\0';
498 }
499 }
500 else
501 {
502 *tokenptr++ = *tempptr++;
503 *tokenptr = '\0';
504 }
505
506 tokenptr += strlen(tokenptr);
507 }
508 else
509 {
510 *tokenptr++ = *tempptr++;
511 *tokenptr = '\0';
512 }
513
514 switch (value)
515 {
516 case IPP_TAG_BOOLEAN :
517 if (!strcasecmp(token, "true"))
518 ippAddBoolean(request, group, attr, 1);
519 else
520 ippAddBoolean(request, group, attr, atoi(token));
521 break;
522
523 case IPP_TAG_INTEGER :
524 case IPP_TAG_ENUM :
525 ippAddInteger(request, group, value, attr, atoi(token));
526 break;
527
528 case IPP_TAG_RESOLUTION :
529 puts(" ERROR: resolution tag not yet supported!");
530 break;
531
532 case IPP_TAG_RANGE :
533 puts(" ERROR: range tag not yet supported!");
534 break;
535
536 default :
537 if (!strchr(token, ','))
538 ippAddString(request, group, value, attr, NULL, token);
539 else
540 {
541 /*
542 * Multiple string values...
543 */
544
545 int num_values; /* Number of values */
546 char *values[100], /* Values */
547 *ptr; /* Pointer to next value */
548
549
550 values[0] = token;
551 num_values = 1;
552
553 for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ','))
554 {
555 *ptr++ = '\0';
556 values[num_values] = ptr;
557 num_values ++;
558 }
559
560 ippAddStrings(request, group, value, attr, num_values,
561 NULL, (const char **)values);
562 }
563 break;
564 }
565 }
566 else if (!strcasecmp(token, "FILE"))
567 {
568 /*
569 * File...
570 */
571
572 get_token(fp, filename, sizeof(filename), &linenum);
573 }
574 else if (!strcasecmp(token, "STATUS") &&
575 num_statuses < (int)(sizeof(statuses) / sizeof(statuses[0])))
576 {
577 /*
578 * Status...
579 */
580
581 get_token(fp, token, sizeof(token), &linenum);
582 statuses[num_statuses] = ippErrorValue(token);
583 num_statuses ++;
584 }
585 else if (!strcasecmp(token, "EXPECT"))
586 {
587 /*
588 * Expected attributes...
589 */
590
591 if (num_expects >= (int)(sizeof(expects) / sizeof(expects[0])))
592 {
593 fprintf(stderr, "ipptest: Too many EXPECT's on line %d\n", linenum);
594 httpClose(http);
595 ippDelete(request);
596 return (0);
597 }
598
599 get_token(fp, token, sizeof(token), &linenum);
600
601 last_expect = expects + num_expects;
602 num_expects ++;
603
604 if (token[0] == '!')
605 {
606 last_expect->not_expect = 1;
607 last_expect->name = strdup(token + 1);
608 }
609 else
610 {
611 last_expect->not_expect = 0;
612 last_expect->name = strdup(token);
613 }
614
615 last_expect->of_type = NULL;
616 last_expect->same_count_as = NULL;
617 last_expect->if_defined = NULL;
618 }
619 else if (!strcasecmp(token, "OF-TYPE"))
620 {
621 get_token(fp, token, sizeof(token), &linenum);
622
623 if (last_expect)
624 last_expect->of_type = strdup(token);
625 else
626 {
627 fprintf(stderr,
628 "ipptest: OF-TYPE without a preceding EXPECT on line %d\n",
629 linenum);
630 httpClose(http);
631 ippDelete(request);
632 return (0);
633 }
634 }
635 else if (!strcasecmp(token, "SAME-COUNT-AS"))
636 {
637 get_token(fp, token, sizeof(token), &linenum);
638
639 if (last_expect)
640 last_expect->same_count_as = strdup(token);
641 else
642 {
643 fprintf(stderr,
644 "ipptest: SAME-COUNT-AS without a preceding EXPECT on line "
645 "%d\n", linenum);
646 httpClose(http);
647 ippDelete(request);
648 return (0);
649 }
650 }
651 else if (!strcasecmp(token, "IF-DEFINED"))
652 {
653 get_token(fp, token, sizeof(token), &linenum);
654
655 if (last_expect)
656 last_expect->if_defined = strdup(token);
657 else
658 {
659 fprintf(stderr,
660 "ipptest: IF-DEFINED without a preceding EXPECT on line %d\n",
661 linenum);
662 httpClose(http);
663 ippDelete(request);
664 return (0);
665 }
666 }
667 else if (!strcasecmp(token, "DISPLAY") &&
668 num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0])))
669 {
670 /*
671 * Display attributes...
672 */
673
674 get_token(fp, token, sizeof(token), &linenum);
675 displayed[num_displayed] = strdup(token);
676 num_displayed ++;
677 }
678 else
679 {
680 fprintf(stderr,
681 "ipptest: Unexpected token %s seen on line %d - aborting "
682 "test!\n", token, linenum);
683 httpClose(http);
684 ippDelete(request);
685 return (0);
686 }
687 }
688
689 /*
690 * Submit the IPP request...
691 */
692
693 request->request.op.version[0] = version / 10;
694 request->request.op.version[1] = version % 10;
695 request->request.op.operation_id = op;
696 request->request.op.request_id = 1;
697
698 if (Verbosity)
699 {
700 printf(" %s:\n", ippOpString(op));
701
702 for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
703 print_attr(attrptr);
704 }
705
706 printf(" %-60.60s [", name);
707 fflush(stdout);
708
709 if (Chunking)
710 {
711 http_status_t status = cupsSendRequest(http, request, resource, 0);
712
713 if (status == HTTP_CONTINUE && filename[0])
714 {
715 int fd; /* File to send */
716 char buffer[8192]; /* Copy buffer */
717 ssize_t bytes; /* Bytes read/written */
718
719
720 if ((fd = open(filename, O_RDONLY | O_BINARY)) >= 0)
721 {
722 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
723 if ((status = cupsWriteRequestData(http, buffer,
724 bytes)) != HTTP_CONTINUE)
725 break;
726 }
727 else
728 status = HTTP_ERROR;
729 }
730
731 ippDelete(request);
732
733 if (status == HTTP_CONTINUE)
734 response = cupsGetResponse(http, resource);
735 else
736 response = NULL;
737 }
738 else if (filename[0])
739 response = cupsDoFileRequest(http, request, resource, filename);
740 else
741 response = cupsDoIORequest(http, request, resource, -1,
742 Verbosity ? 1 : -1);
743
744 if (response == NULL)
745 {
746 time_t curtime;
747
748 curtime = time(NULL);
749
750 puts("FAIL]");
751 printf(" ERROR %04x (%s) @ %s\n", cupsLastError(),
752 cupsLastErrorString(), ctime(&curtime));
753 pass = 0;
754 }
755 else
756 {
757 if (http->version != HTTP_1_1)
758 pass = 0;
759
760 if ((attrptr = ippFindAttribute(response, "job-id",
761 IPP_TAG_INTEGER)) != NULL)
762 job_id = attrptr->values[0].integer;
763
764 if ((attrptr = ippFindAttribute(response, "notify-subscription-id",
765 IPP_TAG_INTEGER)) != NULL)
766 subscription_id = attrptr->values[0].integer;
767
768 for (i = 0; i < num_statuses; i ++)
769 if (response->request.status.status_code == statuses[i])
770 break;
771
772 if (i == num_statuses && num_statuses > 0)
773 pass = 0;
774 else
775 {
776 for (i = num_expects, expect = expects; i > 0; i --, expect ++)
777 {
778 if (expect->if_defined && !getenv(expect->if_defined))
779 continue;
780
781 found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
782
783 if ((found == NULL) != expect->not_expect ||
784 (found && !expect_matches(expect, found->value_tag)))
785 {
786 pass = 0;
787 break;
788 }
789
790 if (found && expect->same_count_as)
791 {
792 attrptr = ippFindAttribute(response, expect->same_count_as,
793 IPP_TAG_ZERO);
794
795 if (!attrptr || attrptr->num_values != found->num_values)
796 {
797 pass = 0;
798 break;
799 }
800 }
801 }
802 }
803
804 if (pass)
805 {
806 puts("PASS]");
807 printf(" RECEIVED: %lu bytes in response\n",
808 (unsigned long)ippLength(response));
809
810 if (Verbosity)
811 {
812 for (attrptr = response->attrs;
813 attrptr != NULL;
814 attrptr = attrptr->next)
815 {
816 print_attr(attrptr);
817 }
818 }
819 else if (num_displayed > 0)
820 {
821 for (attrptr = response->attrs;
822 attrptr != NULL;
823 attrptr = attrptr->next)
824 {
825 if (attrptr->name)
826 {
827 for (i = 0; i < num_displayed; i ++)
828 {
829 if (!strcmp(displayed[i], attrptr->name))
830 {
831 print_attr(attrptr);
832 break;
833 }
834 }
835 }
836 }
837 }
838 }
839 else
840 {
841 puts("FAIL]");
842 printf(" RECEIVED: %lu bytes in response\n",
843 (unsigned long)ippLength(response));
844
845 if (http->version != HTTP_1_1)
846 printf(" BAD HTTP VERSION (%d.%d)\n", http->version / 100,
847 http->version % 100);
848
849 for (i = 0; i < num_statuses; i ++)
850 if (response->request.status.status_code == statuses[i])
851 break;
852
853 if (i == num_statuses && num_statuses > 0)
854 puts(" BAD STATUS");
855
856 printf(" status-code = %04x (%s)\n",
857 cupsLastError(), ippErrorString(cupsLastError()));
858
859 for (i = num_expects, expect = expects; i > 0; i --, expect ++)
860 {
861 if (expect->if_defined && !getenv(expect->if_defined))
862 continue;
863
864 found = ippFindAttribute(response, expect->name, IPP_TAG_ZERO);
865
866 if ((found == NULL) != expect->not_expect)
867 {
868 if (expect->not_expect)
869 printf(" NOT EXPECTED: %s\n", expect->name);
870 else
871 printf(" EXPECTED: %s\n", expect->name);
872 }
873 else if (found)
874 {
875 if (!expect_matches(expect, found->value_tag))
876 printf(" EXPECTED: %s of type %s but got %s\n",
877 expect->name, expect->of_type,
878 ippTagString(found->value_tag));
879 else if (expect->same_count_as)
880 {
881 attrptr = ippFindAttribute(response, expect->same_count_as,
882 IPP_TAG_ZERO);
883
884 if (!attrptr)
885 printf(" EXPECTED: %s (%d values) same count as %s "
886 "(not returned)\n",
887 expect->name, found->num_values, expect->same_count_as);
888 else if (attrptr->num_values != found->num_values)
889 printf(" EXPECTED: %s (%d values) same count as %s "
890 "(%d values)\n",
891 expect->name, found->num_values, expect->same_count_as,
892 attrptr->num_values);
893 }
894 }
895 }
896
897 for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
898 print_attr(attrptr);
899 }
900
901 ippDelete(response);
902 }
903
904 for (i = num_expects, expect = expects; i > 0; i --, expect ++)
905 {
906 free(expect->name);
907 if (expect->of_type)
908 free(expect->of_type);
909 if (expect->same_count_as)
910 free(expect->same_count_as);
911 if (expect->if_defined)
912 free(expect->if_defined);
913 }
914 if (!pass)
915 break;
916 }
917
918 fclose(fp);
919 httpClose(http);
920
921 return (pass);
922 }
923
924
925 /*
926 * 'expect_matches()' - Return true if the tag matches the specification.
927 */
928
929 static int /* O - 1 if matches, 0 otherwise */
930 expect_matches(
931 _cups_expect_t *expect, /* I - Expected attribute */
932 ipp_tag_t value_tag) /* I - Value tag for attribute */
933 {
934 int match; /* Match? */
935 char *of_type, /* Type name to match */
936 *next; /* Next name to match */
937
938
939 /*
940 * If we don't expect a particular type, return immediately...
941 */
942
943 if (!expect->of_type)
944 return (1);
945
946 /*
947 * Parse the "of_type" value since the string can contain multiple attribute
948 * types separated by "|"...
949 */
950
951 for (of_type = expect->of_type, match = 0; !match && of_type; of_type = next)
952 {
953 /*
954 * Find the next separator, and set it (temporarily) to nul if present.
955 */
956
957 if ((next = strchr(of_type, '|')) != NULL)
958 *next = '\0';
959
960 /*
961 * Support some meta-types to make it easier to write the test file.
962 */
963
964 if (!strcmp(of_type, "text"))
965 match = value_tag == IPP_TAG_TEXTLANG || value_tag == IPP_TAG_TEXT;
966 else if (!strcmp(of_type, "name"))
967 match = value_tag == IPP_TAG_NAMELANG || value_tag == IPP_TAG_NAME;
968 else if (!strcmp(of_type, "collection"))
969 match = value_tag == IPP_TAG_BEGIN_COLLECTION;
970 else
971 match = value_tag == ippTagValue(of_type);
972
973 /*
974 * Restore the separator if we have one...
975 */
976
977 if (next)
978 *next++ = '|';
979 }
980
981 return (match);
982 }
983
984
985 /*
986 * 'get_token()' - Get a token from a file.
987 */
988
989 static char * /* O - Token from file or NULL on EOF */
990 get_token(FILE *fp, /* I - File to read from */
991 char *buf, /* I - Buffer to read into */
992 int buflen, /* I - Length of buffer */
993 int *linenum) /* IO - Current line number */
994 {
995 int ch, /* Character from file */
996 quote; /* Quoting character */
997 char *bufptr, /* Pointer into buffer */
998 *bufend; /* End of buffer */
999
1000
1001 for (;;)
1002 {
1003 /*
1004 * Skip whitespace...
1005 */
1006
1007 while (isspace(ch = getc(fp)))
1008 {
1009 if (ch == '\n')
1010 (*linenum) ++;
1011 }
1012
1013 /*
1014 * Read a token...
1015 */
1016
1017 if (ch == EOF)
1018 return (NULL);
1019 else if (ch == '\'' || ch == '\"')
1020 {
1021 /*
1022 * Quoted text...
1023 */
1024
1025 quote = ch;
1026 bufptr = buf;
1027 bufend = buf + buflen - 1;
1028
1029 while ((ch = getc(fp)) != EOF)
1030 if (ch == quote)
1031 break;
1032 else if (bufptr < bufend)
1033 *bufptr++ = ch;
1034
1035 *bufptr = '\0';
1036 return (buf);
1037 }
1038 else if (ch == '#')
1039 {
1040 /*
1041 * Comment...
1042 */
1043
1044 while ((ch = getc(fp)) != EOF)
1045 if (ch == '\n')
1046 break;
1047
1048 (*linenum) ++;
1049 }
1050 else
1051 {
1052 /*
1053 * Whitespace delimited text...
1054 */
1055
1056 ungetc(ch, fp);
1057
1058 bufptr = buf;
1059 bufend = buf + buflen - 1;
1060
1061 while ((ch = getc(fp)) != EOF)
1062 if (isspace(ch) || ch == '#')
1063 break;
1064 else if (bufptr < bufend)
1065 *bufptr++ = ch;
1066
1067 if (ch == '#')
1068 ungetc(ch, fp);
1069
1070 *bufptr = '\0';
1071 return (buf);
1072 }
1073 }
1074 }
1075
1076
1077 /*
1078 * 'print_attr()' - Print an attribute on the screen.
1079 */
1080
1081 static void
1082 print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
1083 {
1084 int i; /* Looping var */
1085
1086
1087 if (attr->name == NULL)
1088 {
1089 puts(" -- separator --");
1090 return;
1091 }
1092
1093 printf(" %s (%s%s) = ", attr->name,
1094 attr->num_values > 1 ? "1setOf " : "",
1095 ippTagString(attr->value_tag));
1096
1097 switch (attr->value_tag)
1098 {
1099 case IPP_TAG_INTEGER :
1100 case IPP_TAG_ENUM :
1101 for (i = 0; i < attr->num_values; i ++)
1102 printf("%d ", attr->values[i].integer);
1103 break;
1104
1105 case IPP_TAG_BOOLEAN :
1106 for (i = 0; i < attr->num_values; i ++)
1107 if (attr->values[i].boolean)
1108 printf("true ");
1109 else
1110 printf("false ");
1111 break;
1112
1113 case IPP_TAG_NOVALUE :
1114 printf("novalue");
1115 break;
1116
1117 case IPP_TAG_RANGE :
1118 for (i = 0; i < attr->num_values; i ++)
1119 printf("%d-%d ", attr->values[i].range.lower,
1120 attr->values[i].range.upper);
1121 break;
1122
1123 case IPP_TAG_RESOLUTION :
1124 for (i = 0; i < attr->num_values; i ++)
1125 printf("%dx%d%s ", attr->values[i].resolution.xres,
1126 attr->values[i].resolution.yres,
1127 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
1128 "dpi" : "dpc");
1129 break;
1130
1131 case IPP_TAG_STRING :
1132 case IPP_TAG_TEXT :
1133 case IPP_TAG_NAME :
1134 case IPP_TAG_KEYWORD :
1135 case IPP_TAG_CHARSET :
1136 case IPP_TAG_URI :
1137 case IPP_TAG_MIMETYPE :
1138 case IPP_TAG_LANGUAGE :
1139 for (i = 0; i < attr->num_values; i ++)
1140 printf("\"%s\" ", attr->values[i].string.text);
1141 break;
1142
1143 case IPP_TAG_TEXTLANG :
1144 case IPP_TAG_NAMELANG :
1145 for (i = 0; i < attr->num_values; i ++)
1146 printf("\"%s\",%s ", attr->values[i].string.text,
1147 attr->values[i].string.charset);
1148 break;
1149
1150 case IPP_TAG_BEGIN_COLLECTION :
1151 for (i = 0; i < attr->num_values; i ++)
1152 {
1153 if (i)
1154 putchar(' ');
1155
1156 print_col(attr->values[i].collection);
1157 }
1158 break;
1159
1160 default :
1161 break; /* anti-compiler-warning-code */
1162 }
1163
1164 putchar('\n');
1165 }
1166
1167
1168 /*
1169 * 'print_col()' - Print a collection attribute on the screen.
1170 */
1171
1172 static void
1173 print_col(ipp_t *col) /* I - Collection attribute to print */
1174 {
1175 int i; /* Looping var */
1176 ipp_attribute_t *attr; /* Current attribute in collection */
1177
1178
1179 putchar('{');
1180 for (attr = col->attrs; attr; attr = attr->next)
1181 {
1182 printf("%s(%s%s)=", attr->name, attr->num_values > 1 ? "1setOf " : "",
1183 ippTagString(attr->value_tag));
1184
1185 switch (attr->value_tag)
1186 {
1187 case IPP_TAG_INTEGER :
1188 case IPP_TAG_ENUM :
1189 for (i = 0; i < attr->num_values; i ++)
1190 printf("%d ", attr->values[i].integer);
1191 break;
1192
1193 case IPP_TAG_BOOLEAN :
1194 for (i = 0; i < attr->num_values; i ++)
1195 if (attr->values[i].boolean)
1196 printf("true ");
1197 else
1198 printf("false ");
1199 break;
1200
1201 case IPP_TAG_NOVALUE :
1202 printf("novalue");
1203 break;
1204
1205 case IPP_TAG_RANGE :
1206 for (i = 0; i < attr->num_values; i ++)
1207 printf("%d-%d ", attr->values[i].range.lower,
1208 attr->values[i].range.upper);
1209 break;
1210
1211 case IPP_TAG_RESOLUTION :
1212 for (i = 0; i < attr->num_values; i ++)
1213 printf("%dx%d%s ", attr->values[i].resolution.xres,
1214 attr->values[i].resolution.yres,
1215 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
1216 "dpi" : "dpc");
1217 break;
1218
1219 case IPP_TAG_STRING :
1220 case IPP_TAG_TEXT :
1221 case IPP_TAG_NAME :
1222 case IPP_TAG_KEYWORD :
1223 case IPP_TAG_CHARSET :
1224 case IPP_TAG_URI :
1225 case IPP_TAG_MIMETYPE :
1226 case IPP_TAG_LANGUAGE :
1227 for (i = 0; i < attr->num_values; i ++)
1228 printf("\"%s\" ", attr->values[i].string.text);
1229 break;
1230
1231 case IPP_TAG_TEXTLANG :
1232 case IPP_TAG_NAMELANG :
1233 for (i = 0; i < attr->num_values; i ++)
1234 printf("\"%s\",%s ", attr->values[i].string.text,
1235 attr->values[i].string.charset);
1236 break;
1237
1238 case IPP_TAG_BEGIN_COLLECTION :
1239 for (i = 0; i < attr->num_values; i ++)
1240 {
1241 print_col(attr->values[i].collection);
1242 putchar(' ');
1243 }
1244 break;
1245
1246 default :
1247 break; /* anti-compiler-warning-code */
1248 }
1249 }
1250
1251 putchar('}');
1252 }
1253
1254
1255 /*
1256 * 'usage()' - Show program usage.
1257 */
1258
1259 static void
1260 usage(void)
1261 {
1262 fputs("Usage: ipptest [options] URL testfile [ ... testfileN ]\n", stderr);
1263 fputs("Options:\n", stderr);
1264 fputs("\n", stderr);
1265 fputs("-c Send requests using chunking.\n", stderr);
1266 fputs("-d name=value Define variable.\n", stderr);
1267 fputs("-i seconds Repeat the last test file with the given interval.\n",
1268 stderr);
1269 fputs("-v Show all attributes in response, even on success.\n",
1270 stderr);
1271
1272 exit(1);
1273 }
1274
1275
1276 /*
1277 * End of "$Id: ipptest.c 7847 2008-08-19 04:22:14Z mike $".
1278 */