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