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