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