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