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