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