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