1 /*
2  * Threaded test program for CUPS.
3  *
4  * Copyright © 2012-2019 by Apple Inc.
5  *
6  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
7  * information.
8  */
9 
10 /*
11  * Include necessary headers...
12  */
13 
14 #include <stdio.h>
15 #include <errno.h>
16 #include <cups/cups.h>
17 #include <cups/thread-private.h>
18 
19 
20 /*
21  * Local functions...
22  */
23 
24 static int	enum_dests_cb(void *_name, unsigned flags, cups_dest_t *dest);
25 static void	*run_query(cups_dest_t *dest);
26 static void	show_supported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value);
27 
28 
29 /*
30  * 'main()' - Main entry.
31  */
32 
33 int					/* O - Exit status */
main(int argc,char * argv[])34 main(int  argc,				/* I - Number of command-line arguments */
35      char *argv[])			/* I - Command-line arguments */
36 {
37  /*
38   * Go through all the available destinations to find the requested one...
39   */
40 
41   (void)argc;
42 
43   cupsEnumDests(CUPS_DEST_FLAGS_NONE, -1, NULL, 0, 0, enum_dests_cb, argv[1]);
44 
45   return (0);
46 }
47 
48 
49 /*
50  * 'enum_dests_cb()' - Destination enumeration function...
51  */
52 
53 static int				/* O - 1 to continue, 0 to stop */
enum_dests_cb(void * _name,unsigned flags,cups_dest_t * dest)54 enum_dests_cb(void        *_name,	/* I - Printer name, if any */
55               unsigned    flags,	/* I - Enumeration flags */
56               cups_dest_t *dest)	/* I - Found destination */
57 {
58   const char		*name = (const char *)_name;
59 					/* Printer name */
60   cups_dest_t		*cdest;		/* Copied destination */
61 
62 
63   (void)flags;
64 
65  /*
66   * If a name was specified, compare it...
67   */
68 
69   if (name && strcasecmp(name, dest->name))
70     return (1);				/* Continue */
71 
72  /*
73   * Copy the destination and run the query on a separate thread...
74   */
75 
76   cupsCopyDest(dest, 0, &cdest);
77   _cupsThreadWait(_cupsThreadCreate((_cups_thread_func_t)run_query, cdest));
78 
79   cupsFreeDests(1, cdest);
80 
81  /*
82   * Continue if no name was specified or the name matches...
83   */
84 
85   return (!name || !strcasecmp(name, dest->name));
86 }
87 
88 
89 /*
90  * 'run_query()' - Query printer capabilities on a separate thread.
91  */
92 
93 static void *				/* O - Return value (not used) */
run_query(cups_dest_t * dest)94 run_query(cups_dest_t *dest)		/* I - Destination to query */
95 {
96   http_t	*http;			/* Connection to destination */
97   cups_dinfo_t	*dinfo;			/* Destination info */
98   unsigned	dflags = CUPS_DEST_FLAGS_NONE;
99 					/* Destination flags */
100 
101 
102   if ((http = cupsConnectDest(dest, dflags, 300, NULL, NULL, 0, NULL, NULL)) == NULL)
103   {
104     printf("testthreads: Unable to connect to destination \"%s\": %s\n", dest->name, cupsLastErrorString());
105     return (NULL);
106   }
107 
108   if ((dinfo = cupsCopyDestInfo(http, dest)) == NULL)
109   {
110     printf("testdest: Unable to get information for destination \"%s\": %s\n", dest->name, cupsLastErrorString());
111     return (NULL);
112   }
113 
114   printf("\n%s:\n", dest->name);
115 
116   show_supported(http, dest, dinfo, NULL, NULL);
117 
118   return (NULL);
119 }
120 
121 
122 
123 /*
124  * 'show_supported()' - Show supported options, values, etc.
125  */
126 
127 static void
show_supported(http_t * http,cups_dest_t * dest,cups_dinfo_t * dinfo,const char * option,const char * value)128 show_supported(http_t       *http,	/* I - Connection to destination */
129 	       cups_dest_t  *dest,	/* I - Destination */
130 	       cups_dinfo_t *dinfo,	/* I - Destination information */
131 	       const char   *option,	/* I - Option, if any */
132 	       const char   *value)	/* I - Value, if any */
133 {
134   ipp_attribute_t	*attr;		/* Attribute */
135   int			i,		/* Looping var */
136 			count;		/* Number of values */
137 
138 
139   if (!option)
140   {
141     attr = cupsFindDestSupported(http, dest, dinfo, "job-creation-attributes");
142     if (attr)
143     {
144       count = ippGetCount(attr);
145       for (i = 0; i < count; i ++)
146         show_supported(http, dest, dinfo, ippGetString(attr, i, NULL), NULL);
147     }
148     else
149     {
150       static const char * const options[] =
151       {					/* List of standard options */
152         CUPS_COPIES,
153 	CUPS_FINISHINGS,
154 	CUPS_MEDIA,
155 	CUPS_NUMBER_UP,
156 	CUPS_ORIENTATION,
157 	CUPS_PRINT_COLOR_MODE,
158 	CUPS_PRINT_QUALITY,
159 	CUPS_SIDES
160       };
161 
162       puts("    No job-creation-attributes-supported attribute, probing instead.");
163 
164       for (i = 0; i < (int)(sizeof(options) / sizeof(options[0])); i ++)
165         if (cupsCheckDestSupported(http, dest, dinfo, options[i], NULL))
166 	  show_supported(http, dest, dinfo, options[i], NULL);
167     }
168   }
169   else if (!value)
170   {
171     printf("    %s (%s - %s)\n", option, cupsLocalizeDestOption(http, dest, dinfo, option), cupsCheckDestSupported(http, dest, dinfo, option, NULL) ? "supported" : "not-supported");
172 
173     if ((attr = cupsFindDestSupported(http, dest, dinfo, option)) != NULL)
174     {
175       count = ippGetCount(attr);
176 
177       switch (ippGetValueTag(attr))
178       {
179         case IPP_TAG_INTEGER :
180 	    for (i = 0; i < count; i ++)
181               printf("        %d\n", ippGetInteger(attr, i));
182 	    break;
183 
184         case IPP_TAG_ENUM :
185 	    for (i = 0; i < count; i ++)
186 	    {
187 	      int val = ippGetInteger(attr, i);
188 	      char valstr[256];
189 
190               snprintf(valstr, sizeof(valstr), "%d", val);
191               printf("        %s (%s)\n", ippEnumString(option, ippGetInteger(attr, i)), cupsLocalizeDestValue(http, dest, dinfo, option, valstr));
192             }
193 	    break;
194 
195         case IPP_TAG_RANGE :
196 	    for (i = 0; i < count; i ++)
197 	    {
198 	      int upper, lower = ippGetRange(attr, i, &upper);
199 
200               printf("        %d-%d\n", lower, upper);
201 	    }
202 	    break;
203 
204         case IPP_TAG_RESOLUTION :
205 	    for (i = 0; i < count; i ++)
206 	    {
207 	      int xres, yres;
208 	      ipp_res_t units;
209 	      xres = ippGetResolution(attr, i, &yres, &units);
210 
211               if (xres == yres)
212                 printf("        %d%s\n", xres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
213 	      else
214                 printf("        %dx%d%s\n", xres, yres, units == IPP_RES_PER_INCH ? "dpi" : "dpcm");
215 	    }
216 	    break;
217 
218 	case IPP_TAG_KEYWORD :
219 	    for (i = 0; i < count; i ++)
220               printf("        %s (%s)\n", ippGetString(attr, i, NULL), cupsLocalizeDestValue(http, dest, dinfo, option, ippGetString(attr, i, NULL)));
221 	    break;
222 
223 	case IPP_TAG_TEXTLANG :
224 	case IPP_TAG_NAMELANG :
225 	case IPP_TAG_TEXT :
226 	case IPP_TAG_NAME :
227 	case IPP_TAG_URI :
228 	case IPP_TAG_URISCHEME :
229 	case IPP_TAG_CHARSET :
230 	case IPP_TAG_LANGUAGE :
231 	case IPP_TAG_MIMETYPE :
232 	    for (i = 0; i < count; i ++)
233               printf("        %s\n", ippGetString(attr, i, NULL));
234 	    break;
235 
236         case IPP_TAG_STRING :
237 	    for (i = 0; i < count; i ++)
238 	    {
239 	      int j, len;
240 	      unsigned char *data = ippGetOctetString(attr, i, &len);
241 
242               fputs("        ", stdout);
243 	      for (j = 0; j < len; j ++)
244 	      {
245 	        if (data[j] < ' ' || data[j] >= 0x7f)
246 		  printf("<%02X>", data[j]);
247 		else
248 		  putchar(data[j]);
249               }
250               putchar('\n');
251 	    }
252 	    break;
253 
254         case IPP_TAG_BOOLEAN :
255 	    break;
256 
257         default :
258 	    printf("        %s\n", ippTagString(ippGetValueTag(attr)));
259 	    break;
260       }
261     }
262 
263   }
264   else if (cupsCheckDestSupported(http, dest, dinfo, option, value))
265     puts("YES");
266   else
267     puts("NO");
268 }
269