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