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