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