• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * "lpstat" 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 
18 
19 /*
20  * Local functions...
21  */
22 
23 static void	check_dest(const char *command, const char *name,
24 		           int *num_dests, cups_dest_t **dests);
25 static int	match_list(const char *list, const char *name);
26 static int	show_accepting(const char *printers, int num_dests,
27 		               cups_dest_t *dests);
28 static int	show_classes(const char *dests);
29 static void	show_default(cups_dest_t *dest);
30 static int	show_devices(const char *printers, int num_dests,
31 		             cups_dest_t *dests);
32 static int	show_jobs(const char *dests, const char *users, int long_status,
33 		          int ranking, const char *which);
34 static int	show_printers(const char *printers, int num_dests,
35 		              cups_dest_t *dests, int long_status);
36 static int	show_scheduler(void);
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 		status;			/* Exit status */
50   char		*opt;			/* Option pointer */
51   int		num_dests;		/* Number of user destinations */
52   cups_dest_t	*dests;			/* User destinations */
53   int		long_status;		/* Long status report? */
54   int		ranking;		/* Show job ranking? */
55   const char	*which;			/* Which jobs to show? */
56   char		op;			/* Last operation on command-line */
57 
58 
59   _cupsSetLocale(argv);
60 
61  /*
62   * Parse command-line options...
63   */
64 
65   num_dests   = 0;
66   dests       = NULL;
67   long_status = 0;
68   ranking     = 0;
69   status      = 0;
70   which       = "not-completed";
71   op          = 0;
72 
73   for (i = 1; i < argc; i ++)
74   {
75     if (!strcmp(argv[i], "--help"))
76       usage();
77     else if (argv[i][0] == '-')
78     {
79       for (opt = argv[i] + 1; *opt; opt ++)
80       {
81 	switch (*opt)
82 	{
83 	  case 'D' : /* Show description */
84 	      long_status = 1;
85 	      break;
86 
87 	  case 'E' : /* Encrypt */
88 #ifdef HAVE_TLS
89 	      cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
90 #else
91 	      _cupsLangPrintf(stderr,
92 			      _("%s: Sorry, no encryption support."),
93 			      argv[0]);
94 #endif /* HAVE_TLS */
95 	      break;
96 
97 	  case 'H' : /* Show server and port */
98 	      if (cupsServer()[0] == '/')
99 		_cupsLangPuts(stdout, cupsServer());
100 	      else
101 		_cupsLangPrintf(stdout, "%s:%d", cupsServer(), ippPort());
102 	      op = 'H';
103 	      break;
104 
105 	  case 'P' : /* Show paper types */
106 	      op = 'P';
107 	      break;
108 
109 	  case 'R' : /* Show ranking */
110 	      ranking = 1;
111 	      break;
112 
113 	  case 'S' : /* Show charsets */
114 	      op = 'S';
115 	      if (!argv[i][2])
116 		i ++;
117 	      break;
118 
119 	  case 'U' : /* Username */
120 	      if (opt[1] != '\0')
121 	      {
122 		cupsSetUser(opt + 1);
123 		opt += strlen(opt) - 1;
124 	      }
125 	      else
126 	      {
127 		i ++;
128 		if (i >= argc)
129 		{
130 		  _cupsLangPrintf(stderr, _("%s: Error - expected username after \"-U\" option."), argv[0]);
131 		  usage();
132 		}
133 
134 		cupsSetUser(argv[i]);
135 	      }
136 	      break;
137 
138 	  case 'W' : /* Show which jobs? */
139 	      if (opt[1] != '\0')
140 	      {
141 		which = opt + 1;
142 		opt += strlen(opt) - 1;
143 	      }
144 	      else
145 	      {
146 		i ++;
147 
148 		if (i >= argc)
149 		{
150 		  _cupsLangPrintf(stderr, _("%s: Error - need \"completed\", \"not-completed\", \"successful\", or \"all\" after \"-W\" option."), argv[0]);
151 		  usage();
152 		}
153 
154 		which = argv[i];
155 	      }
156 
157 	      if (strcmp(which, "completed") && strcmp(which, "not-completed") && strcmp(which, "all") && strcmp(which, "successful"))
158 	      {
159 		_cupsLangPrintf(stderr, _("%s: Error - need \"completed\", \"not-completed\", \"successful\", or \"all\" after \"-W\" option."), argv[0]);
160 		usage();
161 	      }
162 	      break;
163 
164 	  case 'a' : /* Show acceptance status */
165 	      op = 'a';
166 
167 	      if (opt[1] != '\0')
168 	      {
169 		check_dest(argv[0], opt + 1, &num_dests, &dests);
170 
171 		status |= show_accepting(opt + 1, num_dests, dests);
172 	        opt += strlen(opt) - 1;
173 	      }
174 	      else if ((i + 1) < argc && argv[i + 1][0] != '-')
175 	      {
176 		i ++;
177 
178 		check_dest(argv[0], argv[i], &num_dests, &dests);
179 
180 		status |= show_accepting(argv[i], num_dests, dests);
181 	      }
182 	      else
183 	      {
184 		if (num_dests <= 1)
185 		{
186 		  cupsFreeDests(num_dests, dests);
187 		  num_dests = cupsGetDests(&dests);
188 
189 		  if (num_dests == 0 && (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST || cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED))
190 		  {
191 		    _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
192 		    return (1);
193 		  }
194 		}
195 
196 		status |= show_accepting(NULL, num_dests, dests);
197 	      }
198 	      break;
199 
200 	  case 'c' : /* Show classes and members */
201 	      op = 'c';
202 
203 	      if (opt[1] != '\0')
204 	      {
205 		check_dest(argv[0], opt + 1, &num_dests, &dests);
206 
207 		status |= show_classes(opt + 1);
208 	        opt += strlen(opt) - 1;
209 	      }
210 	      else if ((i + 1) < argc && argv[i + 1][0] != '-')
211 	      {
212 		i ++;
213 
214 		check_dest(argv[0], argv[i], &num_dests, &dests);
215 
216 		status |= show_classes(argv[i]);
217 	      }
218 	      else
219 		status |= show_classes(NULL);
220 	      break;
221 
222 	  case 'd' : /* Show default destination */
223 	      op = 'd';
224 
225 	      if (num_dests != 1 || !dests[0].is_default)
226 	      {
227 		cupsFreeDests(num_dests, dests);
228 
229 		dests     = cupsGetNamedDest(CUPS_HTTP_DEFAULT, NULL, NULL);
230 		num_dests = dests ? 1 : 0;
231 
232 		if (num_dests == 0 &&
233 		    (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
234 		     cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED))
235 		{
236 		  _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
237 		  return (1);
238 		}
239 	      }
240 
241 	      show_default(dests);
242 	      break;
243 
244 	  case 'e' : /* List destinations */
245 	      {
246                 cups_dest_t *temp = NULL, *dest;
247                 int j, num_temp = cupsGetDests(&temp);
248 
249                 op = 'e';
250 
251                 for (j = num_temp, dest = temp; j > 0; j --, dest ++)
252                 {
253                   if (dest->instance)
254                     printf("%s/%s", dest->name, dest->instance);
255                   else
256                     fputs(dest->name, stdout);
257 
258                   if (long_status)
259                   {
260                     const char *printer_uri_supported = cupsGetOption("printer-uri-supported", dest->num_options, dest->options);
261                     const char *printer_is_temporary = cupsGetOption("printer-is-temporary", dest->num_options, dest->options);
262                     const char *type = "network";
263 
264                     if (printer_is_temporary && !strcmp(printer_is_temporary, "true"))
265                       type = "temporary";
266                     else if (printer_uri_supported)
267                       type = "permanent";
268 
269                     printf(" %s %s %s\n", type, printer_uri_supported ? printer_uri_supported : "none", cupsGetOption("device-uri", dest->num_options, dest->options));
270                   }
271                   else
272                     putchar('\n');
273                 }
274 
275                 cupsFreeDests(num_temp, temp);
276               }
277               break;
278 
279 	  case 'f' : /* Show forms */
280 	      op   = 'f';
281 	      if (opt[1] != '\0')
282 	      {
283 	        opt += strlen(opt) - 1;
284 	      }
285 	      else
286 	      {
287 		i ++;
288 		if (i >= argc)
289 		  return (1);
290 	      }
291 	      break;
292 
293 	  case 'h' : /* Connect to host */
294 	      if (opt[1] != '\0')
295 	      {
296 		cupsSetServer(opt + 1);
297 	        opt += strlen(opt) - 1;
298 	      }
299 	      else
300 	      {
301 		i ++;
302 
303 		if (i >= argc)
304 		{
305 		  _cupsLangPrintf(stderr, _("%s: Error - expected hostname after \"-h\" option."), argv[0]);
306 		  return (1);
307 		}
308 
309 		cupsSetServer(argv[i]);
310 	      }
311 	      break;
312 
313 	  case 'l' : /* Long status or long job status */
314 	      long_status = 2;
315 	      break;
316 
317 	  case 'o' : /* Show jobs by destination */
318 	      op = 'o';
319 
320 	      if (opt[1])
321 	      {
322 		check_dest(argv[0], opt + 1, &num_dests, &dests);
323 
324 		status |= show_jobs(opt + 1, NULL, long_status, ranking, which);
325 	        opt += strlen(opt) - 1;
326 	      }
327 	      else if ((i + 1) < argc && argv[i + 1][0] != '-')
328 	      {
329 		i ++;
330 
331 		check_dest(argv[0], argv[i], &num_dests, &dests);
332 
333 		status |= show_jobs(argv[i], NULL, long_status, ranking, which);
334 	      }
335 	      else
336 		status |= show_jobs(NULL, NULL, long_status, ranking, which);
337 	      break;
338 
339 	  case 'p' : /* Show printers */
340 	      op = 'p';
341 
342 	      if (opt[1] != '\0')
343 	      {
344 		check_dest(argv[0], opt + 1, &num_dests, &dests);
345 
346 		status |= show_printers(opt + 1, num_dests, dests,
347 					long_status);
348 	        opt += strlen(opt) - 1;
349 	      }
350 	      else if ((i + 1) < argc && argv[i + 1][0] != '-')
351 	      {
352 		i ++;
353 
354 		check_dest(argv[0], argv[i], &num_dests, &dests);
355 
356 		status |= show_printers(argv[i], num_dests, dests, long_status);
357 	      }
358 	      else
359 	      {
360 		if (num_dests <= 1)
361 		{
362 		  cupsFreeDests(num_dests, dests);
363 		  num_dests = cupsGetDests(&dests);
364 
365 		  if (num_dests == 0 &&
366 		      (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
367 		       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED))
368 		  {
369 		    _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
370 		    return (1);
371 		  }
372 		}
373 
374 		status |= show_printers(NULL, num_dests, dests, long_status);
375 	      }
376 	      break;
377 
378 	  case 'r' : /* Show scheduler status */
379 	      op = 'r';
380 
381 	      if (!show_scheduler())
382 		return (0);
383 	      break;
384 
385 	  case 's' : /* Show summary */
386 	      op = 's';
387 
388 	      if (num_dests <= 1)
389 	      {
390 		cupsFreeDests(num_dests, dests);
391 		num_dests = cupsGetDests(&dests);
392 
393 		if (num_dests == 0 &&
394 		    (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
395 		     cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED))
396 		{
397 		  _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
398 		  return (1);
399 		}
400 	      }
401 
402 	      show_default(cupsGetDest(NULL, NULL, num_dests, dests));
403 	      status |= show_classes(NULL);
404 	      status |= show_devices(NULL, num_dests, dests);
405 	      break;
406 
407 	  case 't' : /* Show all info */
408 	      op = 't';
409 
410 	      if (num_dests <= 1)
411 	      {
412 		cupsFreeDests(num_dests, dests);
413 		num_dests = cupsGetDests(&dests);
414 
415 		if (num_dests == 0 &&
416 		    (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
417 		     cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED))
418 		{
419 		  _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
420 		  return (1);
421 		}
422 	      }
423 
424 	      if (!show_scheduler())
425 		return (0);
426 
427 	      show_default(cupsGetDest(NULL, NULL, num_dests, dests));
428 	      status |= show_classes(NULL);
429 	      status |= show_devices(NULL, num_dests, dests);
430 	      status |= show_accepting(NULL, num_dests, dests);
431 	      status |= show_printers(NULL, num_dests, dests, long_status);
432 	      status |= show_jobs(NULL, NULL, long_status, ranking, which);
433 	      break;
434 
435 	  case 'u' : /* Show jobs by user */
436 	      op = 'u';
437 
438 	      if (opt[1] != '\0')
439 	      {
440 		status |= show_jobs(NULL, opt + 1, long_status, ranking, which);
441 	        opt += strlen(opt) - 1;
442 	      }
443 	      else if ((i + 1) < argc && argv[i + 1][0] != '-')
444 	      {
445 		i ++;
446 		status |= show_jobs(NULL, argv[i], long_status, ranking, which);
447 	      }
448 	      else
449 		status |= show_jobs(NULL, NULL, long_status, ranking, which);
450 	      break;
451 
452 	  case 'v' : /* Show printer devices */
453 	      op = 'v';
454 
455 	      if (opt[1] != '\0')
456 	      {
457 		check_dest(argv[0], opt + 1, &num_dests, &dests);
458 
459 		status |= show_devices(opt + 1, num_dests, dests);
460 	        opt += strlen(opt) - 1;
461 	      }
462 	      else if ((i + 1) < argc && argv[i + 1][0] != '-')
463 	      {
464 		i ++;
465 
466 		check_dest(argv[0], argv[i], &num_dests, &dests);
467 
468 		status |= show_devices(argv[i], num_dests, dests);
469 	      }
470 	      else
471 	      {
472 		if (num_dests <= 1)
473 		{
474 		  cupsFreeDests(num_dests, dests);
475 		  num_dests = cupsGetDests(&dests);
476 
477 		  if (num_dests == 0 &&
478 		      (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
479 		       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED))
480 		  {
481 		    _cupsLangPrintf(stderr, _("%s: Error - add '/version=1.1' to server name."), argv[0]);
482 		    return (1);
483 		  }
484 		}
485 
486 		status |= show_devices(NULL, num_dests, dests);
487 	      }
488 	      break;
489 
490 	  default :
491 	      _cupsLangPrintf(stderr, _("%s: Error - unknown option \"%c\"."), argv[0], argv[i][1]);
492 	      usage();
493 	}
494       }
495     }
496     else
497     {
498       status |= show_jobs(argv[i], NULL, long_status, ranking, which);
499       op = 'o';
500     }
501   }
502 
503   if (!op)
504     status |= show_jobs(NULL, cupsUser(), long_status, ranking, which);
505 
506   return (status);
507 }
508 
509 
510 /*
511  * 'check_dest()' - Verify that the named destination(s) exists.
512  */
513 
514 static void
check_dest(const char * command,const char * name,int * num_dests,cups_dest_t ** dests)515 check_dest(const char  *command,	/* I  - Command name */
516            const char  *name,		/* I  - List of printer/class names */
517            int         *num_dests,	/* IO - Number of destinations */
518 	   cups_dest_t **dests)		/* IO - Destinations */
519 {
520   const char	*dptr;			/* Pointer into name */
521   char		*pptr,			/* Pointer into printer */
522 		printer[1024];		/* Current printer/class name */
523 
524 
525  /*
526   * Load the destination list as necessary...
527   */
528 
529   if (*num_dests <= 1)
530   {
531     if (*num_dests)
532       cupsFreeDests(*num_dests, *dests);
533 
534     if (strchr(name, ','))
535       *num_dests = cupsGetDests(dests);
536     else
537     {
538       strlcpy(printer, name, sizeof(printer));
539       if ((pptr = strchr(printer, '/')) != NULL)
540         *pptr++ = '\0';
541 
542       if ((*dests = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, pptr)) == NULL)
543       {
544 	if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
545 	    cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
546 	  _cupsLangPrintf(stderr,
547 			  _("%s: Error - add '/version=1.1' to server name."),
548 			  command);
549 	else
550 	  _cupsLangPrintf(stderr,
551 			  _("%s: Invalid destination name in list \"%s\"."),
552 			  command, name);
553 
554         exit(1);
555       }
556       else
557       {
558         *num_dests = 1;
559         return;
560       }
561     }
562   }
563 
564  /*
565   * Scan the name string for printer/class name(s)...
566   */
567 
568   for (dptr = name; *dptr;)
569   {
570    /*
571     * Skip leading whitespace and commas...
572     */
573 
574     while (isspace(*dptr & 255) || *dptr == ',')
575       dptr ++;
576 
577     if (!*dptr)
578       break;
579 
580    /*
581     * Extract a single destination name from the name string...
582     */
583 
584     for (pptr = printer; !isspace(*dptr & 255) && *dptr != ',' && *dptr;)
585     {
586       if ((size_t)(pptr - printer) < (sizeof(printer) - 1))
587         *pptr++ = *dptr++;
588       else
589       {
590         _cupsLangPrintf(stderr,
591 	                _("%s: Invalid destination name in list \"%s\"."),
592 			command, name);
593         exit(1);
594       }
595     }
596 
597     *pptr = '\0';
598 
599    /*
600     * Check the destination...
601     */
602 
603     if (!cupsGetDest(printer, NULL, *num_dests, *dests))
604     {
605       if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
606           cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
607 	_cupsLangPrintf(stderr,
608 	                _("%s: Error - add '/version=1.1' to server name."),
609 			command);
610       else
611 	_cupsLangPrintf(stderr,
612 			_("%s: Unknown destination \"%s\"."), command, printer);
613 
614       exit(1);
615     }
616   }
617 }
618 
619 
620 /*
621  * 'match_list()' - Match a name from a list of comma or space-separated names.
622  */
623 
624 static int				/* O - 1 on match, 0 on no match */
match_list(const char * list,const char * name)625 match_list(const char *list,		/* I - List of names */
626            const char *name)		/* I - Name to find */
627 {
628   const char	*nameptr;		/* Pointer into name */
629 
630 
631  /*
632   * An empty list always matches...
633   */
634 
635   if (!list || !*list)
636     return (1);
637 
638   if (!name)
639     return (0);
640 
641   do
642   {
643    /*
644     * Skip leading whitespace and commas...
645     */
646 
647     while (isspace(*list & 255) || *list == ',')
648       list ++;
649 
650     if (!*list)
651       break;
652 
653    /*
654     * Compare names...
655     */
656 
657     for (nameptr = name;
658 	 *nameptr && *list && tolower(*nameptr & 255) == tolower(*list & 255);
659 	 nameptr ++, list ++);
660 
661     if (!*nameptr && (!*list || *list == ',' || isspace(*list & 255)))
662       return (1);
663 
664     while (*list && !isspace(*list & 255) && *list != ',')
665       list ++;
666   }
667   while (*list);
668 
669   return (0);
670 }
671 
672 
673 /*
674  * 'show_accepting()' - Show acceptance status.
675  */
676 
677 static int				/* O - 0 on success, 1 on fail */
show_accepting(const char * printers,int num_dests,cups_dest_t * dests)678 show_accepting(const char  *printers,	/* I - Destinations */
679                int         num_dests,	/* I - Number of user-defined dests */
680 	       cups_dest_t *dests)	/* I - User-defined destinations */
681 {
682   int		i;			/* Looping var */
683   ipp_t		*request,		/* IPP Request */
684 		*response;		/* IPP Response */
685   ipp_attribute_t *attr;		/* Current attribute */
686   const char	*printer,		/* Printer name */
687 		*message;		/* Printer device URI */
688   int		accepting;		/* Accepting requests? */
689   time_t	ptime;			/* Printer state time */
690   char		printer_state_time[255];/* Printer state time */
691   static const char *pattrs[] =		/* Attributes we need for printers... */
692 		{
693 		  "printer-name",
694 		  "printer-state-change-time",
695 		  "printer-state-message",
696 		  "printer-is-accepting-jobs"
697 		};
698 
699 
700   if (printers != NULL && !strcmp(printers, "all"))
701     printers = NULL;
702 
703  /*
704   * Build a CUPS_GET_PRINTERS request, which requires the following
705   * attributes:
706   *
707   *    attributes-charset
708   *    attributes-natural-language
709   *    requested-attributes
710   *    requesting-user-name
711   */
712 
713   request = ippNewRequest(CUPS_GET_PRINTERS);
714 
715   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
716                 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
717 		NULL, pattrs);
718 
719   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
720                NULL, cupsUser());
721 
722  /*
723   * Do the request and get back a response...
724   */
725 
726   response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/");
727 
728   if (cupsLastError() == IPP_STATUS_ERROR_SERVICE_UNAVAILABLE)
729   {
730     _cupsLangPrintf(stderr, _("%s: Scheduler is not running."), "lpstat");
731     ippDelete(response);
732     return (1);
733   }
734   else if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST || cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
735   {
736     _cupsLangPrintf(stderr,
737 		    _("%s: Error - add '/version=1.1' to server name."),
738 		    "lpstat");
739     ippDelete(response);
740     return (1);
741   }
742   else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
743   {
744     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
745     ippDelete(response);
746     return (1);
747   }
748 
749   if (response)
750   {
751    /*
752     * Loop through the printers returned in the list and display
753     * their devices...
754     */
755 
756     for (attr = response->attrs; attr != NULL; attr = attr->next)
757     {
758      /*
759       * Skip leading attributes until we hit a printer...
760       */
761 
762       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
763         attr = attr->next;
764 
765       if (attr == NULL)
766         break;
767 
768      /*
769       * Pull the needed attributes from this printer...
770       */
771 
772       printer   = NULL;
773       message   = NULL;
774       accepting = 1;
775       ptime     = 0;
776 
777       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
778       {
779         if (!strcmp(attr->name, "printer-name") &&
780 	    attr->value_tag == IPP_TAG_NAME)
781 	  printer = attr->values[0].string.text;
782         else if (!strcmp(attr->name, "printer-state-change-time") &&
783 	         attr->value_tag == IPP_TAG_INTEGER)
784 	  ptime = (time_t)attr->values[0].integer;
785         else if (!strcmp(attr->name, "printer-state-message") &&
786 	         attr->value_tag == IPP_TAG_TEXT)
787 	  message = attr->values[0].string.text;
788         else if (!strcmp(attr->name, "printer-is-accepting-jobs") &&
789 	         attr->value_tag == IPP_TAG_BOOLEAN)
790 	  accepting = attr->values[0].boolean;
791 
792         attr = attr->next;
793       }
794 
795      /*
796       * See if we have everything needed...
797       */
798 
799       if (printer == NULL)
800       {
801         if (attr == NULL)
802 	  break;
803 	else
804           continue;
805       }
806 
807      /*
808       * Display the printer entry if needed...
809       */
810 
811       if (match_list(printers, printer))
812       {
813         _cupsStrDate(printer_state_time, sizeof(printer_state_time), ptime);
814 
815         if (accepting)
816 	  _cupsLangPrintf(stdout, _("%s accepting requests since %s"),
817 			  printer, printer_state_time);
818 	else
819 	{
820 	  _cupsLangPrintf(stdout, _("%s not accepting requests since %s -"),
821 			  printer, printer_state_time);
822 	  _cupsLangPrintf(stdout, _("\t%s"),
823 			  (message && *message) ?
824 			      message : "reason unknown");
825         }
826 
827         for (i = 0; i < num_dests; i ++)
828 	  if (!_cups_strcasecmp(dests[i].name, printer) && dests[i].instance)
829 	  {
830             if (accepting)
831 	      _cupsLangPrintf(stdout, _("%s/%s accepting requests since %s"),
832 			      printer, dests[i].instance, printer_state_time);
833 	    else
834 	    {
835 	      _cupsLangPrintf(stdout,
836 	                      _("%s/%s not accepting requests since %s -"),
837 			      printer, dests[i].instance, printer_state_time);
838 	      _cupsLangPrintf(stdout, _("\t%s"),
839 	        	      (message && *message) ?
840 			          message : "reason unknown");
841             }
842 	  }
843       }
844 
845       if (attr == NULL)
846         break;
847     }
848 
849     ippDelete(response);
850   }
851 
852   return (0);
853 }
854 
855 
856 /*
857  * 'show_classes()' - Show printer classes.
858  */
859 
860 static int				/* O - 0 on success, 1 on fail */
show_classes(const char * dests)861 show_classes(const char *dests)		/* I - Destinations */
862 {
863   int		i;			/* Looping var */
864   ipp_t		*request,		/* IPP Request */
865 		*response,		/* IPP Response */
866 		*response2;		/* IPP response from remote server */
867   http_t	*http2;			/* Remote server */
868   ipp_attribute_t *attr;		/* Current attribute */
869   const char	*printer,		/* Printer class name */
870 		*printer_uri;		/* Printer class URI */
871   ipp_attribute_t *members;		/* Printer members */
872   char		method[HTTP_MAX_URI],	/* Request method */
873 		username[HTTP_MAX_URI],	/* Username:password */
874 		server[HTTP_MAX_URI],	/* Server name */
875 		resource[HTTP_MAX_URI];	/* Resource name */
876   int		port;			/* Port number */
877   static const char *cattrs[] =		/* Attributes we need for classes... */
878 		{
879 		  "printer-name",
880 		  "printer-uri-supported",
881 		  "member-names"
882 		};
883 
884 
885   if (dests != NULL && !strcmp(dests, "all"))
886     dests = NULL;
887 
888  /*
889   * Build a CUPS_GET_CLASSES request, which requires the following
890   * attributes:
891   *
892   *    attributes-charset
893   *    attributes-natural-language
894   *    requested-attributes
895   *    requesting-user-name
896   */
897 
898   request = ippNewRequest(CUPS_GET_CLASSES);
899 
900   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
901                 "requested-attributes", sizeof(cattrs) / sizeof(cattrs[0]),
902 		NULL, cattrs);
903 
904   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
905                NULL, cupsUser());
906 
907  /*
908   * Do the request and get back a response...
909   */
910 
911   response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/");
912 
913   if (cupsLastError() == IPP_STATUS_ERROR_SERVICE_UNAVAILABLE)
914   {
915     _cupsLangPrintf(stderr, _("%s: Scheduler is not running."), "lpstat");
916     ippDelete(response);
917     return (1);
918   }
919   if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
920       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
921   {
922     _cupsLangPrintf(stderr,
923 		    _("%s: Error - add '/version=1.1' to server name."),
924 		    "lpstat");
925     ippDelete(response);
926     return (1);
927   }
928   else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
929   {
930     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
931     ippDelete(response);
932     return (1);
933   }
934 
935   if (response)
936   {
937     if (response->request.status.status_code > IPP_OK_CONFLICT)
938     {
939       _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
940       ippDelete(response);
941       return (1);
942     }
943 
944    /*
945     * Loop through the printers returned in the list and display
946     * their devices...
947     */
948 
949     for (attr = response->attrs; attr != NULL; attr = attr->next)
950     {
951      /*
952       * Skip leading attributes until we hit a job...
953       */
954 
955       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
956         attr = attr->next;
957 
958       if (attr == NULL)
959         break;
960 
961      /*
962       * Pull the needed attributes from this job...
963       */
964 
965       printer     = NULL;
966       printer_uri = NULL;
967       members     = NULL;
968 
969       do
970       {
971         if (!strcmp(attr->name, "printer-name") &&
972 	    attr->value_tag == IPP_TAG_NAME)
973 	  printer = attr->values[0].string.text;
974 
975         if (!strcmp(attr->name, "printer-uri-supported") &&
976 	    attr->value_tag == IPP_TAG_URI)
977 	  printer_uri = attr->values[0].string.text;
978 
979         if (!strcmp(attr->name, "member-names") &&
980 	    attr->value_tag == IPP_TAG_NAME)
981 	  members = attr;
982 
983         attr = attr->next;
984       }
985 	  while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER);
986 
987      /*
988       * If this is a remote class, grab the class info from the
989       * remote server...
990       */
991 
992       response2 = NULL;
993       if (members == NULL && printer_uri != NULL)
994       {
995         httpSeparateURI(HTTP_URI_CODING_ALL, printer_uri, method, sizeof(method),
996 	                username, sizeof(username), server, sizeof(server),
997 			&port, resource, sizeof(resource));
998 
999         if (!_cups_strcasecmp(server, cupsServer()))
1000 	  http2 = CUPS_HTTP_DEFAULT;
1001 	else
1002 	  http2 = httpConnectEncrypt(server, port, cupsEncryption());
1003 
1004        /*
1005 	* Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the
1006 	* following attributes:
1007 	*
1008 	*    attributes-charset
1009 	*    attributes-natural-language
1010 	*    printer-uri
1011 	*    requested-attributes
1012 	*/
1013 
1014 	request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
1015 
1016 	ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1017 		     "printer-uri", NULL, printer_uri);
1018 
1019 	ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1020 		      "requested-attributes",
1021 		      sizeof(cattrs) / sizeof(cattrs[0]),
1022 		      NULL, cattrs);
1023 
1024 	if ((response2 = cupsDoRequest(http2, request, "/")) != NULL)
1025 	  members = ippFindAttribute(response2, "member-names", IPP_TAG_NAME);
1026 
1027 	if (http2)
1028 	  httpClose(http2);
1029       }
1030 
1031      /*
1032       * See if we have everything needed...
1033       */
1034 
1035       if (printer == NULL)
1036       {
1037         if (response2)
1038 	  ippDelete(response2);
1039 
1040         if (attr == NULL)
1041 	  break;
1042 	else
1043           continue;
1044       }
1045 
1046      /*
1047       * Display the printer entry if needed...
1048       */
1049 
1050       if (match_list(dests, printer))
1051       {
1052         _cupsLangPrintf(stdout, _("members of class %s:"), printer);
1053 
1054 	if (members)
1055 	{
1056 	  for (i = 0; i < members->num_values; i ++)
1057 	    _cupsLangPrintf(stdout, "\t%s", members->values[i].string.text);
1058         }
1059 	else
1060 	  _cupsLangPuts(stdout, "\tunknown");
1061       }
1062 
1063       if (response2)
1064 	ippDelete(response2);
1065 
1066       if (attr == NULL)
1067         break;
1068     }
1069 
1070     ippDelete(response);
1071   }
1072 
1073   return (0);
1074 }
1075 
1076 
1077 /*
1078  * 'show_default()' - Show default destination.
1079  */
1080 
1081 static void
show_default(cups_dest_t * dest)1082 show_default(cups_dest_t *dest)		/* I - Default destination */
1083 {
1084   const char	*printer,		/* Printer name */
1085 		*val;			/* Environment variable name */
1086 
1087 
1088   if (dest)
1089   {
1090     if (dest->instance)
1091       _cupsLangPrintf(stdout, _("system default destination: %s/%s"),
1092                       dest->name, dest->instance);
1093     else
1094       _cupsLangPrintf(stdout, _("system default destination: %s"),
1095                       dest->name);
1096   }
1097   else
1098   {
1099     val = NULL;
1100 
1101     if ((printer = getenv("LPDEST")) == NULL)
1102     {
1103       if ((printer = getenv("PRINTER")) != NULL)
1104       {
1105         if (!strcmp(printer, "lp"))
1106           printer = NULL;
1107 	else
1108 	  val = "PRINTER";
1109       }
1110     }
1111     else
1112       val = "LPDEST";
1113 
1114     if (printer)
1115       _cupsLangPrintf(stdout,
1116                       _("lpstat: error - %s environment variable names "
1117 		        "non-existent destination \"%s\"."),
1118         	      val, printer);
1119     else
1120       _cupsLangPuts(stdout, _("no system default destination"));
1121   }
1122 }
1123 
1124 
1125 /*
1126  * 'show_devices()' - Show printer devices.
1127  */
1128 
1129 static int				/* O - 0 on success, 1 on fail */
show_devices(const char * printers,int num_dests,cups_dest_t * dests)1130 show_devices(const char  *printers,	/* I - Destinations */
1131              int         num_dests,	/* I - Number of user-defined dests */
1132 	     cups_dest_t *dests)	/* I - User-defined destinations */
1133 {
1134   int		i;			/* Looping var */
1135   ipp_t		*request,		/* IPP Request */
1136 		*response;		/* IPP Response */
1137   ipp_attribute_t *attr;		/* Current attribute */
1138   const char	*printer,		/* Printer name */
1139 		*uri,			/* Printer URI */
1140 		*device;		/* Printer device URI */
1141   static const char *pattrs[] =		/* Attributes we need for printers... */
1142 		{
1143 		  "printer-name",
1144 		  "printer-uri-supported",
1145 		  "device-uri"
1146 		};
1147 
1148 
1149   if (printers != NULL && !strcmp(printers, "all"))
1150     printers = NULL;
1151 
1152  /*
1153   * Build a CUPS_GET_PRINTERS request, which requires the following
1154   * attributes:
1155   *
1156   *    attributes-charset
1157   *    attributes-natural-language
1158   *    requested-attributes
1159   *    requesting-user-name
1160   */
1161 
1162   request = ippNewRequest(CUPS_GET_PRINTERS);
1163 
1164   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1165                 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
1166 		NULL, pattrs);
1167 
1168   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1169                NULL, cupsUser());
1170 
1171  /*
1172   * Do the request and get back a response...
1173   */
1174 
1175   response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/");
1176 
1177   if (cupsLastError() == IPP_STATUS_ERROR_SERVICE_UNAVAILABLE)
1178   {
1179     _cupsLangPrintf(stderr, _("%s: Scheduler is not running."), "lpstat");
1180     ippDelete(response);
1181     return (1);
1182   }
1183   if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
1184       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
1185   {
1186     _cupsLangPrintf(stderr,
1187 		    _("%s: Error - add '/version=1.1' to server name."),
1188 		    "lpstat");
1189     ippDelete(response);
1190     return (1);
1191   }
1192   else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1193   {
1194     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1195     ippDelete(response);
1196     return (1);
1197   }
1198 
1199   if (response)
1200   {
1201    /*
1202     * Loop through the printers returned in the list and display
1203     * their devices...
1204     */
1205 
1206     for (attr = response->attrs; attr != NULL; attr = attr->next)
1207     {
1208      /*
1209       * Skip leading attributes until we hit a job...
1210       */
1211 
1212       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1213         attr = attr->next;
1214 
1215       if (attr == NULL)
1216         break;
1217 
1218      /*
1219       * Pull the needed attributes from this job...
1220       */
1221 
1222       printer = NULL;
1223       device  = NULL;
1224       uri     = NULL;
1225 
1226       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
1227       {
1228         if (!strcmp(attr->name, "printer-name") &&
1229 	    attr->value_tag == IPP_TAG_NAME)
1230 	  printer = attr->values[0].string.text;
1231 
1232         if (!strcmp(attr->name, "printer-uri-supported") &&
1233 	    attr->value_tag == IPP_TAG_URI)
1234 	  uri = attr->values[0].string.text;
1235 
1236         if (!strcmp(attr->name, "device-uri") &&
1237 	    attr->value_tag == IPP_TAG_URI)
1238 	  device = attr->values[0].string.text;
1239 
1240         attr = attr->next;
1241       }
1242 
1243      /*
1244       * See if we have everything needed...
1245       */
1246 
1247       if (printer == NULL)
1248       {
1249         if (attr == NULL)
1250 	  break;
1251 	else
1252           continue;
1253       }
1254 
1255      /*
1256       * Display the printer entry if needed...
1257       */
1258 
1259       if (match_list(printers, printer))
1260       {
1261         if (device == NULL)
1262           _cupsLangPrintf(stdout, _("device for %s: %s"),
1263 	                  printer, uri);
1264         else if (!strncmp(device, "file:", 5))
1265           _cupsLangPrintf(stdout, _("device for %s: %s"),
1266 	                  printer, device + 5);
1267         else
1268           _cupsLangPrintf(stdout, _("device for %s: %s"),
1269 	                  printer, device);
1270 
1271         for (i = 0; i < num_dests; i ++)
1272         {
1273 	  if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
1274 	  {
1275             if (device == NULL)
1276               _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
1277 	                      printer, dests[i].instance, uri);
1278             else if (!strncmp(device, "file:", 5))
1279               _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
1280 	                      printer, dests[i].instance, device + 5);
1281             else
1282               _cupsLangPrintf(stdout, _("device for %s/%s: %s"),
1283 	                      printer, dests[i].instance, device);
1284 	  }
1285 	}
1286       }
1287 
1288       if (attr == NULL)
1289         break;
1290     }
1291 
1292     ippDelete(response);
1293   }
1294 
1295   return (0);
1296 }
1297 
1298 
1299 /*
1300  * 'show_jobs()' - Show active print jobs.
1301  */
1302 
1303 static int				/* O - 0 on success, 1 on fail */
show_jobs(const char * dests,const char * users,int long_status,int ranking,const char * which)1304 show_jobs(const char *dests,		/* I - Destinations */
1305           const char *users,		/* I - Users */
1306           int        long_status,	/* I - Show long status? */
1307           int        ranking,		/* I - Show job ranking? */
1308 	  const char *which)		/* I - Show which jobs? */
1309 {
1310   int		i;			/* Looping var */
1311   ipp_t		*request,		/* IPP Request */
1312 		*response;		/* IPP Response */
1313   ipp_attribute_t *attr,		/* Current attribute */
1314 		*reasons;		/* Job state reasons attribute */
1315   const char	*dest,			/* Pointer into job-printer-uri */
1316 		*username,		/* Pointer to job-originating-user-name */
1317 		*message,		/* Pointer to job-printer-state-message */
1318 		*time_at;		/* time-at-xxx attribute name to use */
1319   int		rank,			/* Rank in queue */
1320 		jobid,			/* job-id */
1321 		size;			/* job-k-octets */
1322   time_t	jobtime;		/* time-at-creation */
1323   char		temp[255],		/* Temporary buffer */
1324 		date[255];		/* Date buffer */
1325   static const char *jattrs[] =		/* Attributes we need for jobs... */
1326 		{
1327 		  "job-id",
1328 		  "job-k-octets",
1329 		  "job-name",
1330 		  "job-originating-user-name",
1331 		  "job-printer-state-message",
1332 		  "job-printer-uri",
1333 		  "job-state-reasons",
1334 		  "time-at-creation",
1335 		  "time-at-completed"
1336 		};
1337 
1338 
1339   if (dests != NULL && !strcmp(dests, "all"))
1340     dests = NULL;
1341 
1342  /*
1343   * Build a IPP_GET_JOBS request, which requires the following
1344   * attributes:
1345   *
1346   *    attributes-charset
1347   *    attributes-natural-language
1348   *    printer-uri
1349   *    requested-attributes
1350   *    requesting-user-name
1351   *    which-jobs
1352   */
1353 
1354   request = ippNewRequest(IPP_GET_JOBS);
1355 
1356   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
1357                NULL, "ipp://localhost/");
1358 
1359   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1360                 "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]),
1361 		NULL, jattrs);
1362 
1363   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1364                NULL, cupsUser());
1365 
1366   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
1367                NULL, !strcmp(which, "successful") ? "completed" : which);
1368 
1369  /*
1370   * Do the request and get back a response...
1371   */
1372 
1373   response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/");
1374 
1375   if (cupsLastError() == IPP_STATUS_ERROR_SERVICE_UNAVAILABLE)
1376   {
1377     _cupsLangPrintf(stderr, _("%s: Scheduler is not running."), "lpstat");
1378     ippDelete(response);
1379     return (1);
1380   }
1381   if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
1382       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
1383   {
1384     _cupsLangPrintf(stderr,
1385 		    _("%s: Error - add '/version=1.1' to server name."),
1386 		    "lpstat");
1387     ippDelete(response);
1388     return (1);
1389   }
1390   else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1391   {
1392     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1393     ippDelete(response);
1394     return (1);
1395   }
1396 
1397   if (response)
1398   {
1399    /*
1400     * Loop through the job list and display them...
1401     */
1402 
1403     if (!strcmp(which, "aborted") ||
1404         !strcmp(which, "canceled") ||
1405         !strcmp(which, "successful") ||
1406         !strcmp(which, "completed"))
1407       time_at = "time-at-completed";
1408     else
1409       time_at = "time-at-creation";
1410 
1411     rank = -1;
1412 
1413     for (attr = response->attrs; attr != NULL; attr = attr->next)
1414     {
1415      /*
1416       * Skip leading attributes until we hit a job...
1417       */
1418 
1419       while (attr != NULL && attr->group_tag != IPP_TAG_JOB)
1420         attr = attr->next;
1421 
1422       if (attr == NULL)
1423         break;
1424 
1425      /*
1426       * Pull the needed attributes from this job...
1427       */
1428 
1429       jobid    = 0;
1430       size     = 0;
1431       username = NULL;
1432       dest     = NULL;
1433       jobtime  = 0;
1434       message  = NULL;
1435       reasons  = NULL;
1436 
1437       while (attr != NULL && attr->group_tag == IPP_TAG_JOB)
1438       {
1439         if (!strcmp(attr->name, "job-id") &&
1440 	    attr->value_tag == IPP_TAG_INTEGER)
1441 	  jobid = attr->values[0].integer;
1442         else if (!strcmp(attr->name, "job-k-octets") &&
1443 		 attr->value_tag == IPP_TAG_INTEGER)
1444 	  size = attr->values[0].integer;
1445         else if (!strcmp(attr->name, time_at) && attr->value_tag == IPP_TAG_INTEGER)
1446 	  jobtime = attr->values[0].integer;
1447         else if (!strcmp(attr->name, "job-printer-state-message") &&
1448 	         attr->value_tag == IPP_TAG_TEXT)
1449 	  message = attr->values[0].string.text;
1450         else if (!strcmp(attr->name, "job-printer-uri") &&
1451 	         attr->value_tag == IPP_TAG_URI)
1452 	{
1453 	  if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL)
1454 	    dest ++;
1455         }
1456         else if (!strcmp(attr->name, "job-originating-user-name") &&
1457 	         attr->value_tag == IPP_TAG_NAME)
1458 	  username = attr->values[0].string.text;
1459         else if (!strcmp(attr->name, "job-state-reasons") &&
1460 	         attr->value_tag == IPP_TAG_KEYWORD)
1461 	  reasons = attr;
1462 
1463         attr = attr->next;
1464       }
1465 
1466      /*
1467       * See if we have everything needed...
1468       */
1469 
1470       if (dest == NULL || jobid == 0)
1471       {
1472         if (attr == NULL)
1473 	  break;
1474 	else
1475           continue;
1476       }
1477 
1478      /*
1479       * Display the job...
1480       */
1481 
1482       rank ++;
1483 
1484       if (match_list(dests, dest) && match_list(users, username))
1485       {
1486 	if (!strcmp(which, "successful") && (!reasons || (reasons &&
1487 	    strcmp(reasons->values[0].string.text, "job-completed-successfully"))))
1488 	  continue;
1489 
1490 	snprintf(temp, sizeof(temp), "%s-%d", dest, jobid);
1491 
1492 	_cupsStrDate(date, sizeof(date), jobtime);
1493 
1494 	if (ranking)
1495 	  _cupsLangPrintf(stdout, "%3d %-21s %-13s %8.0f %s",
1496 			  rank, temp, username ? username : "unknown",
1497 			  1024.0 * size, date);
1498 	else
1499 	  _cupsLangPrintf(stdout, "%-23s %-13s %8.0f   %s",
1500 			  temp, username ? username : "unknown",
1501 			  1024.0 * size, date);
1502 	if (long_status)
1503 	{
1504 	  if (message)
1505 	    _cupsLangPrintf(stdout, _("\tStatus: %s"), message);
1506 
1507 	  if (reasons)
1508 	  {
1509 	    char	alerts[1024],	/* Alerts string */
1510 		      *aptr;		/* Pointer into alerts string */
1511 
1512 	    for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
1513 	    {
1514 	      if (i)
1515 		snprintf(aptr, sizeof(alerts) - (size_t)(aptr - alerts), " %s", reasons->values[i].string.text);
1516 	      else
1517 		strlcpy(alerts, reasons->values[i].string.text, sizeof(alerts));
1518 
1519 	      aptr += strlen(aptr);
1520 	    }
1521 
1522 	    _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
1523 	  }
1524 
1525 	  _cupsLangPrintf(stdout, _("\tqueued for %s"), dest);
1526 	}
1527       }
1528 
1529       if (attr == NULL)
1530         break;
1531     }
1532 
1533     ippDelete(response);
1534   }
1535 
1536   return (0);
1537 }
1538 
1539 
1540 /*
1541  * 'show_printers()' - Show printers.
1542  */
1543 
1544 static int				/* O - 0 on success, 1 on fail */
show_printers(const char * printers,int num_dests,cups_dest_t * dests,int long_status)1545 show_printers(const char  *printers,	/* I - Destinations */
1546               int         num_dests,	/* I - Number of user-defined dests */
1547 	      cups_dest_t *dests,	/* I - User-defined destinations */
1548               int         long_status)	/* I - Show long status? */
1549 {
1550   int		i, j;			/* Looping vars */
1551   ipp_t		*request,		/* IPP Request */
1552 		*response,		/* IPP Response */
1553 		*jobs;			/* IPP Get Jobs response */
1554   ipp_attribute_t *attr,		/* Current attribute */
1555 		*jobattr,		/* Job ID attribute */
1556 		*reasons;		/* Job state reasons attribute */
1557   const char	*printer,		/* Printer name */
1558 		*message,		/* Printer state message */
1559 		*description,		/* Description of printer */
1560 		*location,		/* Location of printer */
1561 		*make_model,		/* Make and model of printer */
1562 		*uri;			/* URI of printer */
1563   ipp_attribute_t *allowed,		/* requesting-user-name-allowed */
1564 		*denied;		/* requestint-user-name-denied */
1565   ipp_pstate_t	pstate;			/* Printer state */
1566   cups_ptype_t	ptype;			/* Printer type */
1567   time_t	ptime;			/* Printer state time */
1568   int		jobid;			/* Job ID of current job */
1569   char		printer_uri[HTTP_MAX_URI],
1570 					/* Printer URI */
1571 	printer_state_time[255];/* Printer state time */
1572   _cups_globals_t *cg = _cupsGlobals();	/* Global data */
1573   static const char *pattrs[] =		/* Attributes we need for printers... */
1574 		{
1575 		  "printer-name",
1576 		  "printer-state",
1577 		  "printer-state-message",
1578 		  "printer-state-reasons",
1579 		  "printer-state-change-time",
1580 		  "printer-type",
1581 		  "printer-info",
1582                   "printer-location",
1583 		  "printer-make-and-model",
1584 		  "printer-uri-supported",
1585 		  "requesting-user-name-allowed",
1586 		  "requesting-user-name-denied"
1587 		};
1588   static const char *jattrs[] =		/* Attributes we need for jobs... */
1589 		{
1590 		  "job-id",
1591 		  "job-state"
1592 		};
1593 
1594 
1595   if (printers != NULL && !strcmp(printers, "all"))
1596     printers = NULL;
1597 
1598  /*
1599   * Build a CUPS_GET_PRINTERS request, which requires the following
1600   * attributes:
1601   *
1602   *    attributes-charset
1603   *    attributes-natural-language
1604   *    requested-attributes
1605   *    requesting-user-name
1606   */
1607 
1608   request = ippNewRequest(CUPS_GET_PRINTERS);
1609 
1610   ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1611                 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]),
1612 		NULL, pattrs);
1613 
1614   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
1615                NULL, cupsUser());
1616 
1617  /*
1618   * Do the request and get back a response...
1619   */
1620 
1621   response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/");
1622 
1623   if (cupsLastError() == IPP_STATUS_ERROR_SERVICE_UNAVAILABLE)
1624   {
1625     _cupsLangPrintf(stderr, _("%s: Scheduler is not running."), "lpstat");
1626     ippDelete(response);
1627     return (1);
1628   }
1629   if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST ||
1630       cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED)
1631   {
1632     _cupsLangPrintf(stderr,
1633 		    _("%s: Error - add '/version=1.1' to server name."),
1634 		    "lpstat");
1635     ippDelete(response);
1636     return (1);
1637   }
1638   else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING)
1639   {
1640     _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString());
1641     ippDelete(response);
1642     return (1);
1643   }
1644 
1645   if (response)
1646   {
1647    /*
1648     * Loop through the printers returned in the list and display
1649     * their status...
1650     */
1651 
1652     for (attr = response->attrs; attr != NULL; attr = attr->next)
1653     {
1654      /*
1655       * Skip leading attributes until we hit a job...
1656       */
1657 
1658       while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
1659         attr = attr->next;
1660 
1661       if (attr == NULL)
1662         break;
1663 
1664      /*
1665       * Pull the needed attributes from this job...
1666       */
1667 
1668       printer     = NULL;
1669       ptime       = 0;
1670       ptype       = CUPS_PRINTER_LOCAL;
1671       pstate      = IPP_PRINTER_IDLE;
1672       message     = NULL;
1673       description = NULL;
1674       location    = NULL;
1675       make_model  = NULL;
1676       reasons     = NULL;
1677       uri         = NULL;
1678       jobid       = 0;
1679       allowed     = NULL;
1680       denied      = NULL;
1681 
1682       while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
1683       {
1684         if (!strcmp(attr->name, "printer-name") &&
1685 	    attr->value_tag == IPP_TAG_NAME)
1686 	  printer = attr->values[0].string.text;
1687         else if (!strcmp(attr->name, "printer-state") &&
1688 	         attr->value_tag == IPP_TAG_ENUM)
1689 	  pstate = (ipp_pstate_t)attr->values[0].integer;
1690         else if (!strcmp(attr->name, "printer-type") &&
1691 	         attr->value_tag == IPP_TAG_ENUM)
1692 	  ptype = (cups_ptype_t)attr->values[0].integer;
1693         else if (!strcmp(attr->name, "printer-state-message") &&
1694 	         attr->value_tag == IPP_TAG_TEXT)
1695 	  message = attr->values[0].string.text;
1696         else if (!strcmp(attr->name, "printer-state-change-time") &&
1697 	         attr->value_tag == IPP_TAG_INTEGER)
1698 	  ptime = (time_t)attr->values[0].integer;
1699 	else if (!strcmp(attr->name, "printer-info") &&
1700 	         attr->value_tag == IPP_TAG_TEXT)
1701 	  description = attr->values[0].string.text;
1702         else if (!strcmp(attr->name, "printer-location") &&
1703 	         attr->value_tag == IPP_TAG_TEXT)
1704 	  location = attr->values[0].string.text;
1705         else if (!strcmp(attr->name, "printer-make-and-model") &&
1706 	         attr->value_tag == IPP_TAG_TEXT)
1707 	  make_model = attr->values[0].string.text;
1708         else if (!strcmp(attr->name, "printer-uri-supported") &&
1709 	         attr->value_tag == IPP_TAG_URI)
1710 	  uri = attr->values[0].string.text;
1711         else if (!strcmp(attr->name, "printer-state-reasons") &&
1712 	         attr->value_tag == IPP_TAG_KEYWORD)
1713 	  reasons = attr;
1714         else if (!strcmp(attr->name, "requesting-user-name-allowed") &&
1715 	         attr->value_tag == IPP_TAG_NAME)
1716 	  allowed = attr;
1717         else if (!strcmp(attr->name, "requesting-user-name-denied") &&
1718 	         attr->value_tag == IPP_TAG_NAME)
1719 	  denied = attr;
1720 
1721         attr = attr->next;
1722       }
1723 
1724      /*
1725       * See if we have everything needed...
1726       */
1727 
1728       if (printer == NULL)
1729       {
1730         if (attr == NULL)
1731 	  break;
1732 	else
1733           continue;
1734       }
1735 
1736      /*
1737       * Display the printer entry if needed...
1738       */
1739 
1740       if (match_list(printers, printer))
1741       {
1742        /*
1743         * If the printer state is "IPP_PRINTER_PROCESSING", then grab the
1744 	* current job for the printer.
1745 	*/
1746 
1747         if (pstate == IPP_PRINTER_PROCESSING)
1748 	{
1749 	 /*
1750 	  * Build an IPP_GET_JOBS request, which requires the following
1751 	  * attributes:
1752 	  *
1753 	  *    attributes-charset
1754 	  *    attributes-natural-language
1755 	  *    printer-uri
1756 	  *    limit
1757           *    requested-attributes
1758 	  */
1759 
1760 	  request = ippNewRequest(IPP_GET_JOBS);
1761 
1762 	  request->request.op.operation_id = IPP_GET_JOBS;
1763 	  request->request.op.request_id   = 1;
1764 
1765 	  ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
1766                 	"requested-attributes",
1767 		        sizeof(jattrs) / sizeof(jattrs[0]), NULL, jattrs);
1768 
1769 	  httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri),
1770 	                   "ipp", NULL, "localhost", 0, "/printers/%s", printer);
1771 	  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
1772 	               "printer-uri", NULL, printer_uri);
1773 
1774           if ((jobs = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL)
1775 	  {
1776 	   /*
1777 	    * Get the current active job on this queue...
1778 	    */
1779 
1780             ipp_jstate_t jobstate = IPP_JOB_PENDING;
1781 	    jobid = 0;
1782 
1783 	    for (jobattr = jobs->attrs; jobattr; jobattr = jobattr->next)
1784 	    {
1785 	      if (!jobattr->name)
1786 	      {
1787 	        if (jobstate == IPP_JOB_PROCESSING)
1788 		  break;
1789 	        else
1790 		  continue;
1791               }
1792 
1793 	      if (!strcmp(jobattr->name, "job-id") &&
1794 	          jobattr->value_tag == IPP_TAG_INTEGER)
1795 		jobid = jobattr->values[0].integer;
1796               else if (!strcmp(jobattr->name, "job-state") &&
1797 	               jobattr->value_tag == IPP_TAG_ENUM)
1798 		jobstate = (ipp_jstate_t)jobattr->values[0].integer;
1799 	    }
1800 
1801             if (jobstate != IPP_JOB_PROCESSING)
1802 	      jobid = 0;
1803 
1804             ippDelete(jobs);
1805 	  }
1806         }
1807 
1808        /*
1809         * Display it...
1810 	*/
1811 
1812         _cupsStrDate(printer_state_time, sizeof(printer_state_time), ptime);
1813 
1814         switch (pstate)
1815 	{
1816 	  case IPP_PRINTER_IDLE :
1817 	      if (ippContainsString(reasons, "hold-new-jobs"))
1818 		_cupsLangPrintf(stdout, _("printer %s is holding new jobs.  enabled since %s"), printer, printer_state_time);
1819 	      else
1820 		_cupsLangPrintf(stdout, _("printer %s is idle.  enabled since %s"), printer, printer_state_time);
1821 	      break;
1822 	  case IPP_PRINTER_PROCESSING :
1823 	      _cupsLangPrintf(stdout, _("printer %s now printing %s-%d.  enabled since %s"), printer, printer, jobid, printer_state_time);
1824 	      break;
1825 	  case IPP_PRINTER_STOPPED :
1826 	      _cupsLangPrintf(stdout, _("printer %s disabled since %s -"), printer, printer_state_time);
1827 	      break;
1828 	}
1829 
1830         if ((message && *message) || pstate == IPP_PRINTER_STOPPED)
1831 	{
1832 	  if (message && *message)
1833 	  	_cupsLangPrintf(stdout, "\t%s", message);
1834 	  else
1835 	    _cupsLangPuts(stdout, _("\treason unknown"));
1836 	}
1837 
1838         if (long_status > 1)
1839 	{
1840 	  _cupsLangPuts(stdout, _("\tForm mounted:"));
1841 	  _cupsLangPuts(stdout, _("\tContent types: any"));
1842 	  _cupsLangPuts(stdout, _("\tPrinter types: unknown"));
1843 	}
1844 
1845         if (long_status)
1846 	{
1847 	  _cupsLangPrintf(stdout, _("\tDescription: %s"),
1848 	                  description ? description : "");
1849 
1850 	  if (reasons)
1851 	  {
1852 	    char	alerts[1024],	/* Alerts string */
1853 			*aptr;		/* Pointer into alerts string */
1854 
1855 	    for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
1856 	    {
1857 	      if (i)
1858 		snprintf(aptr, sizeof(alerts) - (size_t)(aptr - alerts), " %s", reasons->values[i].string.text);
1859 	      else
1860 		strlcpy(alerts, reasons->values[i].string.text, sizeof(alerts));
1861 
1862 	      aptr += strlen(aptr);
1863 	    }
1864 
1865 	    _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
1866 	  }
1867 	}
1868         if (long_status > 1)
1869 	{
1870 	  _cupsLangPrintf(stdout, _("\tLocation: %s"),
1871 	                  location ? location : "");
1872 
1873 	  if (ptype & CUPS_PRINTER_REMOTE)
1874 	  {
1875 	    _cupsLangPuts(stdout, _("\tConnection: remote"));
1876 
1877 	    if (make_model && !strstr(make_model, "System V Printer") &&
1878 	             !strstr(make_model, "Raw Printer") && uri)
1879 	      _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"),
1880 	                      uri);
1881 	  }
1882 	  else
1883 	  {
1884 	    _cupsLangPuts(stdout, _("\tConnection: direct"));
1885 
1886 	    if (make_model && !strstr(make_model, "Raw Printer"))
1887 	      _cupsLangPrintf(stdout,
1888 	                      _("\tInterface: %s/ppd/%s.ppd"),
1889 			      cg->cups_serverroot, printer);
1890           }
1891 	  _cupsLangPuts(stdout, _("\tOn fault: no alert"));
1892 	  _cupsLangPuts(stdout, _("\tAfter fault: continue"));
1893 	      /* TODO update to use printer-error-policy */
1894           if (allowed)
1895 	  {
1896 	    _cupsLangPuts(stdout, _("\tUsers allowed:"));
1897 	    for (j = 0; j < allowed->num_values; j ++)
1898 	      _cupsLangPrintf(stdout, "\t\t%s",
1899 	                      allowed->values[j].string.text);
1900 	  }
1901 	  else if (denied)
1902 	  {
1903 	    _cupsLangPuts(stdout, _("\tUsers denied:"));
1904 	    for (j = 0; j < denied->num_values; j ++)
1905 	      _cupsLangPrintf(stdout, "\t\t%s",
1906 	                      denied->values[j].string.text);
1907 	  }
1908 	  else
1909 	  {
1910 	    _cupsLangPuts(stdout, _("\tUsers allowed:"));
1911 	    _cupsLangPuts(stdout, _("\t\t(all)"));
1912 	  }
1913 	  _cupsLangPuts(stdout, _("\tForms allowed:"));
1914 	  _cupsLangPuts(stdout, _("\t\t(none)"));
1915 	  _cupsLangPuts(stdout, _("\tBanner required"));
1916 	  _cupsLangPuts(stdout, _("\tCharset sets:"));
1917 	  _cupsLangPuts(stdout, _("\t\t(none)"));
1918 	  _cupsLangPuts(stdout, _("\tDefault pitch:"));
1919 	  _cupsLangPuts(stdout, _("\tDefault page size:"));
1920 	  _cupsLangPuts(stdout, _("\tDefault port settings:"));
1921 	}
1922 
1923         for (i = 0; i < num_dests; i ++)
1924 	  if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance)
1925 	  {
1926             switch (pstate)
1927 	    {
1928 	      case IPP_PRINTER_IDLE :
1929 		  _cupsLangPrintf(stdout,
1930 		                  _("printer %s/%s is idle.  "
1931 				    "enabled since %s"),
1932 				  printer, dests[i].instance,
1933 				  printer_state_time);
1934 		  break;
1935 	      case IPP_PRINTER_PROCESSING :
1936 		  _cupsLangPrintf(stdout,
1937 		                  _("printer %s/%s now printing %s-%d.  "
1938 				    "enabled since %s"),
1939 				  printer, dests[i].instance, printer, jobid,
1940 				  printer_state_time);
1941 		  break;
1942 	      case IPP_PRINTER_STOPPED :
1943 		  _cupsLangPrintf(stdout,
1944 		                  _("printer %s/%s disabled since %s -"),
1945 				  printer, dests[i].instance,
1946 				  printer_state_time);
1947 		  break;
1948 	    }
1949 
1950             if ((message && *message) || pstate == IPP_PRINTER_STOPPED)
1951 	    {
1952 	      if (message && *message)
1953 		_cupsLangPrintf(stdout, "\t%s", message);
1954 	      else
1955 		_cupsLangPuts(stdout, _("\treason unknown"));
1956             }
1957 
1958             if (long_status > 1)
1959 	    {
1960 	      _cupsLangPuts(stdout, _("\tForm mounted:"));
1961 	      _cupsLangPuts(stdout, _("\tContent types: any"));
1962 	      _cupsLangPuts(stdout, _("\tPrinter types: unknown"));
1963 	    }
1964 
1965             if (long_status)
1966 	    {
1967 	      _cupsLangPrintf(stdout, _("\tDescription: %s"),
1968 	                      description ? description : "");
1969 
1970 	      if (reasons)
1971 	      {
1972 		char	alerts[1024],	/* Alerts string */
1973 			*aptr;		/* Pointer into alerts string */
1974 
1975 		for (i = 0, aptr = alerts; i < reasons->num_values; i ++)
1976 		{
1977 		  if (i)
1978 		    snprintf(aptr, sizeof(alerts) - (size_t)(aptr - alerts), " %s", reasons->values[i].string.text);
1979 		  else
1980 		    strlcpy(alerts, reasons->values[i].string.text, sizeof(alerts));
1981 
1982 		  aptr += strlen(aptr);
1983 		}
1984 
1985 		_cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts);
1986 	      }
1987 	    }
1988             if (long_status > 1)
1989 	    {
1990 	      _cupsLangPrintf(stdout, _("\tLocation: %s"),
1991 	                      location ? location : "");
1992 
1993 	      if (ptype & CUPS_PRINTER_REMOTE)
1994 	      {
1995 		_cupsLangPuts(stdout, _("\tConnection: remote"));
1996 
1997 		if (make_model && !strstr(make_model, "System V Printer") &&
1998 	        	 !strstr(make_model, "Raw Printer") && uri)
1999 		  _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"), uri);
2000 	      }
2001 	      else
2002 	      {
2003 		_cupsLangPuts(stdout, _("\tConnection: direct"));
2004 
2005 		if (make_model && !strstr(make_model, "Raw Printer"))
2006 		  _cupsLangPrintf(stdout,
2007 	                	  _("\tInterface: %s/ppd/%s.ppd"),
2008 				  cg->cups_serverroot, printer);
2009               }
2010 	      _cupsLangPuts(stdout, _("\tOn fault: no alert"));
2011 	      _cupsLangPuts(stdout, _("\tAfter fault: continue"));
2012 		  /* TODO update to use printer-error-policy */
2013               if (allowed)
2014 	      {
2015 		_cupsLangPuts(stdout, _("\tUsers allowed:"));
2016 		for (j = 0; j < allowed->num_values; j ++)
2017 		  _cupsLangPrintf(stdout, "\t\t%s",
2018 	                	  allowed->values[j].string.text);
2019 	      }
2020 	      else if (denied)
2021 	      {
2022 		_cupsLangPuts(stdout, _("\tUsers denied:"));
2023 		for (j = 0; j < denied->num_values; j ++)
2024 		  _cupsLangPrintf(stdout, "\t\t%s",
2025 	                	  denied->values[j].string.text);
2026 	      }
2027 	      else
2028 	      {
2029 		_cupsLangPuts(stdout, _("\tUsers allowed:"));
2030 		_cupsLangPuts(stdout, _("\t\t(all)"));
2031 	      }
2032 	      _cupsLangPuts(stdout, _("\tForms allowed:"));
2033 	      _cupsLangPuts(stdout, _("\t\t(none)"));
2034 	      _cupsLangPuts(stdout, _("\tBanner required"));
2035 	      _cupsLangPuts(stdout, _("\tCharset sets:"));
2036 	      _cupsLangPuts(stdout, _("\t\t(none)"));
2037 	      _cupsLangPuts(stdout, _("\tDefault pitch:"));
2038 	      _cupsLangPuts(stdout, _("\tDefault page size:"));
2039 	      _cupsLangPuts(stdout, _("\tDefault port settings:"));
2040 	    }
2041 	  }
2042       }
2043 
2044       if (attr == NULL)
2045         break;
2046     }
2047 
2048     ippDelete(response);
2049   }
2050 
2051   return (0);
2052 }
2053 
2054 
2055 /*
2056  * 'show_scheduler()' - Show scheduler status.
2057  */
2058 
2059 static int				/* 1 on success, 0 on failure */
show_scheduler(void)2060 show_scheduler(void)
2061 {
2062   http_t	*http;			/* Connection to server */
2063 
2064 
2065   if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
2066                                  cupsEncryption())) != NULL)
2067   {
2068     _cupsLangPuts(stdout, _("scheduler is running"));
2069     httpClose(http);
2070     return (1);
2071   }
2072   else
2073   {
2074     _cupsLangPuts(stdout, _("scheduler is not running"));
2075     return (0);
2076   }
2077 }
2078 
2079 
2080 /*
2081  * 'usage()' - Show program usage and exit.
2082  */
2083 
2084 static void
usage(void)2085 usage(void)
2086 {
2087   _cupsLangPuts(stdout, _("Usage: lpstat [options]"));
2088   _cupsLangPuts(stdout, _("Options:"));
2089   _cupsLangPuts(stdout, _("-E                      Encrypt the connection to the server"));
2090   _cupsLangPuts(stdout, _("-h server[:port]        Connect to the named server and port"));
2091   _cupsLangPuts(stdout, _("-l                      Show verbose (long) output"));
2092   _cupsLangPuts(stdout, _("-U username             Specify the username to use for authentication"));
2093 
2094   _cupsLangPuts(stdout, _("-H                      Show the default server and port"));
2095   _cupsLangPuts(stdout, _("-W completed            Show completed jobs"));
2096   _cupsLangPuts(stdout, _("-W not-completed        Show pending jobs"));
2097   _cupsLangPuts(stdout, _("-a [destination(s)]     Show the accepting state of destinations"));
2098   _cupsLangPuts(stdout, _("-c [class(es)]          Show classes and their member printers"));
2099   _cupsLangPuts(stdout, _("-d                      Show the default destination"));
2100   _cupsLangPuts(stdout, _("-e                      Show available destinations on the network"));
2101   _cupsLangPuts(stdout, _("-o [destination(s)]     Show jobs"));
2102   _cupsLangPuts(stdout, _("-p [printer(s)]         Show the processing state of destinations"));
2103   _cupsLangPuts(stdout, _("-r                      Show whether the CUPS server is running"));
2104   _cupsLangPuts(stdout, _("-R                      Show the ranking of jobs"));
2105   _cupsLangPuts(stdout, _("-s                      Show a status summary"));
2106   _cupsLangPuts(stdout, _("-t                      Show all status information"));
2107   _cupsLangPuts(stdout, _("-u [user(s)]            Show jobs queued by the current or specified users"));
2108   _cupsLangPuts(stdout, _("-v [printer(s)]         Show the devices for each destination"));
2109 
2110   exit(1);
2111 }
2112