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