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