]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
503b54c9 | 2 | * "lpinfo" command for CUPS. |
ef416fc2 | 3 | * |
8e52928c MS |
4 | * Copyright © 2007-2018 by Apple Inc. |
5 | * Copyright © 1997-2006 by Easy Software Products. | |
ef416fc2 | 6 | * |
8e52928c MS |
7 | * Licensed under Apache License v2.0. See the file "LICENSE" for more |
8 | * information. | |
ef416fc2 | 9 | */ |
10 | ||
11 | /* | |
12 | * Include necessary headers... | |
13 | */ | |
14 | ||
71e16022 | 15 | #include <cups/cups-private.h> |
68c4690a | 16 | #include <cups/adminutil.h> |
ef416fc2 | 17 | |
18 | ||
19 | /* | |
20 | * Local functions... | |
21 | */ | |
22 | ||
73c6236f | 23 | static void device_cb(const char *device_class, const char *device_id, |
ae71f5de MS |
24 | const char *device_info, |
25 | const char *device_make_and_model, | |
749b1e90 MS |
26 | const char *device_uri, const char *device_location, |
27 | void *user_data); | |
ed6e7faf MS |
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, | |
58dc1933 | 32 | const char *device_id, const char *language, |
ed6e7faf MS |
33 | const char *make_model, const char *product, |
34 | const char *include_schemes, | |
35 | const char *exclude_schemes); | |
8e52928c | 36 | static void usage(void) _CUPS_NORETURN; |
ef416fc2 | 37 | |
38 | ||
39 | /* | |
40 | * 'main()' - Parse options and show status information. | |
41 | */ | |
42 | ||
43 | int | |
44 | main(int argc, /* I - Number of command-line arguments */ | |
45 | char *argv[]) /* I - Command-line arguments */ | |
46 | { | |
47 | int i; /* Looping var */ | |
ef416fc2 | 48 | int long_status; /* Long listing? */ |
bdbfacc7 MS |
49 | const char *opt, /* Option pointer */ |
50 | *device_id, /* 1284 device ID */ | |
58dc1933 MS |
51 | *language, /* Language */ |
52 | *make_model, /* Make and model */ | |
ed6e7faf MS |
53 | *product, /* Product */ |
54 | *include_schemes, /* Schemes to include */ | |
55 | *exclude_schemes; /* Schemes to exclude */ | |
58dc1933 | 56 | int timeout; /* Device timeout */ |
ef416fc2 | 57 | |
58 | ||
07725fee | 59 | _cupsSetLocale(argv); |
d09495fa | 60 | |
ed6e7faf MS |
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; | |
ef416fc2 | 69 | |
70 | for (i = 1; i < argc; i ++) | |
bdbfacc7 MS |
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\".")); | |
8e52928c | 81 | usage(); |
bdbfacc7 MS |
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\".")); | |
8e52928c | 97 | usage(); |
bdbfacc7 MS |
98 | } |
99 | } | |
100 | else if (!strncmp(argv[i], "--exclude-schemes=", 18) && argv[i][18]) | |
101 | { | |
102 | exclude_schemes = argv[i] + 18; | |
103 | } | |
8e52928c MS |
104 | else if (!strcmp(argv[i], "--help")) |
105 | usage(); | |
bdbfacc7 MS |
106 | else if (!strcmp(argv[i], "--include-schemes")) |
107 | { | |
108 | i ++; | |
109 | ||
110 | if (i < argc) | |
111 | include_schemes = argv[i]; | |
112 | else | |
ef416fc2 | 113 | { |
bdbfacc7 | 114 | _cupsLangPuts(stderr, _("lpinfo: Expected scheme list after \"--include-schemes\".")); |
8e52928c | 115 | usage(); |
bdbfacc7 MS |
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\".")); | |
8e52928c | 130 | usage(); |
bdbfacc7 MS |
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\".")); | |
8e52928c | 145 | usage(); |
bdbfacc7 MS |
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\".")); | |
8e52928c | 160 | usage(); |
bdbfacc7 MS |
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\".")); | |
8e52928c | 175 | usage(); |
bdbfacc7 MS |
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 */ | |
ef416fc2 | 189 | #ifdef HAVE_SSL |
bdbfacc7 | 190 | cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); |
ef416fc2 | 191 | #else |
bdbfacc7 | 192 | _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), argv[0]); |
ef416fc2 | 193 | #endif /* HAVE_SSL */ |
bdbfacc7 | 194 | break; |
58dc1933 | 195 | |
bdbfacc7 MS |
196 | case 'h' : /* Connect to host */ |
197 | if (opt[1] != '\0') | |
58dc1933 | 198 | { |
bdbfacc7 MS |
199 | cupsSetServer(opt + 1); |
200 | opt += strlen(opt) - 1; | |
58dc1933 | 201 | } |
ed6e7faf MS |
202 | else |
203 | { | |
bdbfacc7 | 204 | i ++; |
ed6e7faf | 205 | |
bdbfacc7 MS |
206 | if (i >= argc) |
207 | { | |
208 | _cupsLangPuts(stderr, _("Error: need hostname after \"-h\" option.")); | |
8e52928c | 209 | usage(); |
bdbfacc7 MS |
210 | } |
211 | ||
212 | cupsSetServer(argv[i]); | |
58dc1933 | 213 | } |
bdbfacc7 MS |
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)) | |
58dc1933 | 222 | return (1); |
bdbfacc7 | 223 | break; |
57b7b66b | 224 | |
bdbfacc7 MS |
225 | case 'v' : /* Show available devices */ |
226 | if (show_devices(long_status, timeout, include_schemes, exclude_schemes)) | |
58dc1933 | 227 | return (1); |
bdbfacc7 | 228 | break; |
ef416fc2 | 229 | |
bdbfacc7 MS |
230 | default : |
231 | _cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), argv[0], *opt); | |
8e52928c | 232 | usage(); |
bdbfacc7 | 233 | } |
ef416fc2 | 234 | } |
bdbfacc7 | 235 | } |
ef416fc2 | 236 | else |
237 | { | |
bdbfacc7 | 238 | _cupsLangPrintf(stderr, _("%s: Unknown argument \"%s\"."), argv[0], argv[i]); |
8e52928c | 239 | usage(); |
ef416fc2 | 240 | } |
bdbfacc7 | 241 | } |
ef416fc2 | 242 | |
243 | return (0); | |
244 | } | |
245 | ||
246 | ||
247 | /* | |
ae71f5de | 248 | * 'device_cb()' - Device callback. |
ef416fc2 | 249 | */ |
250 | ||
ae71f5de MS |
251 | static void |
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 */ | |
749b1e90 | 258 | const char *device_location, /* I - device-location string */ |
ae71f5de | 259 | void *user_data) /* I - User data */ |
ef416fc2 | 260 | { |
ae71f5de | 261 | int *long_status; /* Show verbose info? */ |
ef416fc2 | 262 | |
ef416fc2 | 263 | |
264 | /* | |
ae71f5de | 265 | * Display the device... |
ef416fc2 | 266 | */ |
267 | ||
ae71f5de | 268 | long_status = (int *)user_data; |
ef416fc2 | 269 | |
ae71f5de | 270 | if (*long_status) |
ef416fc2 | 271 | { |
ae71f5de MS |
272 | _cupsLangPrintf(stdout, |
273 | _("Device: uri = %s\n" | |
274 | " class = %s\n" | |
275 | " info = %s\n" | |
276 | " make-and-model = %s\n" | |
749b1e90 | 277 | " device-id = %s\n" |
0837b7e8 | 278 | " location = %s"), |
ae71f5de | 279 | device_uri, device_class, device_info, |
749b1e90 | 280 | device_make_and_model, device_id, device_location); |
ae71f5de MS |
281 | } |
282 | else | |
0837b7e8 | 283 | _cupsLangPrintf(stdout, "%s %s", device_class, device_uri); |
ae71f5de | 284 | } |
ef416fc2 | 285 | |
ef416fc2 | 286 | |
ae71f5de MS |
287 | /* |
288 | * 'show_devices()' - Show available devices. | |
289 | */ | |
ef416fc2 | 290 | |
ae71f5de | 291 | static int /* O - 0 on success, 1 on failure */ |
ed6e7faf MS |
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 */ | |
ae71f5de | 297 | { |
ed6e7faf MS |
298 | if (cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include_schemes, |
299 | exclude_schemes, device_cb, &long_status) != IPP_OK) | |
ef416fc2 | 300 | { |
0837b7e8 | 301 | _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString()); |
ef416fc2 | 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 */ | |
ed6e7faf MS |
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 */ | |
ef416fc2 | 322 | { |
323 | ipp_t *request, /* IPP Request */ | |
324 | *response; /* IPP Response */ | |
325 | ipp_attribute_t *attr; /* Current attribute */ | |
fa73b229 | 326 | const char *ppd_device_id, /* Pointer to ppd-device-id */ |
327 | *ppd_language, /* Pointer to ppd-natural-language */ | |
58dc1933 | 328 | *ppd_make_model, /* Pointer to ppd-make-and-model */ |
fa73b229 | 329 | *ppd_name; /* Pointer to ppd-name */ |
ed6e7faf | 330 | cups_option_t option; /* in/exclude-schemes option */ |
ef416fc2 | 331 | |
332 | ||
ef416fc2 | 333 | /* |
58dc1933 | 334 | * Build a CUPS_GET_PPDS request... |
ef416fc2 | 335 | */ |
336 | ||
fa73b229 | 337 | request = ippNewRequest(CUPS_GET_PPDS); |
ef416fc2 | 338 | |
58dc1933 MS |
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 | ||
ed6e7faf MS |
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 | ||
ef416fc2 | 368 | /* |
369 | * Do the request and get back a response... | |
370 | */ | |
371 | ||
ed6e7faf | 372 | if ((response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL) |
ef416fc2 | 373 | { |
374 | /* | |
375 | * Loop through the device list and display them... | |
376 | */ | |
377 | ||
378 | if (response->request.status.status_code > IPP_OK_CONFLICT) | |
379 | { | |
0837b7e8 | 380 | _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString()); |
ef416fc2 | 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 | ||
58dc1933 MS |
401 | ppd_device_id = "NONE"; |
402 | ppd_language = NULL; | |
403 | ppd_make_model = NULL; | |
404 | ppd_name = NULL; | |
ef416fc2 | 405 | |
406 | while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) | |
407 | { | |
fa73b229 | 408 | if (!strcmp(attr->name, "ppd-device-id") && |
ef416fc2 | 409 | attr->value_tag == IPP_TAG_TEXT) |
fa73b229 | 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) | |
58dc1933 | 416 | ppd_make_model = attr->values[0].string.text; |
fa73b229 | 417 | else if (!strcmp(attr->name, "ppd-name") && |
418 | attr->value_tag == IPP_TAG_NAME) | |
ef416fc2 | 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 | ||
58dc1933 | 428 | if (ppd_language == NULL || ppd_make_model == NULL || ppd_name == NULL) |
ef416fc2 | 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 | { | |
fa73b229 | 442 | _cupsLangPrintf(stdout, |
ef416fc2 | 443 | _("Model: name = %s\n" |
444 | " natural_language = %s\n" | |
fa73b229 | 445 | " make-and-model = %s\n" |
0837b7e8 | 446 | " device-id = %s"), |
58dc1933 | 447 | ppd_name, ppd_language, ppd_make_model, ppd_device_id); |
ef416fc2 | 448 | } |
449 | else | |
0837b7e8 | 450 | _cupsLangPrintf(stdout, "%s %s", ppd_name, ppd_make_model); |
ef416fc2 | 451 | |
452 | if (attr == NULL) | |
453 | break; | |
454 | } | |
455 | ||
456 | ippDelete(response); | |
f306ad4d MS |
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"), | |
8e52928c | 471 | "everywhere", cupsLangDefault()->language, "IPP Everywhere™", "CMD:PwgRaster"); |
f306ad4d MS |
472 | } |
473 | else | |
474 | _cupsLangPuts(stdout, "everywhere IPP Everywhere"); | |
475 | } | |
ef416fc2 | 476 | } |
477 | else | |
478 | { | |
0837b7e8 | 479 | _cupsLangPrintf(stderr, "lpinfo: %s", cupsLastErrorString()); |
ef416fc2 | 480 | |
481 | return (1); | |
482 | } | |
483 | ||
484 | return (0); | |
485 | } | |
8e52928c MS |
486 | |
487 | ||
488 | /* | |
489 | * 'usage()' - Show program usage and exit. | |
490 | */ | |
491 | ||
492 | static 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 | } |