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