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