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