Imported Upstream version 2.2.0
[platform/upstream/cups.git] / cups / testdest.c
1 /*
2  * CUPS destination API test program for CUPS.
3  *
4  * Copyright 2012-2016 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  * file is 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 */
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
109     dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, argv[1], NULL);
110
111   if (!dest)
112   {
113     printf("testdest: Unable to get destination \"%s\": %s\n", argv[1], cupsLastErrorString());
114     return (1);
115   }
116
117   if ((http = cupsConnectDest(dest, CUPS_DEST_FLAGS_NONE, 30000, NULL, NULL, 0, NULL, NULL)) == NULL)
118   {
119     printf("testdest: Unable to connect to destination \"%s\": %s\n", argv[1], cupsLastErrorString());
120     return (1);
121   }
122
123   if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL)
124   {
125     printf("testdest: Unable to get information for destination \"%s\": %s\n", argv[1], cupsLastErrorString());
126     return (1);
127   }
128
129   if (argc == 2 || (!strcmp(argv[2], "supported") && argc < 6))
130   {
131     if (argc > 3)
132       show_supported(http, dest, dinfo, argv[3], argv[4]);
133     else if (argc > 2)
134       show_supported(http, dest, dinfo, argv[3], NULL);
135     else
136       show_supported(http, dest, dinfo, NULL, NULL);
137   }
138   else if (!strcmp(argv[2], "conflicts") && argc > 3)
139   {
140     int                 i,              /* Looping var */
141                         num_options = 0;/* Number of options */
142     cups_option_t       *options = NULL;/* Options */
143
144     for (i = 3; i < argc; i ++)
145       num_options = cupsParseOptions(argv[i], num_options, &options);
146
147     show_conflicts(http, dest, dinfo, num_options, options);
148   }
149   else if (!strcmp(argv[2], "default") && argc == 4)
150   {
151     show_default(http, dest, dinfo, argv[3]);
152   }
153   else if (!strcmp(argv[2], "localize") && argc < 6)
154   {
155     if (argc > 3)
156       localize(http, dest, dinfo, argv[3], argv[4]);
157     else if (argc > 2)
158       localize(http, dest, dinfo, argv[3], NULL);
159     else
160       localize(http, dest, dinfo, NULL, NULL);
161   }
162   else if (!strcmp(argv[2], "media"))
163   {
164     int         i;                      /* Looping var */
165     const char  *name = NULL;           /* Media name, if any */
166     unsigned    flags = CUPS_MEDIA_FLAGS_DEFAULT;
167                                         /* Media selection flags */
168
169     for (i = 3; i < argc; i ++)
170     {
171       if (!strcmp(argv[i], "borderless"))
172         flags = CUPS_MEDIA_FLAGS_BORDERLESS;
173       else if (!strcmp(argv[i], "duplex"))
174         flags = CUPS_MEDIA_FLAGS_DUPLEX;
175       else if (!strcmp(argv[i], "exact"))
176         flags = CUPS_MEDIA_FLAGS_EXACT;
177       else if (!strcmp(argv[i], "ready"))
178         flags = CUPS_MEDIA_FLAGS_READY;
179       else if (name)
180         usage(argv[i]);
181       else
182         name = argv[i];
183     }
184
185     show_media(http, dest, dinfo, flags, name);
186   }
187   else if (!strcmp(argv[2], "print") && argc > 3)
188   {
189     int                 i,              /* Looping var */
190                         num_options = 0;/* Number of options */
191     cups_option_t       *options = NULL;/* Options */
192
193     for (i = 4; i < argc; i ++)
194       num_options = cupsParseOptions(argv[i], num_options, &options);
195
196     print_file(http, dest, dinfo, argv[3], num_options, options);
197   }
198   else
199     usage(argv[2]);
200
201   return (0);
202 }
203
204
205 /*
206  * 'enum_cb()' - Print the results from the enumeration of destinations.
207  */
208
209 static int                              /* O - 1 to continue */
210 enum_cb(void        *user_data,         /* I - User data (unused) */
211         unsigned    flags,              /* I - Flags */
212         cups_dest_t *dest)              /* I - Destination */
213 {
214   int   i;                              /* Looping var */
215
216
217   (void)user_data;
218   (void)flags;
219
220   if (dest->instance)
221     printf("%s/%s:\n", dest->name, dest->instance);
222   else
223     printf("%s:\n", dest->name);
224
225   for (i = 0; i < dest->num_options; i ++)
226     printf("    %s=\"%s\"\n", dest->options[i].name, dest->options[i].value);
227
228   return (1);
229 }
230
231
232 /*
233  * 'localize()' - Localize an option and value.
234  */
235
236 static void
237 localize(http_t       *http,            /* I - Connection to destination */
238          cups_dest_t  *dest,            /* I - Destination */
239          cups_dinfo_t *dinfo,           /* I - Destination information */
240          const char   *option,          /* I - Option */
241          const char   *value)           /* I - Value, if any */
242 {
243   ipp_attribute_t       *attr;          /* Attribute */
244   int                   i,              /* Looping var */
245                         count;          /* Number of values */
246
247
248   if (!option)
249   {
250     attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes");
251     if (attr)
252     {
253       count = ippGetCount(attr);
254       for (i = 0; i < count; i ++)
255         localize(http, dest, dinfo, ippGetString(attr, i, NULL), NULL);
256     }
257     else
258     {
259       static const char * const options[] =
260       {                                 /* List of standard options */
261         CUPS_COPIES,
262         CUPS_FINISHINGS,
263         CUPS_MEDIA,
264         CUPS_NUMBER_UP,
265         CUPS_ORIENTATION,
266         CUPS_PRINT_COLOR_MODE,
267         CUPS_PRINT_QUALITY,
268         CUPS_SIDES
269       };
270
271       puts("No job-creation-attributes-supported attribute, probing instead.");
272
273       for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++)
274         if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL))
275           localize(http, dest, dinfo, options[i], NULL);
276     }
277   }
278   else if (!value)
279   {
280     printf("%s (%s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option));
281
282     if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL)
283     {
284       count = ippGetCount(attr);
285
286       switch (ippGetValueTag(attr))
287       {
288         case IPP_TAG_INTEGER :
289             for (i = 0; i < count; i ++)
290               printf("  %d\n", ippGetInteger(attr, i));
291             break;
292
293         case IPP_TAG_ENUM :
294             for (i = 0; i < count; i ++)
295               printf("  %s\n", ippEnumString(option, ippGetInteger(attr, i)));
296             break;
297
298         case IPP_TAG_RANGE :
299             for (i = 0; i < count; i ++)
300             {
301               int upper, lower = ippGetRange(attr, i, &upper);
302
303               printf("  %d-%d\n", lower, upper);
304             }
305             break;
306
307         case IPP_TAG_RESOLUTION :
308             for (i = 0; i < count; i ++)
309             {
310               int xres, yres;
311               ipp_res_t units;
312               xres = ippGetResolution(attr, i, &yres, &units);
313
314               if (xres == yres)
315                 printf("  %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
316               else
317                 printf("  %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
318             }
319             break;
320
321         case IPP_TAG_TEXTLANG :
322         case IPP_TAG_NAMELANG :
323         case IPP_TAG_TEXT :
324         case IPP_TAG_NAME :
325         case IPP_TAG_KEYWORD :
326         case IPP_TAG_URI :
327         case IPP_TAG_URISCHEME :
328         case IPP_TAG_CHARSET :
329         case IPP_TAG_LANGUAGE :
330         case IPP_TAG_MIMETYPE :
331             for (i = 0; i < count; i ++)
332               printf("  %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL)));
333             break;
334
335         case IPP_TAG_STRING :
336             for (i = 0; i < count; i ++)
337             {
338               int j, len;
339               unsigned char *data = ippGetOctetString(attr, i, &len);
340
341               fputs("  ", stdout);
342               for (j = 0; j < len; j ++)
343               {
344                 if (data[j] < ' ' || data[j] >= 0x7f)
345                   printf("<%02X>", data[j]);
346                 else
347                   putchar(data[j]);
348               }
349               putchar('\n');
350             }
351             break;
352
353         case IPP_TAG_BOOLEAN :
354             break;
355
356         default :
357             printf("  %s\n", ippTagString(ippGetValueTag(attr)));
358             break;
359       }
360     }
361
362   }
363   else
364     puts(cupsLocalizeDestValue(http, dest, dinfo, option, value));
365 }
366
367
368 /*
369  * 'print_file()' - Print a file.
370  */
371
372 static void
373 print_file(http_t        *http,         /* I - Connection to destination */
374            cups_dest_t   *dest,         /* I - Destination */
375            cups_dinfo_t  *dinfo,        /* I - Destination information */
376            const char    *filename,     /* I - File to print */
377            int           num_options,   /* I - Number of options */
378            cups_option_t *options)      /* I - Options */
379 {
380   cups_file_t   *fp;                    /* File to print */
381   int           job_id;                 /* Job ID */
382   ipp_status_t  status;                 /* Submission status */
383   const char    *title;                 /* Title of job */
384   char          buffer[32768];          /* File buffer */
385   ssize_t       bytes;                  /* Bytes read/to write */
386
387
388   if ((fp = cupsFileOpen(filename, "r")) == NULL)
389   {
390     printf("Unable to open \"%s\": %s\n", filename, strerror(errno));
391     return;
392   }
393
394   if ((title = strrchr(filename, '/')) != NULL)
395     title ++;
396   else
397     title = filename;
398
399   if ((status = cupsCreateDestJob(http, dest, dinfo, &job_id, title, num_options, options)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
400   {
401     printf("Unable to create job: %s\n", cupsLastErrorString());
402     cupsFileClose(fp);
403     return;
404   }
405
406   printf("Created job ID: %d\n", job_id);
407
408   if (cupsStartDestDocument(http, dest, dinfo, job_id, title, CUPS_FORMAT_AUTO, 0, NULL, 1) != HTTP_STATUS_CONTINUE)
409   {
410     printf("Unable to send document: %s\n", cupsLastErrorString());
411     cupsFileClose(fp);
412     return;
413   }
414
415   while ((bytes = cupsFileRead(fp, buffer, sizeof(buffer))) > 0)
416   {
417     if (cupsWriteRequestData(http, buffer, (size_t)bytes) != HTTP_STATUS_CONTINUE)
418     {
419       printf("Unable to write document data: %s\n", cupsLastErrorString());
420       break;
421     }
422   }
423
424   cupsFileClose(fp);
425
426   if ((status = cupsFinishDestDocument(http, dest, dinfo)) > IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED)
427   {
428     printf("Unable to send document: %s\n", cupsLastErrorString());
429     return;
430   }
431
432   puts("Job queued.");
433 }
434
435
436 /*
437  * 'show_conflicts()' - Show conflicts for selected options.
438  */
439
440 static void
441 show_conflicts(
442     http_t        *http,                /* I - Connection to destination */
443     cups_dest_t   *dest,                /* I - Destination */
444     cups_dinfo_t  *dinfo,               /* I - Destination information */
445     int           num_options,          /* I - Number of options */
446     cups_option_t *options)             /* I - Options */
447 {
448   (void)http;
449   (void)dest;
450   (void)dinfo;
451   (void)num_options;
452   (void)options;
453 }
454
455
456 /*
457  * 'show_default()' - Show default value for option.
458  */
459
460 static void
461 show_default(http_t       *http,        /* I - Connection to destination */
462              cups_dest_t  *dest,        /* I - Destination */
463              cups_dinfo_t *dinfo,       /* I - Destination information */
464              const char  *option)       /* I - Option */
465 {
466   (void)http;
467   (void)dest;
468   (void)dinfo;
469   (void)option;
470 }
471
472
473 /*
474  * 'show_media()' - Show available media.
475  */
476
477 static void
478 show_media(http_t       *http,          /* I - Connection to destination */
479            cups_dest_t  *dest,          /* I - Destination */
480            cups_dinfo_t *dinfo,         /* I - Destination information */
481            unsigned     flags,          /* I - Media flags */
482            const char   *name)          /* I - Size name */
483 {
484   int           i,                      /* Looping var */
485                 count;                  /* Number of sizes */
486   cups_size_t   size;                   /* Media size info */
487
488
489   if (name)
490   {
491     double      dw, dl;                 /* Width and length from name */
492     char        units[32];              /* Units */
493     int         width,                  /* Width in 100ths of millimeters */
494                 length;                 /* Length in 100ths of millimeters */
495
496
497     if (sscanf(name, "%lfx%lf%31s", &dw, &dl, units) == 3)
498     {
499       if (!strcmp(units, "in"))
500       {
501         width  = (int)(dw * 2540.0);
502         length = (int)(dl * 2540.0);
503       }
504       else if (!strcmp(units, "mm"))
505       {
506         width  = (int)(dw * 100.0);
507         length = (int)(dl * 100.0);
508       }
509       else
510       {
511         puts("  bad units in size");
512         return;
513       }
514
515       if (cupsGetDestMediaBySize(http, dest, dinfo, width, length, flags, &size))
516       {
517         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);
518       }
519       else
520       {
521         puts("  not supported");
522       }
523     }
524     else if (cupsGetDestMediaByName(http, dest, dinfo, name, flags, &size))
525     {
526       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);
527     }
528     else
529     {
530       puts("  not supported");
531     }
532   }
533   else
534   {
535     count = cupsGetDestMediaCount(http, dest, dinfo, flags);
536     printf("%d size%s:\n", count, count == 1 ? "" : "s");
537
538     for (i = 0; i < count; i ++)
539     {
540       if (cupsGetDestMediaByIndex(http, dest, dinfo, i, flags, &size))
541         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);
542       else
543         puts("  error");
544     }
545   }
546 }
547
548
549 /*
550  * 'show_supported()' - Show supported options, values, etc.
551  */
552
553 static void
554 show_supported(http_t       *http,      /* I - Connection to destination */
555                cups_dest_t  *dest,      /* I - Destination */
556                cups_dinfo_t *dinfo,     /* I - Destination information */
557                const char   *option,    /* I - Option, if any */
558                const char   *value)     /* I - Value, if any */
559 {
560   ipp_attribute_t       *attr;          /* Attribute */
561   int                   i,              /* Looping var */
562                         count;          /* Number of values */
563
564
565   if (!option)
566   {
567     attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes");
568     if (attr)
569     {
570       count = ippGetCount(attr);
571       for (i = 0; i < count; i ++)
572         show_supported(http, dest, dinfo, ippGetString(attr, i, NULL), NULL);
573     }
574     else
575     {
576       static const char * const options[] =
577       {                                 /* List of standard options */
578         CUPS_COPIES,
579         CUPS_FINISHINGS,
580         CUPS_MEDIA,
581         CUPS_NUMBER_UP,
582         CUPS_ORIENTATION,
583         CUPS_PRINT_COLOR_MODE,
584         CUPS_PRINT_QUALITY,
585         CUPS_SIDES
586       };
587
588       puts("No job-creation-attributes-supported attribute, probing instead.");
589
590       for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++)
591         if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL))
592           show_supported(http, dest, dinfo, options[i], NULL);
593     }
594   }
595   else if (!value)
596   {
597     puts(option);
598     if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL)
599     {
600       count = ippGetCount(attr);
601
602       switch (ippGetValueTag(attr))
603       {
604         case IPP_TAG_INTEGER :
605             for (i = 0; i < count; i ++)
606               printf("  %d\n", ippGetInteger(attr, i));
607             break;
608
609         case IPP_TAG_ENUM :
610             for (i = 0; i < count; i ++)
611               printf("  %s\n", ippEnumString(option, ippGetInteger(attr, i)));
612             break;
613
614         case IPP_TAG_RANGE :
615             for (i = 0; i < count; i ++)
616             {
617               int upper, lower = ippGetRange(attr, i, &upper);
618
619               printf("  %d-%d\n", lower, upper);
620             }
621             break;
622
623         case IPP_TAG_RESOLUTION :
624             for (i = 0; i < count; i ++)
625             {
626               int xres, yres;
627               ipp_res_t units;
628               xres = ippGetResolution(attr, i, &yres, &units);
629
630               if (xres == yres)
631                 printf("  %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
632               else
633                 printf("  %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
634             }
635             break;
636
637         case IPP_TAG_TEXTLANG :
638         case IPP_TAG_NAMELANG :
639         case IPP_TAG_TEXT :
640         case IPP_TAG_NAME :
641         case IPP_TAG_KEYWORD :
642         case IPP_TAG_URI :
643         case IPP_TAG_URISCHEME :
644         case IPP_TAG_CHARSET :
645         case IPP_TAG_LANGUAGE :
646         case IPP_TAG_MIMETYPE :
647             for (i = 0; i < count; i ++)
648               printf("  %s\n", ippGetString(attr, i, NULL));
649             break;
650
651         case IPP_TAG_STRING :
652             for (i = 0; i < count; i ++)
653             {
654               int j, len;
655               unsigned char *data = ippGetOctetString(attr, i, &len);
656
657               fputs("  ", stdout);
658               for (j = 0; j < len; j ++)
659               {
660                 if (data[j] < ' ' || data[j] >= 0x7f)
661                   printf("<%02X>", data[j]);
662                 else
663                   putchar(data[j]);
664               }
665               putchar('\n');
666             }
667             break;
668
669         case IPP_TAG_BOOLEAN :
670             break;
671
672         default :
673             printf("  %s\n", ippTagString(ippGetValueTag(attr)));
674             break;
675       }
676     }
677
678   }
679   else if (cupsCheckDestSupported(http, dest, dinfo, option, value))
680     puts("YES");
681   else
682     puts("NO");
683 }
684
685
686 /*
687  * 'usage()' - Show program usage.
688  */
689
690 static void
691 usage(const char *arg)                  /* I - Argument for usage message */
692 {
693   if (arg)
694     printf("testdest: Unknown option \"%s\".\n", arg);
695
696   puts("Usage:");
697   puts("  ./testdest name [operation ...]");
698   puts("  ./testdest ipp://... [operation ...]");
699   puts("  ./testdest ipps://... [operation ...]");
700   puts("  ./testdest --enum [grayscale] [color] [duplex] [staple] [small]\n"
701        "                    [medium] [large]");
702   puts("");
703   puts("Operations:");
704   puts("  conflicts options");
705   puts("  default option");
706   puts("  localize option [value]");
707   puts("  media [borderless] [duplex] [exact] [ready] [name or size]");
708   puts("  print filename [options]");
709   puts("  supported [option [value]]");
710
711   exit(arg != NULL);
712 }