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