1 /*
2 * CUPS destination API test program for CUPS.
3 *
4 * Copyright 2012-2017 by Apple Inc.
5 *
6 * These coded instructions, statements, and computer programs are the
7 * property of Apple Inc. and are protected by Federal copyright
8 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
9 * which should have been included with this file. If this file is
10 * missing or damaged, see the license at "http://www.cups.org/".
11 *
12 * This file is subject to the Apple OS-Developed Software exception.
13 */
14
15 /*
16 * Include necessary headers...
17 */
18
19 #include <stdio.h>
20 #include <errno.h>
21 #include "cups.h"
22
23
24 /*
25 * Local functions...
26 */
27
28 static int enum_cb(void *user_data, unsigned flags, cups_dest_t *dest);
29 static void localize(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value);
30 static void print_file(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *filename, int num_options, cups_option_t *options);
31 static void show_conflicts(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, int num_options, cups_option_t *options);
32 static void show_default(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option);
33 static void show_media(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, const char *name);
34 static void show_supported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value);
35 static void usage(const char *arg) __attribute__((noreturn));
36
37
38 /*
39 * 'main()' - Main entry.
40 */
41
42 int /* O - Exit status */
main(int argc,char * argv[])43 main(int argc, /* I - Number of command-line arguments */
44 char *argv[]) /* I - Command-line arguments */
45 {
46 http_t *http; /* Connection to destination */
47 cups_dest_t *dest = NULL; /* Destination */
48 cups_dinfo_t *dinfo; /* Destination info */
49
50
51 if (argc < 2)
52 usage(NULL);
53
54 if (!strcmp(argv[1], "--enum"))
55 {
56 int i; /* Looping var */
57 cups_ptype_t type = 0, /* Printer type filter */
58 mask = 0; /* Printer type mask */
59
60
61 for (i = 2; i < argc; i ++)
62 {
63 if (!strcmp(argv[i], "grayscale"))
64 {
65 type |= CUPS_PRINTER_BW;
66 mask |= CUPS_PRINTER_BW;
67 }
68 else if (!strcmp(argv[i], "color"))
69 {
70 type |= CUPS_PRINTER_COLOR;
71 mask |= CUPS_PRINTER_COLOR;
72 }
73 else if (!strcmp(argv[i], "duplex"))
74 {
75 type |= CUPS_PRINTER_DUPLEX;
76 mask |= CUPS_PRINTER_DUPLEX;
77 }
78 else if (!strcmp(argv[i], "staple"))
79 {
80 type |= CUPS_PRINTER_STAPLE;
81 mask |= CUPS_PRINTER_STAPLE;
82 }
83 else if (!strcmp(argv[i], "small"))
84 {
85 type |= CUPS_PRINTER_SMALL;
86 mask |= CUPS_PRINTER_SMALL;
87 }
88 else if (!strcmp(argv[i], "medium"))
89 {
90 type |= CUPS_PRINTER_MEDIUM;
91 mask |= CUPS_PRINTER_MEDIUM;
92 }
93 else if (!strcmp(argv[i], "large"))
94 {
95 type |= CUPS_PRINTER_LARGE;
96 mask |= CUPS_PRINTER_LARGE;
97 }
98 else
99 usage(argv[i]);
100 }
101
102 cupsEnumDests(CUPS_DEST_FLAGS_NONE, 5000, NULL, type, mask, enum_cb, NULL);
103
104 return (0);
105 }
106 else if (!strncmp(argv[1], "ipp://", 6) || !strncmp(argv[1], "ipps://", 7))
107 dest = cupsGetDestWithURI(NULL, argv[1]);
108 else if (!strcmp(argv[1], "default"))
109 {
110 dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
111 if (dest && dest->instance)
112 printf("default is \"%s/%s\".\n", dest->name, dest->instance);
113 else
114 printf("default is \"%s\".\n", dest->name);
115 }
116 else
117 dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[1], NULL);
118
119 if (!dest)
120 {
121 printf("testdest: Unable to get destination \"%s\": %s\n", argv[1], cupsLastErrorString());
122 return (1);
123 }
124
125 if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
126 {
127 printf("testdest: Unable to connect to destination \"%s\": %s\n", argv[1], cupsLastErrorString());
128 return (1);
129 }
130
131 if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL)
132 {
133 printf("testdest: Unable to get information for destination \"%s\": %s\n", argv[1], cupsLastErrorString());
134 return (1);
135 }
136
137 if (argc == 2 || (!strcmp(argv[2], "supported") && argc < 6))
138 {
139 if (argc > 3)
140 show_supported(http, dest, dinfo, argv[3], argv[4]);
141 else if (argc > 2)
142 show_supported(http, dest, dinfo, argv[3], NULL);
143 else
144 show_supported(http, dest, dinfo, NULL, NULL);
145 }
146 else if (!strcmp(argv[2], "conflicts") && argc > 3)
147 {
148 int i, /* Looping var */
149 num_options = 0;/* Number of options */
150 cups_option_t *options = NULL;/* Options */
151
152 for (i = 3; i < argc; i ++)
153 num_options = cupsParseOptions(argv[i], num_options, &options);
154
155 show_conflicts(http, dest, dinfo, num_options, options);
156 }
157 else if (!strcmp(argv[2], "default") && argc == 4)
158 {
159 show_default(http, dest, dinfo, argv[3]);
160 }
161 else if (!strcmp(argv[2], "localize") && argc < 6)
162 {
163 if (argc > 3)
164 localize(http, dest, dinfo, argv[3], argv[4]);
165 else if (argc > 2)
166 localize(http, dest, dinfo, argv[3], NULL);
167 else
168 localize(http, dest, dinfo, NULL, NULL);
169 }
170 else if (!strcmp(argv[2], "media"))
171 {
172 int i; /* Looping var */
173 const char *name = NULL; /* Media name, if any */
174 unsigned flags = CUPS_MEDIA_FLAGS_DEFAULT;
175 /* Media selection flags */
176
177 for (i = 3; i < argc; i ++)
178 {
179 if (!strcmp(argv[i], "borderless"))
180 flags = CUPS_MEDIA_FLAGS_BORDERLESS;
181 else if (!strcmp(argv[i], "duplex"))
182 flags = CUPS_MEDIA_FLAGS_DUPLEX;
183 else if (!strcmp(argv[i], "exact"))
184 flags = CUPS_MEDIA_FLAGS_EXACT;
185 else if (!strcmp(argv[i], "ready"))
186 flags = CUPS_MEDIA_FLAGS_READY;
187 else if (name)
188 usage(argv[i]);
189 else
190 name = argv[i];
191 }
192
193 show_media(http, dest, dinfo, flags, name);
194 }
195 else if (!strcmp(argv[2], "print") && argc > 3)
196 {
197 int i, /* Looping var */
198 num_options = 0;/* Number of options */
199 cups_option_t *options = NULL;/* Options */
200
201 for (i = 4; i < argc; i ++)
202 num_options = cupsParseOptions(argv[i], num_options, &options);
203
204 print_file(http, dest, dinfo, argv[3], num_options, options);
205 }
206 else
207 usage(argv[2]);
208
209 return (0);
210 }
211
212
213 /*
214 * 'enum_cb()' - Print the results from the enumeration of destinations.
215 */
216
217 static int /* O - 1 to continue */
enum_cb(void * user_data,unsigned flags,cups_dest_t * dest)218 enum_cb(void *user_data, /* I - User data (unused) */
219 unsigned flags, /* I - Flags */
220 cups_dest_t *dest) /* I - Destination */
221 {
222 int i; /* Looping var */
223
224
225 (void)user_data;
226 (void)flags;
227
228 if (dest->instance)
229 printf("%s%s/%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name, dest->instance);
230 else
231 printf("%s%s:\n", (flags & CUPS_DEST_FLAGS_REMOVED) ? "REMOVE " : "", dest->name);
232
233 for (i = 0; i < dest->num_options; i ++)
234 printf(" %s=\"%s\"\n", dest->options[i].name, dest->options[i].value);
235
236 return (1);
237 }
238
239
240 /*
241 * 'localize()' - Localize an option and value.
242 */
243
244 static void
localize(http_t * http,cups_dest_t * dest,cups_dinfo_t * dinfo,const char * option,const char * value)245 localize(http_t *http, /* I - Connection to destination */
246 cups_dest_t *dest, /* I - Destination */
247 cups_dinfo_t *dinfo, /* I - Destination information */
248 const char *option, /* I - Option */
249 const char *value) /* I - Value, if any */
250 {
251 ipp_attribute_t *attr; /* Attribute */
252 int i, /* Looping var */
253 count; /* Number of values */
254
255
256 if (!option)
257 {
258 attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes");
259 if (attr)
260 {
261 count = ippGetCount(attr);
262 for (i = 0; i < count; i ++)
263 localize(http, dest, dinfo, ippGetString(attr, i, NULL), NULL);
264 }
265 else
266 {
267 static const char * const options[] =
268 { /* List of standard options */
269 CUPS_COPIES,
270 CUPS_FINISHINGS,
271 CUPS_MEDIA,
272 CUPS_NUMBER_UP,
273 CUPS_ORIENTATION,
274 CUPS_PRINT_COLOR_MODE,
275 CUPS_PRINT_QUALITY,
276 CUPS_SIDES
277 };
278
279 puts("No job-creation-attributes-supported attribute, probing instead.");
280
281 for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++)
282 if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL))
283 localize(http, dest, dinfo, options[i], NULL);
284 }
285 }
286 else if (!value)
287 {
288 printf("%s (%s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option));
289
290 if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL)
291 {
292 count = ippGetCount(attr);
293
294 switch (ippGetValueTag(attr))
295 {
296 case IPP_TAG_INTEGER :
297 for (i = 0; i < count; i ++)
298 printf(" %d\n", ippGetInteger(attr, i));
299 break;
300
301 case IPP_TAG_ENUM :
302 for (i = 0; i < count; i ++)
303 printf(" %s\n", ippEnumString(option, ippGetInteger(attr, i)));
304 break;
305
306 case IPP_TAG_RANGE :
307 for (i = 0; i < count; i ++)
308 {
309 int upper, lower = ippGetRange(attr, i, &upper);
310
311 printf(" %d-%d\n", lower, upper);
312 }
313 break;
314
315 case IPP_TAG_RESOLUTION :
316 for (i = 0; i < count; i ++)
317 {
318 int xres, yres;
319 ipp_res_t units;
320 xres = ippGetResolution(attr, i, &yres, &units);
321
322 if (xres == yres)
323 printf(" %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
324 else
325 printf(" %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
326 }
327 break;
328
329 case IPP_TAG_TEXTLANG :
330 case IPP_TAG_NAMELANG :
331 case IPP_TAG_TEXT :
332 case IPP_TAG_NAME :
333 case IPP_TAG_KEYWORD :
334 case IPP_TAG_URI :
335 case IPP_TAG_URISCHEME :
336 case IPP_TAG_CHARSET :
337 case IPP_TAG_LANGUAGE :
338 case IPP_TAG_MIMETYPE :
339 for (i = 0; i < count; i ++)
340 printf(" %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL)));
341 break;
342
343 case IPP_TAG_STRING :
344 for (i = 0; i < count; i ++)
345 {
346 int j, len;
347 unsigned char *data = ippGetOctetString(attr, i, &len);
348
349 fputs(" ", stdout);
350 for (j = 0; j < len; j ++)
351 {
352 if (data[j] < ' ' || data[j] >= 0x7f)
353 printf("<%02X>", data[j]);
354 else
355 putchar(data[j]);
356 }
357 putchar('\n');
358 }
359 break;
360
361 case IPP_TAG_BOOLEAN :
362 break;
363
364 default :
365 printf(" %s\n", ippTagString(ippGetValueTag(attr)));
366 break;
367 }
368 }
369
370 }
371 else
372 puts(cupsLocalizeDestValue(http, dest, dinfo, option, value));
373 }
374
375
376 /*
377 * 'print_file()' - Print a file.
378 */
379
380 static void
print_file(http_t * http,cups_dest_t * dest,cups_dinfo_t * dinfo,const char * filename,int num_options,cups_option_t * options)381 print_file(http_t *http, /* I - Connection to destination */
382 cups_dest_t *dest, /* I - Destination */
383 cups_dinfo_t *dinfo, /* I - Destination information */
384 const char *filename, /* I - File to print */
385 int num_options, /* I - Number of options */
386 cups_option_t *options) /* I - Options */
387 {
388 cups_file_t *fp; /* File to print */
389 int job_id; /* Job ID */
390 ipp_status_t status; /* Submission status */
391 const char *title; /* Title of job */
392 char buffer[32768]; /* File buffer */
393 ssize_t bytes; /* Bytes read/to write */
394
395
396 if ((fp = cupsFileOpen(filename, "r")) == NULL)
397 {
398 printf("Unable to open \"%s\": %s\n", filename, strerror(errno));
399 return;
400 }
401
402 if ((title = strrchr(filename, '/')) != NULL)
403 title ++;
404 else
405 title = filename;
406
407 if ((status = cupsCreateDestJob(http, dest, dinfo, &job_id, title, num_options, options)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
408 {
409 printf("Unable to create job: %s\n", cupsLastErrorString());
410 cupsFileClose(fp);
411 return;
412 }
413
414 printf("Created job ID: %d\n", job_id);
415
416 if (cupsStartDestDocument(http, dest, dinfo, job_id, title, CUPS_FORMAT_AUTO, 0, NULL, 1) != HTTP_STATUS_CONTINUE)
417 {
418 printf("Unable to send document: %s\n", cupsLastErrorString());
419 cupsFileClose(fp);
420 return;
421 }
422
423 while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
424 {
425 if (cupsWriteRequestData(http, buffer, (size_t)bytes) != HTTP_STATUS_CONTINUE)
426 {
427 printf("Unable to write document data: %s\n", cupsLastErrorString());
428 break;
429 }
430 }
431
432 cupsFileClose(fp);
433
434 if ((status = cupsFinishDestDocument(http, dest, dinfo)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
435 {
436 printf("Unable to send document: %s\n", cupsLastErrorString());
437 return;
438 }
439
440 puts("Job queued.");
441 }
442
443
444 /*
445 * 'show_conflicts()' - Show conflicts for selected options.
446 */
447
448 static void
show_conflicts(http_t * http,cups_dest_t * dest,cups_dinfo_t * dinfo,int num_options,cups_option_t * options)449 show_conflicts(
450 http_t *http, /* I - Connection to destination */
451 cups_dest_t *dest, /* I - Destination */
452 cups_dinfo_t *dinfo, /* I - Destination information */
453 int num_options, /* I - Number of options */
454 cups_option_t *options) /* I - Options */
455 {
456 (void)http;
457 (void)dest;
458 (void)dinfo;
459 (void)num_options;
460 (void)options;
461 }
462
463
464 /*
465 * 'show_default()' - Show default value for option.
466 */
467
468 static void
show_default(http_t * http,cups_dest_t * dest,cups_dinfo_t * dinfo,const char * option)469 show_default(http_t *http, /* I - Connection to destination */
470 cups_dest_t *dest, /* I - Destination */
471 cups_dinfo_t *dinfo, /* I - Destination information */
472 const char *option) /* I - Option */
473 {
474 if (!strcmp(option, "media"))
475 {
476 /*
477 * Show default media option...
478 */
479
480 cups_size_t size; /* Media size information */
481
482 if (cupsGetDestMediaDefault(http, dest, dinfo, CUPS_MEDIA_FLAGS_DEFAULT, &size))
483 printf("%s (%.2fx%.2fmm, margins=[%.2f %.2f %.2f %.2f])\n", size.media, size.width * 0.01, size.length * 0.01, size.left * 0.01, size.bottom * 0.01, size.right * 0.01, size.top * 0.01);
484 else
485 puts("FAILED");
486 }
487 else
488 {
489 /*
490 * Show default other option...
491 */
492
493 ipp_attribute_t *defattr; /* Default attribute */
494
495 if ((defattr = cupsFindDestDefault(http, dest, dinfo, option)) != NULL)
496 {
497 char value[1024]; /* Value of default attribute */
498
499 ippAttributeString(defattr, value, sizeof(value));
500 puts(value);
501 }
502 else
503 puts("FAILED");
504 }
505 }
506
507
508 /*
509 * 'show_media()' - Show available media.
510 */
511
512 static void
show_media(http_t * http,cups_dest_t * dest,cups_dinfo_t * dinfo,unsigned flags,const char * name)513 show_media(http_t *http, /* I - Connection to destination */
514 cups_dest_t *dest, /* I - Destination */
515 cups_dinfo_t *dinfo, /* I - Destination information */
516 unsigned flags, /* I - Media flags */
517 const char *name) /* I - Size name */
518 {
519 int i, /* Looping var */
520 count; /* Number of sizes */
521 cups_size_t size; /* Media size info */
522
523
524 if (name)
525 {
526 double dw, dl; /* Width and length from name */
527 char units[32]; /* Units */
528 int width, /* Width in 100ths of millimeters */
529 length; /* Length in 100ths of millimeters */
530
531
532 if (sscanf(name, "%lfx%lf%31s", &dw, &dl, units) == 3)
533 {
534 if (!strcmp(units, "in"))
535 {
536 width = (int)(dw * 2540.0);
537 length = (int)(dl * 2540.0);
538 }
539 else if (!strcmp(units, "mm"))
540 {
541 width = (int)(dw * 100.0);
542 length = (int)(dl * 100.0);
543 }
544 else
545 {
546 puts(" bad units in size");
547 return;
548 }
549
550 if (cupsGetDestMediaBySize(http, dest, dinfo, width, length, flags, &size))
551 {
552 printf(" %s (%s) %dx%d B%d L%d R%d T%d\n", size.media, cupsLocalizeDestMedia(http, dest, dinfo, flags, &size), size.width, size.length, size.bottom, size.left, size.right, size.top);
553 }
554 else
555 {
556 puts(" not supported");
557 }
558 }
559 else if (cupsGetDestMediaByName(http, dest, dinfo, name, flags, &size))
560 {
561 printf(" %s (%s) %dx%d B%d L%d R%d T%d\n", size.media, cupsLocalizeDestMedia(http, dest, dinfo, flags, &size), size.width, size.length, size.bottom, size.left, size.right, size.top);
562 }
563 else
564 {
565 puts(" not supported");
566 }
567 }
568 else
569 {
570 count = cupsGetDestMediaCount(http, dest, dinfo, flags);
571 printf("%d size%s:\n", count, count == 1 ? "" : "s");
572
573 for (i = 0; i < count; i ++)
574 {
575 if (cupsGetDestMediaByIndex(http, dest, dinfo, i, flags, &size))
576 printf(" %s (%s) %dx%d B%d L%d R%d T%d\n", size.media, cupsLocalizeDestMedia(http, dest, dinfo, flags, &size), size.width, size.length, size.bottom, size.left, size.right, size.top);
577 else
578 puts(" error");
579 }
580 }
581 }
582
583
584 /*
585 * 'show_supported()' - Show supported options, values, etc.
586 */
587
588 static void
show_supported(http_t * http,cups_dest_t * dest,cups_dinfo_t * dinfo,const char * option,const char * value)589 show_supported(http_t *http, /* I - Connection to destination */
590 cups_dest_t *dest, /* I - Destination */
591 cups_dinfo_t *dinfo, /* I - Destination information */
592 const char *option, /* I - Option, if any */
593 const char *value) /* I - Value, if any */
594 {
595 ipp_attribute_t *attr; /* Attribute */
596 int i, /* Looping var */
597 count; /* Number of values */
598
599
600 if (!option)
601 {
602 attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes");
603 if (attr)
604 {
605 count = ippGetCount(attr);
606 for (i = 0; i < count; i ++)
607 show_supported(http, dest, dinfo, ippGetString(attr, i, NULL), NULL);
608 }
609 else
610 {
611 static const char * const options[] =
612 { /* List of standard options */
613 CUPS_COPIES,
614 CUPS_FINISHINGS,
615 CUPS_MEDIA,
616 CUPS_NUMBER_UP,
617 CUPS_ORIENTATION,
618 CUPS_PRINT_COLOR_MODE,
619 CUPS_PRINT_QUALITY,
620 CUPS_SIDES
621 };
622
623 puts("No job-creation-attributes-supported attribute, probing instead.");
624
625 for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++)
626 if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL))
627 show_supported(http, dest, dinfo, options[i], NULL);
628 }
629 }
630 else if (!value)
631 {
632 printf("%s (%s - %s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option), cupsCheckDestSupported(http, dest, dinfo, option, NULL) ? "supported" : "not-supported");
633
634 if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL)
635 {
636 count = ippGetCount(attr);
637
638 switch (ippGetValueTag(attr))
639 {
640 case IPP_TAG_INTEGER :
641 for (i = 0; i < count; i ++)
642 printf(" %d\n", ippGetInteger(attr, i));
643 break;
644
645 case IPP_TAG_ENUM :
646 for (i = 0; i < count; i ++)
647 {
648 int val = ippGetInteger(attr, i);
649 char valstr[256];
650
651 snprintf(valstr, sizeof(valstr), "%d", val);
652 printf(" %s (%s)\n", ippEnumString(option, ippGetInteger(attr, i)), cupsLocalizeDestValue(http, dest, dinfo, option, valstr));
653 }
654 break;
655
656 case IPP_TAG_RANGE :
657 for (i = 0; i < count; i ++)
658 {
659 int upper, lower = ippGetRange(attr, i, &upper);
660
661 printf(" %d-%d\n", lower, upper);
662 }
663 break;
664
665 case IPP_TAG_RESOLUTION :
666 for (i = 0; i < count; i ++)
667 {
668 int xres, yres;
669 ipp_res_t units;
670 xres = ippGetResolution(attr, i, &yres, &units);
671
672 if (xres == yres)
673 printf(" %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
674 else
675 printf(" %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
676 }
677 break;
678
679 case IPP_TAG_KEYWORD :
680 for (i = 0; i < count; i ++)
681 printf(" %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL)));
682 break;
683
684 case IPP_TAG_TEXTLANG :
685 case IPP_TAG_NAMELANG :
686 case IPP_TAG_TEXT :
687 case IPP_TAG_NAME :
688 case IPP_TAG_URI :
689 case IPP_TAG_URISCHEME :
690 case IPP_TAG_CHARSET :
691 case IPP_TAG_LANGUAGE :
692 case IPP_TAG_MIMETYPE :
693 for (i = 0; i < count; i ++)
694 printf(" %s\n", ippGetString(attr, i, NULL));
695 break;
696
697 case IPP_TAG_STRING :
698 for (i = 0; i < count; i ++)
699 {
700 int j, len;
701 unsigned char *data = ippGetOctetString(attr, i, &len);
702
703 fputs(" ", stdout);
704 for (j = 0; j < len; j ++)
705 {
706 if (data[j] < ' ' || data[j] >= 0x7f)
707 printf("<%02X>", data[j]);
708 else
709 putchar(data[j]);
710 }
711 putchar('\n');
712 }
713 break;
714
715 case IPP_TAG_BOOLEAN :
716 break;
717
718 default :
719 printf(" %s\n", ippTagString(ippGetValueTag(attr)));
720 break;
721 }
722 }
723
724 }
725 else if (cupsCheckDestSupported(http, dest, dinfo, option, value))
726 puts("YES");
727 else
728 puts("NO");
729 }
730
731
732 /*
733 * 'usage()' - Show program usage.
734 */
735
736 static void
usage(const char * arg)737 usage(const char *arg) /* I - Argument for usage message */
738 {
739 if (arg)
740 printf("testdest: Unknown option \"%s\".\n", arg);
741
742 puts("Usage:");
743 puts(" ./testdest name [operation ...]");
744 puts(" ./testdest ipp://... [operation ...]");
745 puts(" ./testdest ipps://... [operation ...]");
746 puts(" ./testdest --enum [grayscale] [color] [duplex] [staple] [small]\n"
747 " [medium] [large]");
748 puts("");
749 puts("Operations:");
750 puts(" conflicts options");
751 puts(" default option");
752 puts(" localize option [value]");
753 puts(" media [borderless] [duplex] [exact] [ready] [name or size]");
754 puts(" print filename [options]");
755 puts(" supported [option [value]]");
756
757 exit(arg != NULL);
758 }
759