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