1 /*
2 * "lpinfo" command for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products.
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 <cups/cups-private.h>
16 #include <cups/adminutil.h>
17
18
19 /*
20 * Local functions...
21 */
22
23 static void device_cb(const char *device_class, const char *device_id,
24 const char *device_info,
25 const char *device_make_and_model,
26 const char *device_uri, const char *device_location,
27 void *user_data);
28 static int show_devices(int long_status, int timeout,
29 const char *include_schemes,
30 const char *exclude_schemes);
31 static int show_models(int long_status,
32 const char *device_id, const char *language,
33 const char *make_model, const char *product,
34 const char *include_schemes,
35 const char *exclude_schemes);
36 static void usage(void) _CUPS_NORETURN;
37
38
39 /*
40 * 'main()' - Parse options and show status information.
41 */
42
43 int
main(int argc,char * argv[])44 main(int argc, /* I - Number of command-line arguments */
45 char *argv[]) /* I - Command-line arguments */
46 {
47 int i; /* Looping var */
48 int long_status; /* Long listing? */
49 const char *opt, /* Option pointer */
50 *device_id, /* 1284 device ID */
51 *language, /* Language */
52 *make_model, /* Make and model */
53 *product, /* Product */
54 *include_schemes, /* Schemes to include */
55 *exclude_schemes; /* Schemes to exclude */
56 int timeout; /* Device timeout */
57
58
59 _cupsSetLocale(argv);
60
61 long_status = 0;
62 device_id = NULL;
63 language = NULL;
64 make_model = NULL;
65 product = NULL;
66 include_schemes = CUPS_INCLUDE_ALL;
67 exclude_schemes = CUPS_EXCLUDE_NONE;
68 timeout = CUPS_TIMEOUT_DEFAULT;
69
70 for (i = 1; i < argc; i ++)
71 {
72 if (!strcmp(argv[i], "--device-id"))
73 {
74 i ++;
75
76 if (i < argc)
77 device_id = argv[i];
78 else
79 {
80 _cupsLangPuts(stderr, _("lpinfo: Expected 1284 device ID string after \"--device-id\"."));
81 usage();
82 }
83 }
84 else if (!strncmp(argv[i], "--device-id=", 12) && argv[i][12])
85 {
86 device_id = argv[i] + 12;
87 }
88 else if (!strcmp(argv[i], "--exclude-schemes"))
89 {
90 i ++;
91
92 if (i < argc)
93 exclude_schemes = argv[i];
94 else
95 {
96 _cupsLangPuts(stderr, _("lpinfo: Expected scheme list after \"--exclude-schemes\"."));
97 usage();
98 }
99 }
100 else if (!strncmp(argv[i], "--exclude-schemes=", 18) && argv[i][18])
101 {
102 exclude_schemes = argv[i] + 18;
103 }
104 else if (!strcmp(argv[i], "--help"))
105 usage();
106 else if (!strcmp(argv[i], "--include-schemes"))
107 {
108 i ++;
109
110 if (i < argc)
111 include_schemes = argv[i];
112 else
113 {
114 _cupsLangPuts(stderr, _("lpinfo: Expected scheme list after \"--include-schemes\"."));
115 usage();
116 }
117 }
118 else if (!strncmp(argv[i], "--include-schemes=", 18) && argv[i][18])
119 {
120 include_schemes = argv[i] + 18;
121 }
122 else if (!strcmp(argv[i], "--language"))
123 {
124 i ++;
125 if (i < argc)
126 language = argv[i];
127 else
128 {
129 _cupsLangPuts(stderr, _("lpinfo: Expected language after \"--language\"."));
130 usage();
131 }
132 }
133 else if (!strncmp(argv[i], "--language=", 11) && argv[i][11])
134 {
135 language = argv[i] + 11;
136 }
137 else if (!strcmp(argv[i], "--make-and-model"))
138 {
139 i ++;
140 if (i < argc)
141 make_model= argv[i];
142 else
143 {
144 _cupsLangPuts(stderr, _("lpinfo: Expected make and model after \"--make-and-model\"."));
145 usage();
146 }
147 }
148 else if (!strncmp(argv[i], "--make-and-model=", 17) && argv[i][17])
149 {
150 make_model = argv[i] + 17;
151 }
152 else if (!strcmp(argv[i], "--product"))
153 {
154 i ++;
155 if (i < argc)
156 product = argv[i];
157 else
158 {
159 _cupsLangPuts(stderr, _("lpinfo: Expected product string after \"--product\"."));
160 usage();
161 }
162 }
163 else if (!strncmp(argv[i], "--product=", 10) && argv[i][10])
164 {
165 product = argv[i] + 10;
166 }
167 else if (!strcmp(argv[i], "--timeout"))
168 {
169 i ++;
170 if (i < argc)
171 timeout = atoi(argv[i]);
172 else
173 {
174 _cupsLangPuts(stderr, _("lpinfo: Expected timeout after \"--timeout\"."));
175 usage();
176 }
177 }
178 else if (!strncmp(argv[i], "--timeout=", 10) && argv[i][10])
179 {
180 timeout = atoi(argv[i] + 10);
181 }
182 else if (argv[i][0] == '-')
183 {
184 for (opt = argv[i] + 1; *opt; opt ++)
185 {
186 switch (*opt)
187 {
188 case 'E' : /* Encrypt */
189 #ifdef HAVE_SSL
190 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
191 #else
192 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]);
193 #endif /* HAVE_SSL */
194 break;
195
196 case 'h' : /* Connect to host */
197 if (opt[1] != '\0')
198 {
199 cupsSetServer(opt + 1);
200 opt += strlen(opt) - 1;
201 }
202 else
203 {
204 i ++;
205
206 if (i >= argc)
207 {
208 _cupsLangPuts(stderr, _("Error: need hostname after \"-h\" option."));
209 usage();
210 }
211
212 cupsSetServer(argv[i]);
213 }
214 break;
215
216 case 'l' : /* Show long listing */
217 long_status = 1;
218 break;
219
220 case 'm' : /* Show models */
221 if (show_models(long_status, device_id, language, make_model, product, include_schemes, exclude_schemes))
222 return (1);
223 break;
224
225 case 'v' : /* Show available devices */
226 if (show_devices(long_status, timeout, include_schemes, exclude_schemes))
227 return (1);
228 break;
229
230 default :
231 _cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), argv[0], *opt);
232 usage();
233 }
234 }
235 }
236 else
237 {
238 _cupsLangPrintf(stderr, _("%s: Unknown argument \"%s\"."), argv[0], argv[i]);
239 usage();
240 }
241 }
242
243 return (0);
244 }
245
246
247 /*
248 * 'device_cb()' - Device callback.
249 */
250
251 static void
device_cb(const char * device_class,const char * device_id,const char * device_info,const char * device_make_and_model,const char * device_uri,const char * device_location,void * user_data)252 device_cb(
253 const char *device_class, /* I - device-class string */
254 const char *device_id, /* I - device-id string */
255 const char *device_info, /* I - device-info string */
256 const char *device_make_and_model, /* I - device-make-and-model string */
257 const char *device_uri, /* I - device-uri string */
258 const char *device_location, /* I - device-location string */
259 void *user_data) /* I - User data */
260 {
261 int *long_status; /* Show verbose info? */
262
263
264 /*
265 * Display the device...
266 */
267
268 long_status = (int *)user_data;
269
270 if (*long_status)
271 {
272 _cupsLangPrintf(stdout,
273 _("Device: uri = %s\n"
274 " class = %s\n"
275 " info = %s\n"
276 " make-and-model = %s\n"
277 " device-id = %s\n"
278 " location = %s"),
279 device_uri, device_class, device_info,
280 device_make_and_model, device_id, device_location);
281 }
282 else
283 _cupsLangPrintf(stdout, "%s %s", device_class, device_uri);
284 }
285
286
287 /*
288 * 'show_devices()' - Show available devices.
289 */
290
291 static int /* O - 0 on success, 1 on failure */
show_devices(int long_status,int timeout,const char * include_schemes,const char * exclude_schemes)292 show_devices(
293 int long_status, /* I - Long status report? */
294 int timeout, /* I - Timeout */
295 const char *include_schemes, /* I - List of schemes to include */
296 const char *exclude_schemes) /* I - List of schemes to exclude */
297 {
298 if (cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include_schemes,
299 exclude_schemes, device_cb, &long_status) != IPP_OK)
300 {
301 _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
302 return (1);
303 }
304
305 return (0);
306 }
307
308
309 /*
310 * 'show_models()' - Show available PPDs.
311 */
312
313 static int /* O - 0 on success, 1 on failure */
show_models(int long_status,const char * device_id,const char * language,const char * make_model,const char * product,const char * include_schemes,const char * exclude_schemes)314 show_models(
315 int long_status, /* I - Long status report? */
316 const char *device_id, /* I - 1284 device ID */
317 const char *language, /* I - Language */
318 const char *make_model, /* I - Make and model */
319 const char *product, /* I - Product */
320 const char *include_schemes, /* I - List of schemes to include */
321 const char *exclude_schemes) /* I - List of schemes to exclude */
322 {
323 ipp_t *request, /* IPP Request */
324 *response; /* IPP Response */
325 ipp_attribute_t *attr; /* Current attribute */
326 const char *ppd_device_id, /* Pointer to ppd-device-id */
327 *ppd_language, /* Pointer to ppd-natural-language */
328 *ppd_make_model, /* Pointer to ppd-make-and-model */
329 *ppd_name; /* Pointer to ppd-name */
330 cups_option_t option; /* in/exclude-schemes option */
331
332
333 /*
334 * Build a CUPS_GET_PPDS request...
335 */
336
337 request = ippNewRequest(CUPS_GET_PPDS);
338
339 if (device_id)
340 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-device-id",
341 NULL, device_id);
342 if (language)
343 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "ppd-language",
344 NULL, language);
345 if (make_model)
346 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make-and-model",
347 NULL, make_model);
348 if (product)
349 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-product",
350 NULL, product);
351
352 if (include_schemes)
353 {
354 option.name = "include-schemes";
355 option.value = (char *)include_schemes;
356
357 cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
358 }
359
360 if (exclude_schemes)
361 {
362 option.name = "exclude-schemes";
363 option.value = (char *)exclude_schemes;
364
365 cupsEncodeOptions2(request, 1, &option, IPP_TAG_OPERATION);
366 }
367
368 /*
369 * Do the request and get back a response...
370 */
371
372 if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
373 {
374 /*
375 * Loop through the device list and display them...
376 */
377
378 if (response->request.status.status_code > IPP_OK_CONFLICT)
379 {
380 _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
381 ippDelete(response);
382 return (1);
383 }
384
385 for (attr = response->attrs; attr != NULL; attr = attr->next)
386 {
387 /*
388 * Skip leading attributes until we hit a PPD...
389 */
390
391 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
392 attr = attr->next;
393
394 if (attr == NULL)
395 break;
396
397 /*
398 * Pull the needed attributes from this PPD...
399 */
400
401 ppd_device_id = "NONE";
402 ppd_language = NULL;
403 ppd_make_model = NULL;
404 ppd_name = NULL;
405
406 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
407 {
408 if (!strcmp(attr->name, "ppd-device-id") &&
409 attr->value_tag == IPP_TAG_TEXT)
410 ppd_device_id = attr->values[0].string.text;
411 else if (!strcmp(attr->name, "ppd-natural-language") &&
412 attr->value_tag == IPP_TAG_LANGUAGE)
413 ppd_language = attr->values[0].string.text;
414 else if (!strcmp(attr->name, "ppd-make-and-model") &&
415 attr->value_tag == IPP_TAG_TEXT)
416 ppd_make_model = attr->values[0].string.text;
417 else if (!strcmp(attr->name, "ppd-name") &&
418 attr->value_tag == IPP_TAG_NAME)
419 ppd_name = attr->values[0].string.text;
420
421 attr = attr->next;
422 }
423
424 /*
425 * See if we have everything needed...
426 */
427
428 if (ppd_language == NULL || ppd_make_model == NULL || ppd_name == NULL)
429 {
430 if (attr == NULL)
431 break;
432 else
433 continue;
434 }
435
436 /*
437 * Display the device...
438 */
439
440 if (long_status)
441 {
442 _cupsLangPrintf(stdout,
443 _("Model: name = %s\n"
444 " natural_language = %s\n"
445 " make-and-model = %s\n"
446 " device-id = %s"),
447 ppd_name, ppd_language, ppd_make_model, ppd_device_id);
448 }
449 else
450 _cupsLangPrintf(stdout, "%s %s", ppd_name, ppd_make_model);
451
452 if (attr == NULL)
453 break;
454 }
455
456 ippDelete(response);
457
458 /*
459 * Show the "everywhere" model, which is handled by the lpadmin command...
460 */
461
462 if ((!include_schemes || strstr(include_schemes, "everywhere")) && (!exclude_schemes || !strstr(exclude_schemes, "everywhere")))
463 {
464 if (long_status)
465 {
466 _cupsLangPrintf(stdout,
467 _("Model: name = %s\n"
468 " natural_language = %s\n"
469 " make-and-model = %s\n"
470 " device-id = %s"),
471 "everywhere", cupsLangDefault()->language, "IPP Everywhere™", "CMD:PwgRaster");
472 }
473 else
474 _cupsLangPuts(stdout, "everywhere IPP Everywhere");
475 }
476 }
477 else
478 {
479 _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString());
480
481 return (1);
482 }
483
484 return (0);
485 }
486
487
488 /*
489 * 'usage()' - Show program usage and exit.
490 */
491
492 static void
usage(void)493 usage(void)
494 {
495 _cupsLangPuts(stdout, _("Usage: lpinfo [options] -m\n"
496 " lpinfo [options] -v"));
497 _cupsLangPuts(stdout, _("Options:"));
498 _cupsLangPuts(stdout, _("-E Encrypt the connection to the server"));
499 _cupsLangPuts(stdout, _("-h server[:port] Connect to the named server and port"));
500 _cupsLangPuts(stdout, _("-l Show verbose (long) output"));
501 _cupsLangPuts(stdout, _("-m Show models"));
502 _cupsLangPuts(stdout, _("-U username Specify the username to use for authentication"));
503 _cupsLangPuts(stdout, _("-v Show devices"));
504 _cupsLangPuts(stdout, _("--device-id device-id Show models matching the given IEEE 1284 device ID"));
505 _cupsLangPuts(stdout, _("--exclude-schemes scheme-list\n"
506 " Exclude the specified URI schemes"));
507 _cupsLangPuts(stdout, _("--include-schemes scheme-list\n"
508 " Include only the specified URI schemes"));
509 _cupsLangPuts(stdout, _("--language locale Show models matching the given locale"));
510 _cupsLangPuts(stdout, _("--make-and-model name Show models matching the given make and model name"));
511 _cupsLangPuts(stdout, _("--product name Show models matching the given PostScript product"));
512 _cupsLangPuts(stdout, _("--timeout seconds Specify the maximum number of seconds to discover devices"));
513
514 exit(1);
515 }
516