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