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