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