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