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