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