]> git.ipfire.org Git - thirdparty/cups.git/blob - test/ipptest.c
Load cups into easysw/current.
[thirdparty/cups.git] / test / ipptest.c
1 /*
2 * "$Id: ipptest.c 5037 2006-02-01 15:19:59Z mike $"
3 *
4 * IPP test command for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Parse options and do tests.
27 * do_tests() - Do tests as specified in the test file.
28 * get_tag() - Get an IPP value or group tag from a name...
29 * get_token() - Get a token from a file.
30 * print_attr() - Print an attribute on the screen.
31 * usage() - Show program usage.
32 */
33
34 /*
35 * Include necessary headers...
36 */
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <cups/string.h>
41 #include <errno.h>
42 #include <ctype.h>
43
44 #include <cups/cups.h>
45 #include <cups/language.h>
46
47
48 /*
49 * Globals...
50 */
51
52 int Verbosity = 0; /* Show all attributes? */
53
54
55 /*
56 * Local functions...
57 */
58
59 int do_tests(const char *, const char *);
60 ipp_op_t ippOpValue(const char *);
61 ipp_status_t ippErrorValue(const char *);
62 ipp_tag_t get_tag(const char *);
63 char *get_token(FILE *, char *, int, int *linenum);
64 void print_attr(ipp_attribute_t *);
65 void usage(const char *option);
66
67
68 /*
69 * 'main()' - Parse options and do tests.
70 */
71
72 int /* O - Exit status */
73 main(int argc, /* I - Number of command-line arguments */
74 char *argv[]) /* I - Command-line arguments */
75 {
76 int i; /* Looping var */
77 int status; /* Status of tests... */
78 const char *uri; /* URI to use */
79 const char *testfile; /* Test file to use */
80
81
82 /*
83 * We need at least:
84 *
85 * testipp URL testfile
86 */
87
88 uri = NULL;
89 testfile = NULL;
90 status = 0;
91
92 for (i = 1; i < argc; i ++)
93 {
94 if (argv[i][0] == '-')
95 {
96 if (!strcmp(argv[i], "-v"))
97 Verbosity ++;
98 else
99 usage(argv[i]);
100 }
101 else if (!strncmp(argv[i], "ipp://", 6) ||
102 !strncmp(argv[i], "http://", 7) ||
103 !strncmp(argv[i], "https://", 8))
104 {
105 /*
106 * Set URI...
107 */
108
109 if (!testfile && uri)
110 usage(NULL);
111
112 uri = argv[i];
113 testfile = NULL;
114 }
115 else
116 {
117 /*
118 * Run test...
119 */
120
121 testfile = argv[i];
122
123 if (!do_tests(uri, testfile))
124 status ++;
125 }
126 }
127
128 if (!uri || !testfile)
129 usage(NULL);
130
131 /*
132 * Exit...
133 */
134
135 return (status);
136 }
137
138
139 /*
140 * 'do_tests()' - Do tests as specified in the test file.
141 */
142
143 int /* 1 = success, 0 = failure */
144 do_tests(const char *uri, /* I - URI to connect on */
145 const char *testfile) /* I - Test file to use */
146 {
147 int i; /* Looping var */
148 int linenum; /* Current line number */
149 int version; /* IPP version number to use */
150 http_t *http; /* HTTP connection to server */
151 char method[HTTP_MAX_URI], /* URI method */
152 userpass[HTTP_MAX_URI], /* username:password */
153 server[HTTP_MAX_URI], /* Server */
154 resource[HTTP_MAX_URI]; /* Resource path */
155 int port; /* Port number */
156 FILE *fp; /* Test file */
157 char token[1024], /* Token from file */
158 *tokenptr, /* Pointer into token */
159 temp[1024], /* Temporary string */
160 *tempptr; /* Pointer into temp string */
161 ipp_t *request; /* IPP request */
162 ipp_t *response; /* IPP response */
163 ipp_op_t op; /* Operation */
164 ipp_tag_t group; /* Current group */
165 ipp_tag_t value; /* Current value type */
166 ipp_attribute_t *attrptr; /* Attribute pointer */
167 char attr[128]; /* Attribute name */
168 int num_statuses; /* Number of valid status codes */
169 ipp_status_t statuses[100]; /* Valid status codes */
170 int num_expects; /* Number of expected attributes */
171 char *expects[100]; /* Expected attributes */
172 int num_displayed; /* Number of displayed attributes */
173 char *displayed[100]; /* Displayed attributes */
174 char name[1024]; /* Name of test */
175 char filename[1024]; /* Filename */
176 int pass; /* Did we pass the test? */
177 int job_id; /* Job ID from last operation */
178 int subscription_id; /* Subscription ID from last operation */
179
180
181 /*
182 * Open the test file...
183 */
184
185 if ((fp = fopen(testfile, "r")) == NULL)
186 {
187 printf("Unable to open test file %s - %s\n", testfile, strerror(errno));
188 return (0);
189 }
190
191 /*
192 * Connect to the server...
193 */
194
195 httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), userpass,
196 sizeof(userpass), server, sizeof(server), &port, resource,
197 sizeof(resource));
198 if ((http = httpConnect(server, port)) == NULL)
199 {
200 printf("Unable to connect to %s on port %d - %s\n", server, port,
201 strerror(errno));
202 return (0);
203 }
204
205 /*
206 * Loop on tests...
207 */
208
209 printf("\"%s\":\n", testfile);
210 pass = 1;
211 job_id = 0;
212 subscription_id = 0;
213 version = 1;
214 linenum = 1;
215
216 while (get_token(fp, token, sizeof(token), &linenum) != NULL)
217 {
218 /*
219 * Expect an open brace...
220 */
221
222 if (strcmp(token, "{"))
223 {
224 printf("Unexpected token %s seen on line %d - aborting test!\n", token,
225 linenum);
226 httpClose(http);
227 return (0);
228 }
229
230 /*
231 * Initialize things...
232 */
233
234 httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), userpass,
235 sizeof(userpass), server, sizeof(server), &port, resource,
236 sizeof(resource));
237
238 request = ippNew();
239 op = (ipp_op_t)0;
240 group = IPP_TAG_ZERO;
241 value = IPP_TAG_ZERO;
242 num_statuses = 0;
243 num_expects = 0;
244 num_displayed = 0;
245 filename[0] = '\0';
246
247 strcpy(name, testfile);
248 if (strrchr(name, '.') != NULL)
249 *strrchr(name, '.') = '\0';
250
251 /*
252 * Parse until we see a close brace...
253 */
254
255 while (get_token(fp, token, sizeof(token), &linenum) != NULL)
256 {
257 if (!strcmp(token, "}"))
258 break;
259 else if (!strcasecmp(token, "NAME"))
260 {
261 /*
262 * Name of test...
263 */
264
265 get_token(fp, name, sizeof(name), &linenum);
266 }
267 else if (!strcasecmp(token, "VERSION"))
268 {
269 /*
270 * IPP version number for test...
271 */
272
273 get_token(fp, temp, sizeof(temp), &linenum);
274 sscanf(temp, "%*d.%d", &version);
275 }
276 else if (!strcasecmp(token, "RESOURCE"))
277 {
278 /*
279 * Resource name...
280 */
281
282 get_token(fp, resource, sizeof(resource), &linenum);
283 }
284 else if (!strcasecmp(token, "OPERATION"))
285 {
286 /*
287 * Operation...
288 */
289
290 get_token(fp, token, sizeof(token), &linenum);
291 op = ippOpValue(token);
292 }
293 else if (!strcasecmp(token, "GROUP"))
294 {
295 /*
296 * Attribute group...
297 */
298
299 get_token(fp, token, sizeof(token), &linenum);
300 value = get_tag(token);
301
302 if (value == group)
303 ippAddSeparator(request);
304
305 group = value;
306 }
307 else if (!strcasecmp(token, "DELAY"))
308 {
309 /*
310 * Delay before operation...
311 */
312
313 int delay;
314
315 get_token(fp, token, sizeof(token), &linenum);
316 if ((delay = atoi(token)) > 0)
317 sleep(delay);
318 }
319 else if (!strcasecmp(token, "ATTR"))
320 {
321 /*
322 * Attribute...
323 */
324
325 get_token(fp, token, sizeof(token), &linenum);
326 value = get_tag(token);
327 get_token(fp, attr, sizeof(attr), &linenum);
328 get_token(fp, temp, sizeof(temp), &linenum);
329
330 token[sizeof(token) - 1] = '\0';
331
332 for (tempptr = temp, tokenptr = token;
333 *tempptr && tokenptr < (token + sizeof(token) - 1);)
334 if (*tempptr == '$')
335 {
336 /*
337 * Substitute a string/number...
338 */
339
340 if (!strncasecmp(tempptr + 1, "uri", 3))
341 {
342 strlcpy(tokenptr, uri, sizeof(token) - (tokenptr - token));
343 tempptr += 4;
344 }
345 else if (!strncasecmp(tempptr + 1, "method", 6))
346 {
347 strlcpy(tokenptr, method, sizeof(token) - (tokenptr - token));
348 tempptr += 7;
349 }
350 else if (!strncasecmp(tempptr + 1, "username", 8))
351 {
352 strlcpy(tokenptr, userpass, sizeof(token) - (tokenptr - token));
353 tempptr += 9;
354 }
355 else if (!strncasecmp(tempptr + 1, "hostname", 8))
356 {
357 strlcpy(tokenptr, server, sizeof(token) - (tokenptr - token));
358 tempptr += 9;
359 }
360 else if (!strncasecmp(tempptr + 1, "port", 4))
361 {
362 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
363 "%d", port);
364 tempptr += 5;
365 }
366 else if (!strncasecmp(tempptr + 1, "resource", 8))
367 {
368 strlcpy(tokenptr, resource, sizeof(token) - (tokenptr - token));
369 tempptr += 9;
370 }
371 else if (!strncasecmp(tempptr + 1, "job-id", 6))
372 {
373 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
374 "%d", job_id);
375 tempptr += 7;
376 }
377 else if (!strncasecmp(tempptr + 1, "notify-subscription-id", 22))
378 {
379 snprintf(tokenptr, sizeof(token) - (tokenptr - token),
380 "%d", subscription_id);
381 tempptr += 23;
382 }
383 else if (!strncasecmp(tempptr + 1, "user", 4))
384 {
385 strlcpy(tokenptr, cupsUser(), sizeof(token) - (tokenptr - token));
386 tempptr += 5;
387 }
388 else
389 {
390 *tokenptr++ = *tempptr ++;
391 *tokenptr = '\0';
392 }
393
394 tokenptr += strlen(tokenptr);
395 }
396 else
397 {
398 *tokenptr++ = *tempptr++;
399 *tokenptr = '\0';
400 }
401
402 switch (value)
403 {
404 case IPP_TAG_BOOLEAN :
405 if (!strcasecmp(token, "true"))
406 ippAddBoolean(request, group, attr, 1);
407 else
408 ippAddBoolean(request, group, attr, atoi(token));
409 break;
410
411 case IPP_TAG_INTEGER :
412 case IPP_TAG_ENUM :
413 ippAddInteger(request, group, value, attr, atoi(token));
414 break;
415
416 case IPP_TAG_RESOLUTION :
417 puts(" ERROR: resolution tag not yet supported!");
418 break;
419
420 case IPP_TAG_RANGE :
421 puts(" ERROR: range tag not yet supported!");
422 break;
423
424 default :
425 if (!strchr(token, ','))
426 ippAddString(request, group, value, attr, NULL, token);
427 else
428 {
429 /*
430 * Multiple string values...
431 */
432
433 int num_values; /* Number of values */
434 char *values[100], /* Values */
435 *ptr; /* Pointer to next value */
436
437
438 values[0] = token;
439 num_values = 1;
440
441 for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ','))
442 {
443 *ptr++ = '\0';
444 values[num_values] = ptr;
445 num_values ++;
446 }
447
448 ippAddStrings(request, group, value, attr, num_values,
449 NULL, (const char **)values);
450 }
451 break;
452 }
453 }
454 else if (!strcasecmp(token, "FILE"))
455 {
456 /*
457 * File...
458 */
459
460 get_token(fp, filename, sizeof(filename), &linenum);
461 }
462 else if (!strcasecmp(token, "STATUS") &&
463 num_statuses < (int)(sizeof(statuses) / sizeof(statuses[0])))
464 {
465 /*
466 * Status...
467 */
468
469 get_token(fp, token, sizeof(token), &linenum);
470 statuses[num_statuses] = ippErrorValue(token);
471 num_statuses ++;
472 }
473 else if (!strcasecmp(token, "EXPECT") &&
474 num_expects < (int)(sizeof(expects) / sizeof(expects[0])))
475 {
476 /*
477 * Expected attributes...
478 */
479
480 get_token(fp, token, sizeof(token), &linenum);
481 expects[num_expects] = strdup(token);
482 num_expects ++;
483 }
484 else if (!strcasecmp(token, "DISPLAY") &&
485 num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0])))
486 {
487 /*
488 * Display attributes...
489 */
490
491 get_token(fp, token, sizeof(token), &linenum);
492 displayed[num_displayed] = strdup(token);
493 num_displayed ++;
494 }
495 else
496 {
497 printf("Unexpected token %s seen on line %d - aborting test!\n", token,
498 linenum);
499 httpClose(http);
500 ippDelete(request);
501 return (0);
502 }
503 }
504
505 /*
506 * Submit the IPP request...
507 */
508
509 request->request.op.version[1] = version;
510 request->request.op.operation_id = op;
511 request->request.op.request_id = 1;
512
513 #ifdef DEBUG
514 for (attrptr = request->attrs; attrptr; attrptr = attrptr->next)
515 print_attr(attrptr);
516 #endif /* DEBUG */
517
518 printf(" %-60.60s [", name);
519 fflush(stdout);
520
521 if (filename[0])
522 response = cupsDoFileRequest(http, request, resource, filename);
523 else
524 response = cupsDoRequest(http, request, resource);
525
526 if (response == NULL)
527 {
528 time_t curtime;
529
530 curtime = time(NULL);
531
532 puts("FAIL]");
533 printf(" ERROR %04x (%s) @ %s\n", cupsLastError(),
534 ippErrorString(cupsLastError()), ctime(&curtime));
535 pass = 0;
536 }
537 else
538 {
539 if ((attrptr = ippFindAttribute(response, "job-id",
540 IPP_TAG_INTEGER)) != NULL)
541 job_id = attrptr->values[0].integer;
542
543 if ((attrptr = ippFindAttribute(response, "notify-subscription-id",
544 IPP_TAG_INTEGER)) != NULL)
545 subscription_id = attrptr->values[0].integer;
546
547 for (i = 0; i < num_statuses; i ++)
548 if (response->request.status.status_code == statuses[i])
549 break;
550
551 if (i == num_statuses && num_statuses > 0)
552 pass = 0;
553 else
554 {
555 for (i = 0; i < num_expects; i ++)
556 if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
557 {
558 pass = 0;
559 break;
560 }
561 }
562
563 if (pass)
564 {
565 puts("PASS]");
566 printf(" RECEIVED: %lu bytes in response\n",
567 (unsigned long)ippLength(response));
568
569 if (Verbosity)
570 {
571 for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
572 print_attr(attrptr);
573 }
574 else if (num_displayed > 0)
575 {
576 for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
577 if (attrptr->name)
578 {
579 for (i = 0; i < num_displayed; i ++)
580 if (!strcmp(displayed[i], attrptr->name))
581 {
582 print_attr(attrptr);
583 break;
584 }
585 }
586 }
587 }
588 else
589 {
590 puts("FAIL]");
591 printf(" RECEIVED: %lu bytes in response\n",
592 (unsigned long)ippLength(response));
593
594 for (i = 0; i < num_statuses; i ++)
595 if (response->request.status.status_code == statuses[i])
596 break;
597
598 if (i == num_statuses && num_statuses > 0)
599 puts(" BAD STATUS");
600
601 printf(" status-code = %04x (%s)\n",
602 response->request.status.status_code,
603 ippErrorString(response->request.status.status_code));
604
605 for (i = 0; i < num_expects; i ++)
606 if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
607 printf(" EXPECTED: %s\n", expects[i]);
608
609 for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next)
610 print_attr(attrptr);
611 }
612
613 ippDelete(response);
614 }
615
616 for (i = 0; i < num_expects; i ++)
617 free(expects[i]);
618
619 if (!pass)
620 break;
621 }
622
623 fclose(fp);
624 httpClose(http);
625
626 return (pass);
627 }
628
629
630 /*
631 * 'get_tag()' - Get an IPP value or group tag from a name...
632 */
633
634 ipp_tag_t /* O - Value/group tag */
635 get_tag(const char *name) /* I - Name of value/group tag */
636 {
637 int i; /* Looping var */
638 static const char * const names[] =
639 { /* Value/group tag names */
640 "zero", "operation", "job", "end", "printer",
641 "unsupported-group", "subscription", "event-notification",
642 "", "", "", "", "",
643 "", "", "", "unsupported-value", "default",
644 "unknown", "novalue", "", "notsettable",
645 "deleteattr", "anyvalue", "", "", "", "", "", "",
646 "", "", "", "integer", "boolean", "enum", "", "",
647 "", "", "", "", "", "", "", "", "", "", "string",
648 "date", "resolution", "range", "collection",
649 "textlang", "namelang", "", "", "", "", "", "", "",
650 "", "", "", "text", "name", "", "keyword", "uri",
651 "urischeme", "charset", "language", "mimetype"
652 };
653
654
655 for (i = 0; i < (sizeof(names) / sizeof(names[0])); i ++)
656 if (!strcasecmp(name, names[i]))
657 return ((ipp_tag_t)i);
658
659 return (IPP_TAG_ZERO);
660 }
661
662
663 /*
664 * 'get_token()' - Get a token from a file.
665 */
666
667 char * /* O - Token from file or NULL on EOF */
668 get_token(FILE *fp, /* I - File to read from */
669 char *buf, /* I - Buffer to read into */
670 int buflen, /* I - Length of buffer */
671 int *linenum) /* IO - Current line number */
672 {
673 int ch, /* Character from file */
674 quote; /* Quoting character */
675 char *bufptr, /* Pointer into buffer */
676 *bufend; /* End of buffer */
677
678
679 for (;;)
680 {
681 /*
682 * Skip whitespace...
683 */
684
685 while (isspace(ch = getc(fp)))
686 {
687 if (ch == '\n')
688 (*linenum) ++;
689 }
690
691 /*
692 * Read a token...
693 */
694
695 if (ch == EOF)
696 return (NULL);
697 else if (ch == '\'' || ch == '\"')
698 {
699 /*
700 * Quoted text...
701 */
702
703 quote = ch;
704 bufptr = buf;
705 bufend = buf + buflen - 1;
706
707 while ((ch = getc(fp)) != EOF)
708 if (ch == quote)
709 break;
710 else if (bufptr < bufend)
711 *bufptr++ = ch;
712
713 *bufptr = '\0';
714 return (buf);
715 }
716 else if (ch == '#')
717 {
718 /*
719 * Comment...
720 */
721
722 while ((ch = getc(fp)) != EOF)
723 if (ch == '\n')
724 break;
725
726 (*linenum) ++;
727 }
728 else
729 {
730 /*
731 * Whitespace delimited text...
732 */
733
734 ungetc(ch, fp);
735
736 bufptr = buf;
737 bufend = buf + buflen - 1;
738
739 while ((ch = getc(fp)) != EOF)
740 if (isspace(ch) || ch == '#')
741 break;
742 else if (bufptr < bufend)
743 *bufptr++ = ch;
744
745 if (ch == '#')
746 ungetc(ch, fp);
747
748 *bufptr = '\0';
749 return (buf);
750 }
751 }
752 }
753
754
755 /*
756 * 'print_attr()' - Print an attribute on the screen.
757 */
758
759 void
760 print_attr(ipp_attribute_t *attr) /* I - Attribute to print */
761 {
762 int i; /* Looping var */
763
764
765 if (attr->name == NULL)
766 {
767 puts(" -- separator --");
768 return;
769 }
770
771 printf(" %s = ", attr->name);
772
773 switch (attr->value_tag)
774 {
775 case IPP_TAG_INTEGER :
776 case IPP_TAG_ENUM :
777 for (i = 0; i < attr->num_values; i ++)
778 printf("%d ", attr->values[i].integer);
779 break;
780
781 case IPP_TAG_BOOLEAN :
782 for (i = 0; i < attr->num_values; i ++)
783 if (attr->values[i].boolean)
784 printf("true ");
785 else
786 printf("false ");
787 break;
788
789 case IPP_TAG_NOVALUE :
790 printf("novalue");
791 break;
792
793 case IPP_TAG_RANGE :
794 for (i = 0; i < attr->num_values; i ++)
795 printf("%d-%d ", attr->values[i].range.lower,
796 attr->values[i].range.upper);
797 break;
798
799 case IPP_TAG_RESOLUTION :
800 for (i = 0; i < attr->num_values; i ++)
801 printf("%dx%d%s ", attr->values[i].resolution.xres,
802 attr->values[i].resolution.yres,
803 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
804 "dpi" : "dpc");
805 break;
806
807 case IPP_TAG_STRING :
808 case IPP_TAG_TEXT :
809 case IPP_TAG_NAME :
810 case IPP_TAG_KEYWORD :
811 case IPP_TAG_CHARSET :
812 case IPP_TAG_URI :
813 case IPP_TAG_MIMETYPE :
814 case IPP_TAG_LANGUAGE :
815 for (i = 0; i < attr->num_values; i ++)
816 printf("\"%s\" ", attr->values[i].string.text);
817 break;
818
819 case IPP_TAG_TEXTLANG :
820 case IPP_TAG_NAMELANG :
821 for (i = 0; i < attr->num_values; i ++)
822 printf("\"%s\",%s ", attr->values[i].string.text,
823 attr->values[i].string.charset);
824 break;
825
826 default :
827 break; /* anti-compiler-warning-code */
828 }
829
830 putchar('\n');
831 }
832
833
834 /*
835 * 'usage()' - Show program usage.
836 */
837
838 void
839 usage(const char *option) /* I - Option string or NULL */
840 {
841 if (option)
842 fprintf(stderr, "ipptest: Unknown option \"%s\"!\n", option);
843
844 fputs("Usage: ipptest [options] URL testfile [ ... testfileN ]\n", stderr);
845 fputs("Options:\n", stderr);
846 fputs("\n", stderr);
847 fputs("-v Show all attributes in response, even on success.\n", stderr);
848
849 exit(1);
850 }
851
852
853 /*
854 * End of "$Id: ipptest.c 5037 2006-02-01 15:19:59Z mike $".
855 */