1/* 2 * "$Id: lpstat.c 11433 2013-11-20 18:57:44Z msweet $" 3 * 4 * "lpstat" command for CUPS. 5 * 6 * Copyright 2007-2013 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 struct tm *pdate; /* Printer state date & time */ 653 char printer_state_time[255];/* Printer state time */ 654 static const char *pattrs[] = /* Attributes we need for printers... */ 655 { 656 "printer-name", 657 "printer-state-change-time", 658 "printer-state-message", 659 "printer-is-accepting-jobs" 660 }; 661 662 663 DEBUG_printf(("show_accepting(printers=\"%s\")\n", printers)); 664 665 if (printers != NULL && !strcmp(printers, "all")) 666 printers = NULL; 667 668 /* 669 * Build a CUPS_GET_PRINTERS request, which requires the following 670 * attributes: 671 * 672 * attributes-charset 673 * attributes-natural-language 674 * requested-attributes 675 * requesting-user-name 676 */ 677 678 request = ippNewRequest(CUPS_GET_PRINTERS); 679 680 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 681 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), 682 NULL, pattrs); 683 684 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 685 NULL, cupsUser()); 686 687 /* 688 * Do the request and get back a response... 689 */ 690 691 response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/"); 692 693 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST || 694 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) 695 { 696 _cupsLangPrintf(stderr, 697 _("%s: Error - add '/version=1.1' to server name."), 698 "lpstat"); 699 ippDelete(response); 700 return (1); 701 } 702 else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) 703 { 704 _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString()); 705 ippDelete(response); 706 return (1); 707 } 708 709 if (response) 710 { 711 DEBUG_puts("show_accepting: request succeeded..."); 712 713 /* 714 * Loop through the printers returned in the list and display 715 * their devices... 716 */ 717 718 for (attr = response->attrs; attr != NULL; attr = attr->next) 719 { 720 /* 721 * Skip leading attributes until we hit a printer... 722 */ 723 724 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 725 attr = attr->next; 726 727 if (attr == NULL) 728 break; 729 730 /* 731 * Pull the needed attributes from this printer... 732 */ 733 734 printer = NULL; 735 message = NULL; 736 accepting = 1; 737 ptime = 0; 738 739 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) 740 { 741 if (!strcmp(attr->name, "printer-name") && 742 attr->value_tag == IPP_TAG_NAME) 743 printer = attr->values[0].string.text; 744 else if (!strcmp(attr->name, "printer-state-change-time") && 745 attr->value_tag == IPP_TAG_INTEGER) 746 ptime = (time_t)attr->values[0].integer; 747 else if (!strcmp(attr->name, "printer-state-message") && 748 attr->value_tag == IPP_TAG_TEXT) 749 message = attr->values[0].string.text; 750 else if (!strcmp(attr->name, "printer-is-accepting-jobs") && 751 attr->value_tag == IPP_TAG_BOOLEAN) 752 accepting = attr->values[0].boolean; 753 754 attr = attr->next; 755 } 756 757 /* 758 * See if we have everything needed... 759 */ 760 761 if (printer == NULL) 762 { 763 if (attr == NULL) 764 break; 765 else 766 continue; 767 } 768 769 /* 770 * Display the printer entry if needed... 771 */ 772 773 if (match_list(printers, printer)) 774 { 775 pdate = localtime(&ptime); 776 strftime(printer_state_time, sizeof(printer_state_time), "%c", pdate); 777 778 if (accepting) 779 _cupsLangPrintf(stdout, _("%s accepting requests since %s"), 780 printer, printer_state_time); 781 else 782 { 783 _cupsLangPrintf(stdout, _("%s not accepting requests since %s -"), 784 printer, printer_state_time); 785 _cupsLangPrintf(stdout, _("\t%s"), 786 (message == NULL || !*message) ? 787 "reason unknown" : message); 788 } 789 790 for (i = 0; i < num_dests; i ++) 791 if (!_cups_strcasecmp(dests[i].name, printer) && dests[i].instance) 792 { 793 if (accepting) 794 _cupsLangPrintf(stdout, _("%s/%s accepting requests since %s"), 795 printer, dests[i].instance, printer_state_time); 796 else 797 { 798 _cupsLangPrintf(stdout, 799 _("%s/%s not accepting requests since %s -"), 800 printer, dests[i].instance, printer_state_time); 801 _cupsLangPrintf(stdout, _("\t%s"), 802 (message == NULL || !*message) ? 803 "reason unknown" : message); 804 } 805 } 806 } 807 808 if (attr == NULL) 809 break; 810 } 811 812 ippDelete(response); 813 } 814 815 return (0); 816} 817 818 819/* 820 * 'show_classes()' - Show printer classes. 821 */ 822 823static int /* O - 0 on success, 1 on fail */ 824show_classes(const char *dests) /* I - Destinations */ 825{ 826 int i; /* Looping var */ 827 ipp_t *request, /* IPP Request */ 828 *response, /* IPP Response */ 829 *response2; /* IPP response from remote server */ 830 http_t *http2; /* Remote server */ 831 ipp_attribute_t *attr; /* Current attribute */ 832 const char *printer, /* Printer class name */ 833 *printer_uri; /* Printer class URI */ 834 ipp_attribute_t *members; /* Printer members */ 835 char method[HTTP_MAX_URI], /* Request method */ 836 username[HTTP_MAX_URI], /* Username:password */ 837 server[HTTP_MAX_URI], /* Server name */ 838 resource[HTTP_MAX_URI]; /* Resource name */ 839 int port; /* Port number */ 840 static const char *cattrs[] = /* Attributes we need for classes... */ 841 { 842 "printer-name", 843 "printer-uri-supported", 844 "member-names" 845 }; 846 847 848 DEBUG_printf(("show_classes(dests=\"%s\")\n", dests)); 849 850 if (dests != NULL && !strcmp(dests, "all")) 851 dests = NULL; 852 853 /* 854 * Build a CUPS_GET_CLASSES request, which requires the following 855 * attributes: 856 * 857 * attributes-charset 858 * attributes-natural-language 859 * requested-attributes 860 * requesting-user-name 861 */ 862 863 request = ippNewRequest(CUPS_GET_CLASSES); 864 865 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 866 "requested-attributes", sizeof(cattrs) / sizeof(cattrs[0]), 867 NULL, cattrs); 868 869 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 870 NULL, cupsUser()); 871 872 /* 873 * Do the request and get back a response... 874 */ 875 876 response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/"); 877 878 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST || 879 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) 880 { 881 _cupsLangPrintf(stderr, 882 _("%s: Error - add '/version=1.1' to server name."), 883 "lpstat"); 884 ippDelete(response); 885 return (1); 886 } 887 else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) 888 { 889 _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString()); 890 ippDelete(response); 891 return (1); 892 } 893 894 if (response) 895 { 896 DEBUG_puts("show_classes: request succeeded..."); 897 898 if (response->request.status.status_code > IPP_OK_CONFLICT) 899 { 900 _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString()); 901 ippDelete(response); 902 return (1); 903 } 904 905 /* 906 * Loop through the printers returned in the list and display 907 * their devices... 908 */ 909 910 for (attr = response->attrs; attr != NULL; attr = attr->next) 911 { 912 /* 913 * Skip leading attributes until we hit a job... 914 */ 915 916 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 917 attr = attr->next; 918 919 if (attr == NULL) 920 break; 921 922 /* 923 * Pull the needed attributes from this job... 924 */ 925 926 printer = NULL; 927 printer_uri = NULL; 928 members = NULL; 929 930 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) 931 { 932 if (!strcmp(attr->name, "printer-name") && 933 attr->value_tag == IPP_TAG_NAME) 934 printer = attr->values[0].string.text; 935 936 if (!strcmp(attr->name, "printer-uri-supported") && 937 attr->value_tag == IPP_TAG_URI) 938 printer_uri = attr->values[0].string.text; 939 940 if (!strcmp(attr->name, "member-names") && 941 attr->value_tag == IPP_TAG_NAME) 942 members = attr; 943 944 attr = attr->next; 945 } 946 947 /* 948 * If this is a remote class, grab the class info from the 949 * remote server... 950 */ 951 952 response2 = NULL; 953 if (members == NULL && printer_uri != NULL) 954 { 955 httpSeparateURI(HTTP_URI_CODING_ALL, printer_uri, method, sizeof(method), 956 username, sizeof(username), server, sizeof(server), 957 &port, resource, sizeof(resource)); 958 959 if (!_cups_strcasecmp(server, cupsServer())) 960 http2 = CUPS_HTTP_DEFAULT; 961 else 962 http2 = httpConnectEncrypt(server, port, cupsEncryption()); 963 964 /* 965 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the 966 * following attributes: 967 * 968 * attributes-charset 969 * attributes-natural-language 970 * printer-uri 971 * requested-attributes 972 */ 973 974 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 975 976 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 977 "printer-uri", NULL, printer_uri); 978 979 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 980 "requested-attributes", 981 sizeof(cattrs) / sizeof(cattrs[0]), 982 NULL, cattrs); 983 984 if ((response2 = cupsDoRequest(http2, request, "/")) != NULL) 985 members = ippFindAttribute(response2, "member-names", IPP_TAG_NAME); 986 987 if (http2) 988 httpClose(http2); 989 } 990 991 /* 992 * See if we have everything needed... 993 */ 994 995 if (printer == NULL) 996 { 997 if (response2) 998 ippDelete(response2); 999 1000 if (attr == NULL) 1001 break; 1002 else 1003 continue; 1004 } 1005 1006 /* 1007 * Display the printer entry if needed... 1008 */ 1009 1010 if (match_list(dests, printer)) 1011 { 1012 _cupsLangPrintf(stdout, _("members of class %s:"), printer); 1013 1014 if (members) 1015 { 1016 for (i = 0; i < members->num_values; i ++) 1017 _cupsLangPrintf(stdout, "\t%s", members->values[i].string.text); 1018 } 1019 else 1020 _cupsLangPuts(stdout, "\tunknown"); 1021 } 1022 1023 if (response2) 1024 ippDelete(response2); 1025 1026 if (attr == NULL) 1027 break; 1028 } 1029 1030 ippDelete(response); 1031 } 1032 1033 return (0); 1034} 1035 1036 1037/* 1038 * 'show_default()' - Show default destination. 1039 */ 1040 1041static void 1042show_default(cups_dest_t *dest) /* I - Default destination */ 1043{ 1044 const char *printer, /* Printer name */ 1045 *val; /* Environment variable name */ 1046 1047 1048 if (dest) 1049 { 1050 if (dest->instance) 1051 _cupsLangPrintf(stdout, _("system default destination: %s/%s"), 1052 dest->name, dest->instance); 1053 else 1054 _cupsLangPrintf(stdout, _("system default destination: %s"), 1055 dest->name); 1056 } 1057 else 1058 { 1059 val = NULL; 1060 1061 if ((printer = getenv("LPDEST")) == NULL) 1062 { 1063 if ((printer = getenv("PRINTER")) != NULL) 1064 { 1065 if (!strcmp(printer, "lp")) 1066 printer = NULL; 1067 else 1068 val = "PRINTER"; 1069 } 1070 } 1071 else 1072 val = "LPDEST"; 1073 1074 if (printer) 1075 _cupsLangPrintf(stdout, 1076 _("lpstat: error - %s environment variable names " 1077 "non-existent destination \"%s\"."), 1078 val, printer); 1079 else 1080 _cupsLangPuts(stdout, _("no system default destination")); 1081 } 1082} 1083 1084 1085/* 1086 * 'show_devices()' - Show printer devices. 1087 */ 1088 1089static int /* O - 0 on success, 1 on fail */ 1090show_devices(const char *printers, /* I - Destinations */ 1091 int num_dests, /* I - Number of user-defined dests */ 1092 cups_dest_t *dests) /* I - User-defined destinations */ 1093{ 1094 int i; /* Looping var */ 1095 ipp_t *request, /* IPP Request */ 1096 *response; /* IPP Response */ 1097 ipp_attribute_t *attr; /* Current attribute */ 1098 const char *printer, /* Printer name */ 1099 *uri, /* Printer URI */ 1100 *device; /* Printer device URI */ 1101 static const char *pattrs[] = /* Attributes we need for printers... */ 1102 { 1103 "printer-name", 1104 "printer-uri-supported", 1105 "device-uri" 1106 }; 1107 1108 1109 DEBUG_printf(("show_devices(printers=\"%s\")\n", printers)); 1110 1111 if (printers != NULL && !strcmp(printers, "all")) 1112 printers = NULL; 1113 1114 /* 1115 * Build a CUPS_GET_PRINTERS request, which requires the following 1116 * attributes: 1117 * 1118 * attributes-charset 1119 * attributes-natural-language 1120 * requested-attributes 1121 * requesting-user-name 1122 */ 1123 1124 request = ippNewRequest(CUPS_GET_PRINTERS); 1125 1126 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1127 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), 1128 NULL, pattrs); 1129 1130 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 1131 NULL, cupsUser()); 1132 1133 /* 1134 * Do the request and get back a response... 1135 */ 1136 1137 response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/"); 1138 1139 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST || 1140 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) 1141 { 1142 _cupsLangPrintf(stderr, 1143 _("%s: Error - add '/version=1.1' to server name."), 1144 "lpstat"); 1145 ippDelete(response); 1146 return (1); 1147 } 1148 else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) 1149 { 1150 _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString()); 1151 ippDelete(response); 1152 return (1); 1153 } 1154 1155 if (response) 1156 { 1157 DEBUG_puts("show_devices: request succeeded..."); 1158 1159 /* 1160 * Loop through the printers returned in the list and display 1161 * their devices... 1162 */ 1163 1164 for (attr = response->attrs; attr != NULL; attr = attr->next) 1165 { 1166 /* 1167 * Skip leading attributes until we hit a job... 1168 */ 1169 1170 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 1171 attr = attr->next; 1172 1173 if (attr == NULL) 1174 break; 1175 1176 /* 1177 * Pull the needed attributes from this job... 1178 */ 1179 1180 printer = NULL; 1181 device = NULL; 1182 uri = NULL; 1183 1184 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) 1185 { 1186 if (!strcmp(attr->name, "printer-name") && 1187 attr->value_tag == IPP_TAG_NAME) 1188 printer = attr->values[0].string.text; 1189 1190 if (!strcmp(attr->name, "printer-uri-supported") && 1191 attr->value_tag == IPP_TAG_URI) 1192 uri = attr->values[0].string.text; 1193 1194 if (!strcmp(attr->name, "device-uri") && 1195 attr->value_tag == IPP_TAG_URI) 1196 device = attr->values[0].string.text; 1197 1198 attr = attr->next; 1199 } 1200 1201 /* 1202 * See if we have everything needed... 1203 */ 1204 1205 if (printer == NULL) 1206 { 1207 if (attr == NULL) 1208 break; 1209 else 1210 continue; 1211 } 1212 1213 /* 1214 * Display the printer entry if needed... 1215 */ 1216 1217 if (match_list(printers, printer)) 1218 { 1219#ifdef __osf__ /* Compaq/Digital like to do it their own way... */ 1220 char scheme[HTTP_MAX_URI], /* Components of printer URI */ 1221 username[HTTP_MAX_URI], 1222 hostname[HTTP_MAX_URI], 1223 resource[HTTP_MAX_URI]; 1224 int port; 1225 1226 1227 if (device == NULL) 1228 { 1229 httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), 1230 username, sizeof(username), hostname, 1231 sizeof(hostname), &port, resource, sizeof(resource)); 1232 _cupsLangPrintf(stdout, 1233 _("Output for printer %s is sent to remote " 1234 "printer %s on %s"), 1235 printer, strrchr(resource, '/') + 1, hostname); 1236 } 1237 else if (!strncmp(device, "file:", 5)) 1238 _cupsLangPrintf(stdout, 1239 _("Output for printer %s is sent to %s"), 1240 printer, device + 5); 1241 else 1242 _cupsLangPrintf(stdout, 1243 _("Output for printer %s is sent to %s"), 1244 printer, device); 1245 1246 for (i = 0; i < num_dests; i ++) 1247 if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance) 1248 { 1249 if (device == NULL) 1250 _cupsLangPrintf(stdout, 1251 _("Output for printer %s/%s is sent to " 1252 "remote printer %s on %s"), 1253 printer, dests[i].instance, 1254 strrchr(resource, '/') + 1, hostname); 1255 else if (!strncmp(device, "file:", 5)) 1256 _cupsLangPrintf(stdout, 1257 _("Output for printer %s/%s is sent to %s"), 1258 printer, dests[i].instance, device + 5); 1259 else 1260 _cupsLangPrintf(stdout, 1261 _("Output for printer %s/%s is sent to %s"), 1262 printer, dests[i].instance, device); 1263 } 1264#else 1265 if (device == NULL) 1266 _cupsLangPrintf(stdout, _("device for %s: %s"), 1267 printer, uri); 1268 else if (!strncmp(device, "file:", 5)) 1269 _cupsLangPrintf(stdout, _("device for %s: %s"), 1270 printer, device + 5); 1271 else 1272 _cupsLangPrintf(stdout, _("device for %s: %s"), 1273 printer, device); 1274 1275 for (i = 0; i < num_dests; i ++) 1276 if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance) 1277 { 1278 if (device == NULL) 1279 _cupsLangPrintf(stdout, _("device for %s/%s: %s"), 1280 printer, dests[i].instance, uri); 1281 else if (!strncmp(device, "file:", 5)) 1282 _cupsLangPrintf(stdout, _("device for %s/%s: %s"), 1283 printer, dests[i].instance, device + 5); 1284 else 1285 _cupsLangPrintf(stdout, _("device for %s/%s: %s"), 1286 printer, dests[i].instance, device); 1287 } 1288#endif /* __osf__ */ 1289 } 1290 1291 if (attr == NULL) 1292 break; 1293 } 1294 1295 ippDelete(response); 1296 } 1297 1298 return (0); 1299} 1300 1301 1302/* 1303 * 'show_jobs()' - Show active print jobs. 1304 */ 1305 1306static int /* O - 0 on success, 1 on fail */ 1307show_jobs(const char *dests, /* I - Destinations */ 1308 const char *users, /* I - Users */ 1309 int long_status, /* I - Show long status? */ 1310 int ranking, /* I - Show job ranking? */ 1311 const char *which) /* I - Show which jobs? */ 1312{ 1313 int i; /* Looping var */ 1314 ipp_t *request, /* IPP Request */ 1315 *response; /* IPP Response */ 1316 ipp_attribute_t *attr, /* Current attribute */ 1317 *reasons; /* Job state reasons attribute */ 1318 const char *dest, /* Pointer into job-printer-uri */ 1319 *username, /* Pointer to job-originating-user-name */ 1320 *title, /* Pointer to job-name */ 1321 *message; /* Pointer to job-printer-state-message */ 1322 int rank, /* Rank in queue */ 1323 jobid, /* job-id */ 1324 size; /* job-k-octets */ 1325 time_t jobtime; /* time-at-creation */ 1326 struct tm *jobdate; /* Date & time */ 1327 char temp[255], /* Temporary buffer */ 1328 date[255]; /* Date buffer */ 1329 static const char *jattrs[] = /* Attributes we need for jobs... */ 1330 { 1331 "job-id", 1332 "job-k-octets", 1333 "job-name", 1334 "job-originating-user-name", 1335 "job-printer-state-message", 1336 "job-printer-uri", 1337 "job-state-reasons", 1338 "time-at-creation" 1339 }; 1340 1341 1342 DEBUG_printf(("show_jobs(dests=\"%s\", users=\"%s\", long_status=%d, " 1343 "ranking=%d, which=\"%s\")\n", dests, users, long_status, 1344 ranking, which)); 1345 1346 if (dests != NULL && !strcmp(dests, "all")) 1347 dests = NULL; 1348 1349 /* 1350 * Build a IPP_GET_JOBS request, which requires the following 1351 * attributes: 1352 * 1353 * attributes-charset 1354 * attributes-natural-language 1355 * printer-uri 1356 * requested-attributes 1357 * requesting-user-name 1358 * which-jobs 1359 */ 1360 1361 request = ippNewRequest(IPP_GET_JOBS); 1362 1363 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 1364 NULL, "ipp://localhost/"); 1365 1366 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1367 "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]), 1368 NULL, jattrs); 1369 1370 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 1371 NULL, cupsUser()); 1372 1373 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", 1374 NULL, which); 1375 1376 /* 1377 * Do the request and get back a response... 1378 */ 1379 1380 response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/"); 1381 1382 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST || 1383 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) 1384 { 1385 _cupsLangPrintf(stderr, 1386 _("%s: Error - add '/version=1.1' to server name."), 1387 "lpstat"); 1388 ippDelete(response); 1389 return (1); 1390 } 1391 else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) 1392 { 1393 _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString()); 1394 ippDelete(response); 1395 return (1); 1396 } 1397 1398 if (response) 1399 { 1400 /* 1401 * Loop through the job list and display them... 1402 */ 1403 1404 rank = -1; 1405 1406 for (attr = response->attrs; attr != NULL; attr = attr->next) 1407 { 1408 /* 1409 * Skip leading attributes until we hit a job... 1410 */ 1411 1412 while (attr != NULL && attr->group_tag != IPP_TAG_JOB) 1413 attr = attr->next; 1414 1415 if (attr == NULL) 1416 break; 1417 1418 /* 1419 * Pull the needed attributes from this job... 1420 */ 1421 1422 jobid = 0; 1423 size = 0; 1424 username = NULL; 1425 dest = NULL; 1426 jobtime = 0; 1427 title = "no title"; 1428 message = NULL; 1429 reasons = NULL; 1430 1431 while (attr != NULL && attr->group_tag == IPP_TAG_JOB) 1432 { 1433 if (!strcmp(attr->name, "job-id") && 1434 attr->value_tag == IPP_TAG_INTEGER) 1435 jobid = attr->values[0].integer; 1436 else if (!strcmp(attr->name, "job-k-octets") && 1437 attr->value_tag == IPP_TAG_INTEGER) 1438 size = attr->values[0].integer; 1439 else if (!strcmp(attr->name, "time-at-creation") && 1440 attr->value_tag == IPP_TAG_INTEGER) 1441 jobtime = attr->values[0].integer; 1442 else if (!strcmp(attr->name, "job-printer-state-message") && 1443 attr->value_tag == IPP_TAG_TEXT) 1444 message = attr->values[0].string.text; 1445 else if (!strcmp(attr->name, "job-printer-uri") && 1446 attr->value_tag == IPP_TAG_URI) 1447 { 1448 if ((dest = strrchr(attr->values[0].string.text, '/')) != NULL) 1449 dest ++; 1450 } 1451 else if (!strcmp(attr->name, "job-originating-user-name") && 1452 attr->value_tag == IPP_TAG_NAME) 1453 username = attr->values[0].string.text; 1454 else if (!strcmp(attr->name, "job-name") && 1455 attr->value_tag == IPP_TAG_NAME) 1456 title = attr->values[0].string.text; 1457 else if (!strcmp(attr->name, "job-state-reasons") && 1458 attr->value_tag == IPP_TAG_KEYWORD) 1459 reasons = attr; 1460 1461 attr = attr->next; 1462 } 1463 1464 /* 1465 * See if we have everything needed... 1466 */ 1467 1468 if (dest == NULL || jobid == 0) 1469 { 1470 if (attr == NULL) 1471 break; 1472 else 1473 continue; 1474 } 1475 1476 /* 1477 * Display the job... 1478 */ 1479 1480 rank ++; 1481 1482 if (match_list(dests, dest) && match_list(users, username)) 1483 { 1484 jobdate = localtime(&jobtime); 1485 snprintf(temp, sizeof(temp), "%s-%d", dest, jobid); 1486 1487 if (long_status == 3) 1488 { 1489 /* 1490 * Show the consolidated output format for the SGI tools... 1491 */ 1492 1493 if (!strftime(date, sizeof(date), "%b %d %H:%M", jobdate)) 1494 strlcpy(date, "Unknown", sizeof(date)); 1495 1496 _cupsLangPrintf(stdout, "%s;%s;%d;%s;%s", 1497 temp, username ? username : "unknown", 1498 size, title ? title : "unknown", date); 1499 } 1500 else 1501 { 1502 if (!strftime(date, sizeof(date), "%c", jobdate)) 1503 strlcpy(date, "Unknown", sizeof(date)); 1504 1505 if (ranking) 1506 _cupsLangPrintf(stdout, "%3d %-21s %-13s %8.0f %s", 1507 rank, temp, username ? username : "unknown", 1508 1024.0 * size, date); 1509 else 1510 _cupsLangPrintf(stdout, "%-23s %-13s %8.0f %s", 1511 temp, username ? username : "unknown", 1512 1024.0 * size, date); 1513 if (long_status) 1514 { 1515 if (message) 1516 _cupsLangPrintf(stdout, _("\tStatus: %s"), message); 1517 1518 if (reasons) 1519 { 1520 char alerts[1024], /* Alerts string */ 1521 *aptr; /* Pointer into alerts string */ 1522 1523 for (i = 0, aptr = alerts; i < reasons->num_values; i ++) 1524 { 1525 if (i) 1526 snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s", 1527 reasons->values[i].string.text); 1528 else 1529 strlcpy(alerts, reasons->values[i].string.text, 1530 sizeof(alerts)); 1531 1532 aptr += strlen(aptr); 1533 } 1534 1535 _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts); 1536 } 1537 1538 _cupsLangPrintf(stdout, _("\tqueued for %s"), dest); 1539 } 1540 } 1541 } 1542 1543 if (attr == NULL) 1544 break; 1545 } 1546 1547 ippDelete(response); 1548 } 1549 1550 return (0); 1551} 1552 1553 1554/* 1555 * 'show_printers()' - Show printers. 1556 */ 1557 1558static int /* O - 0 on success, 1 on fail */ 1559show_printers(const char *printers, /* I - Destinations */ 1560 int num_dests, /* I - Number of user-defined dests */ 1561 cups_dest_t *dests, /* I - User-defined destinations */ 1562 int long_status) /* I - Show long status? */ 1563{ 1564 int i, j; /* Looping vars */ 1565 ipp_t *request, /* IPP Request */ 1566 *response, /* IPP Response */ 1567 *jobs; /* IPP Get Jobs response */ 1568 ipp_attribute_t *attr, /* Current attribute */ 1569 *jobattr, /* Job ID attribute */ 1570 *reasons; /* Job state reasons attribute */ 1571 const char *printer, /* Printer name */ 1572 *message, /* Printer state message */ 1573 *description, /* Description of printer */ 1574 *location, /* Location of printer */ 1575 *make_model, /* Make and model of printer */ 1576 *uri; /* URI of printer */ 1577 ipp_attribute_t *allowed, /* requesting-user-name-allowed */ 1578 *denied; /* requestint-user-name-denied */ 1579 ipp_pstate_t pstate; /* Printer state */ 1580 cups_ptype_t ptype; /* Printer type */ 1581 time_t ptime; /* Printer state time */ 1582 struct tm *pdate; /* Printer state date & time */ 1583 int jobid; /* Job ID of current job */ 1584 char printer_uri[HTTP_MAX_URI], 1585 /* Printer URI */ 1586 printer_state_time[255];/* Printer state time */ 1587 _cups_globals_t *cg = _cupsGlobals(); /* Global data */ 1588 static const char *pattrs[] = /* Attributes we need for printers... */ 1589 { 1590 "printer-name", 1591 "printer-state", 1592 "printer-state-message", 1593 "printer-state-reasons", 1594 "printer-state-change-time", 1595 "printer-type", 1596 "printer-info", 1597 "printer-location", 1598 "printer-make-and-model", 1599 "printer-uri-supported", 1600 "requesting-user-name-allowed", 1601 "requesting-user-name-denied" 1602 }; 1603 static const char *jattrs[] = /* Attributes we need for jobs... */ 1604 { 1605 "job-id", 1606 "job-state" 1607 }; 1608 1609 1610 DEBUG_printf(("show_printers(printers=\"%s\", num_dests=%d, dests=%p, " 1611 "long_status=%d)\n", printers, num_dests, dests, long_status)); 1612 1613 if (printers != NULL && !strcmp(printers, "all")) 1614 printers = NULL; 1615 1616 /* 1617 * Build a CUPS_GET_PRINTERS request, which requires the following 1618 * attributes: 1619 * 1620 * attributes-charset 1621 * attributes-natural-language 1622 * requested-attributes 1623 * requesting-user-name 1624 */ 1625 1626 request = ippNewRequest(CUPS_GET_PRINTERS); 1627 1628 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1629 "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), 1630 NULL, pattrs); 1631 1632 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 1633 NULL, cupsUser()); 1634 1635 /* 1636 * Do the request and get back a response... 1637 */ 1638 1639 response = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/"); 1640 1641 if (cupsLastError() == IPP_STATUS_ERROR_BAD_REQUEST || 1642 cupsLastError() == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) 1643 { 1644 _cupsLangPrintf(stderr, 1645 _("%s: Error - add '/version=1.1' to server name."), 1646 "lpstat"); 1647 ippDelete(response); 1648 return (1); 1649 } 1650 else if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) 1651 { 1652 _cupsLangPrintf(stderr, "lpstat: %s", cupsLastErrorString()); 1653 ippDelete(response); 1654 return (1); 1655 } 1656 1657 if (response) 1658 { 1659 DEBUG_puts("show_printers: request succeeded..."); 1660 1661 /* 1662 * Loop through the printers returned in the list and display 1663 * their status... 1664 */ 1665 1666 for (attr = response->attrs; attr != NULL; attr = attr->next) 1667 { 1668 /* 1669 * Skip leading attributes until we hit a job... 1670 */ 1671 1672 while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER) 1673 attr = attr->next; 1674 1675 if (attr == NULL) 1676 break; 1677 1678 /* 1679 * Pull the needed attributes from this job... 1680 */ 1681 1682 printer = NULL; 1683 ptime = 0; 1684 ptype = CUPS_PRINTER_LOCAL; 1685 pstate = IPP_PRINTER_IDLE; 1686 message = NULL; 1687 description = NULL; 1688 location = NULL; 1689 make_model = NULL; 1690 reasons = NULL; 1691 uri = NULL; 1692 jobid = 0; 1693 allowed = NULL; 1694 denied = NULL; 1695 1696 while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) 1697 { 1698 if (!strcmp(attr->name, "printer-name") && 1699 attr->value_tag == IPP_TAG_NAME) 1700 printer = attr->values[0].string.text; 1701 else if (!strcmp(attr->name, "printer-state") && 1702 attr->value_tag == IPP_TAG_ENUM) 1703 pstate = (ipp_pstate_t)attr->values[0].integer; 1704 else if (!strcmp(attr->name, "printer-type") && 1705 attr->value_tag == IPP_TAG_ENUM) 1706 ptype = (cups_ptype_t)attr->values[0].integer; 1707 else if (!strcmp(attr->name, "printer-state-message") && 1708 attr->value_tag == IPP_TAG_TEXT) 1709 message = attr->values[0].string.text; 1710 else if (!strcmp(attr->name, "printer-state-change-time") && 1711 attr->value_tag == IPP_TAG_INTEGER) 1712 ptime = (time_t)attr->values[0].integer; 1713 else if (!strcmp(attr->name, "printer-info") && 1714 attr->value_tag == IPP_TAG_TEXT) 1715 description = attr->values[0].string.text; 1716 else if (!strcmp(attr->name, "printer-location") && 1717 attr->value_tag == IPP_TAG_TEXT) 1718 location = attr->values[0].string.text; 1719 else if (!strcmp(attr->name, "printer-make-and-model") && 1720 attr->value_tag == IPP_TAG_TEXT) 1721 make_model = attr->values[0].string.text; 1722 else if (!strcmp(attr->name, "printer-uri-supported") && 1723 attr->value_tag == IPP_TAG_URI) 1724 uri = attr->values[0].string.text; 1725 else if (!strcmp(attr->name, "printer-state-reasons") && 1726 attr->value_tag == IPP_TAG_KEYWORD) 1727 reasons = attr; 1728 else if (!strcmp(attr->name, "requesting-user-name-allowed") && 1729 attr->value_tag == IPP_TAG_NAME) 1730 allowed = attr; 1731 else if (!strcmp(attr->name, "requesting-user-name-denied") && 1732 attr->value_tag == IPP_TAG_NAME) 1733 denied = attr; 1734 1735 attr = attr->next; 1736 } 1737 1738 /* 1739 * See if we have everything needed... 1740 */ 1741 1742 if (printer == NULL) 1743 { 1744 if (attr == NULL) 1745 break; 1746 else 1747 continue; 1748 } 1749 1750 /* 1751 * Display the printer entry if needed... 1752 */ 1753 1754 if (match_list(printers, printer)) 1755 { 1756 /* 1757 * If the printer state is "IPP_PRINTER_PROCESSING", then grab the 1758 * current job for the printer. 1759 */ 1760 1761 if (pstate == IPP_PRINTER_PROCESSING) 1762 { 1763 /* 1764 * Build an IPP_GET_JOBS request, which requires the following 1765 * attributes: 1766 * 1767 * attributes-charset 1768 * attributes-natural-language 1769 * printer-uri 1770 * limit 1771 * requested-attributes 1772 */ 1773 1774 request = ippNewRequest(IPP_GET_JOBS); 1775 1776 request->request.op.operation_id = IPP_GET_JOBS; 1777 request->request.op.request_id = 1; 1778 1779 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1780 "requested-attributes", 1781 sizeof(jattrs) / sizeof(jattrs[0]), NULL, jattrs); 1782 1783 httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), 1784 "ipp", NULL, "localhost", 0, "/printers/%s", printer); 1785 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 1786 "printer-uri", NULL, printer_uri); 1787 1788 if ((jobs = cupsDoRequest(CUPS_HTTP_DEFAULT, request, "/")) != NULL) 1789 { 1790 /* 1791 * Get the current active job on this queue... 1792 */ 1793 1794 ipp_jstate_t jobstate = IPP_JOB_PENDING; 1795 jobid = 0; 1796 1797 for (jobattr = jobs->attrs; jobattr; jobattr = jobattr->next) 1798 { 1799 if (!jobattr->name) 1800 { 1801 if (jobstate == IPP_JOB_PROCESSING) 1802 break; 1803 else 1804 continue; 1805 } 1806 1807 if (!strcmp(jobattr->name, "job-id") && 1808 jobattr->value_tag == IPP_TAG_INTEGER) 1809 jobid = jobattr->values[0].integer; 1810 else if (!strcmp(jobattr->name, "job-state") && 1811 jobattr->value_tag == IPP_TAG_ENUM) 1812 jobstate = jobattr->values[0].integer; 1813 } 1814 1815 if (jobstate != IPP_JOB_PROCESSING) 1816 jobid = 0; 1817 1818 ippDelete(jobs); 1819 } 1820 } 1821 1822 /* 1823 * Display it... 1824 */ 1825 1826 pdate = localtime(&ptime); 1827 strftime(printer_state_time, sizeof(printer_state_time), "%c", pdate); 1828 1829 switch (pstate) 1830 { 1831 case IPP_PRINTER_IDLE : 1832 _cupsLangPrintf(stdout, 1833 _("printer %s is idle. enabled since %s"), 1834 printer, printer_state_time); 1835 break; 1836 case IPP_PRINTER_PROCESSING : 1837 _cupsLangPrintf(stdout, 1838 _("printer %s now printing %s-%d. " 1839 "enabled since %s"), 1840 printer, printer, jobid, printer_state_time); 1841 break; 1842 case IPP_PRINTER_STOPPED : 1843 _cupsLangPrintf(stdout, 1844 _("printer %s disabled since %s -"), 1845 printer, printer_state_time); 1846 break; 1847 } 1848 1849 if ((message && *message) || pstate == IPP_PRINTER_STOPPED) 1850 { 1851 if (!message || !*message) 1852 _cupsLangPuts(stdout, _("\treason unknown")); 1853 else 1854 _cupsLangPrintf(stdout, "\t%s", message); 1855 } 1856 1857 if (long_status > 1) 1858 { 1859 _cupsLangPuts(stdout, _("\tForm mounted:")); 1860 _cupsLangPuts(stdout, _("\tContent types: any")); 1861 _cupsLangPuts(stdout, _("\tPrinter types: unknown")); 1862 } 1863 1864 if (long_status) 1865 { 1866 _cupsLangPrintf(stdout, _("\tDescription: %s"), 1867 description ? description : ""); 1868 1869 if (reasons) 1870 { 1871 char alerts[1024], /* Alerts string */ 1872 *aptr; /* Pointer into alerts string */ 1873 1874 for (i = 0, aptr = alerts; i < reasons->num_values; i ++) 1875 { 1876 if (i) 1877 snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s", 1878 reasons->values[i].string.text); 1879 else 1880 strlcpy(alerts, reasons->values[i].string.text, 1881 sizeof(alerts)); 1882 1883 aptr += strlen(aptr); 1884 } 1885 1886 _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts); 1887 } 1888 } 1889 if (long_status > 1) 1890 { 1891 _cupsLangPrintf(stdout, _("\tLocation: %s"), 1892 location ? location : ""); 1893 1894 if (ptype & CUPS_PRINTER_REMOTE) 1895 { 1896 _cupsLangPuts(stdout, _("\tConnection: remote")); 1897 1898 if (make_model && !strstr(make_model, "System V Printer") && 1899 !strstr(make_model, "Raw Printer") && uri) 1900 _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"), 1901 uri); 1902 } 1903 else 1904 { 1905 _cupsLangPuts(stdout, _("\tConnection: direct")); 1906 1907 if (make_model && strstr(make_model, "System V Printer")) 1908 _cupsLangPrintf(stdout, 1909 _("\tInterface: %s/interfaces/%s"), 1910 cg->cups_serverroot, printer); 1911 else if (make_model && !strstr(make_model, "Raw Printer")) 1912 _cupsLangPrintf(stdout, 1913 _("\tInterface: %s/ppd/%s.ppd"), 1914 cg->cups_serverroot, printer); 1915 } 1916 _cupsLangPuts(stdout, _("\tOn fault: no alert")); 1917 _cupsLangPuts(stdout, _("\tAfter fault: continue")); 1918 /* TODO update to use printer-error-policy */ 1919 if (allowed) 1920 { 1921 _cupsLangPuts(stdout, _("\tUsers allowed:")); 1922 for (j = 0; j < allowed->num_values; j ++) 1923 _cupsLangPrintf(stdout, "\t\t%s", 1924 allowed->values[j].string.text); 1925 } 1926 else if (denied) 1927 { 1928 _cupsLangPuts(stdout, _("\tUsers denied:")); 1929 for (j = 0; j < denied->num_values; j ++) 1930 _cupsLangPrintf(stdout, "\t\t%s", 1931 denied->values[j].string.text); 1932 } 1933 else 1934 { 1935 _cupsLangPuts(stdout, _("\tUsers allowed:")); 1936 _cupsLangPuts(stdout, _("\t\t(all)")); 1937 } 1938 _cupsLangPuts(stdout, _("\tForms allowed:")); 1939 _cupsLangPuts(stdout, _("\t\t(none)")); 1940 _cupsLangPuts(stdout, _("\tBanner required")); 1941 _cupsLangPuts(stdout, _("\tCharset sets:")); 1942 _cupsLangPuts(stdout, _("\t\t(none)")); 1943 _cupsLangPuts(stdout, _("\tDefault pitch:")); 1944 _cupsLangPuts(stdout, _("\tDefault page size:")); 1945 _cupsLangPuts(stdout, _("\tDefault port settings:")); 1946 } 1947 1948 for (i = 0; i < num_dests; i ++) 1949 if (!_cups_strcasecmp(printer, dests[i].name) && dests[i].instance) 1950 { 1951 switch (pstate) 1952 { 1953 case IPP_PRINTER_IDLE : 1954 _cupsLangPrintf(stdout, 1955 _("printer %s/%s is idle. " 1956 "enabled since %s"), 1957 printer, dests[i].instance, 1958 printer_state_time); 1959 break; 1960 case IPP_PRINTER_PROCESSING : 1961 _cupsLangPrintf(stdout, 1962 _("printer %s/%s now printing %s-%d. " 1963 "enabled since %s"), 1964 printer, dests[i].instance, printer, jobid, 1965 printer_state_time); 1966 break; 1967 case IPP_PRINTER_STOPPED : 1968 _cupsLangPrintf(stdout, 1969 _("printer %s/%s disabled since %s -"), 1970 printer, dests[i].instance, 1971 printer_state_time); 1972 break; 1973 } 1974 1975 if ((message && *message) || pstate == IPP_PRINTER_STOPPED) 1976 { 1977 if (!message || !*message) 1978 _cupsLangPuts(stdout, _("\treason unknown")); 1979 else 1980 _cupsLangPrintf(stdout, "\t%s", message); 1981 } 1982 1983 if (long_status > 1) 1984 { 1985 _cupsLangPuts(stdout, _("\tForm mounted:")); 1986 _cupsLangPuts(stdout, _("\tContent types: any")); 1987 _cupsLangPuts(stdout, _("\tPrinter types: unknown")); 1988 } 1989 1990 if (long_status) 1991 { 1992 _cupsLangPrintf(stdout, _("\tDescription: %s"), 1993 description ? description : ""); 1994 1995 if (reasons) 1996 { 1997 char alerts[1024], /* Alerts string */ 1998 *aptr; /* Pointer into alerts string */ 1999 2000 for (i = 0, aptr = alerts; i < reasons->num_values; i ++) 2001 { 2002 if (i) 2003 snprintf(aptr, sizeof(alerts) - (aptr - alerts), " %s", 2004 reasons->values[i].string.text); 2005 else 2006 strlcpy(alerts, reasons->values[i].string.text, 2007 sizeof(alerts)); 2008 2009 aptr += strlen(aptr); 2010 } 2011 2012 _cupsLangPrintf(stdout, _("\tAlerts: %s"), alerts); 2013 } 2014 } 2015 if (long_status > 1) 2016 { 2017 _cupsLangPrintf(stdout, _("\tLocation: %s"), 2018 location ? location : ""); 2019 2020 if (ptype & CUPS_PRINTER_REMOTE) 2021 { 2022 _cupsLangPuts(stdout, _("\tConnection: remote")); 2023 2024 if (make_model && !strstr(make_model, "System V Printer") && 2025 !strstr(make_model, "Raw Printer") && uri) 2026 _cupsLangPrintf(stdout, _("\tInterface: %s.ppd"), uri); 2027 } 2028 else 2029 { 2030 _cupsLangPuts(stdout, _("\tConnection: direct")); 2031 2032 if (make_model && strstr(make_model, "System V Printer")) 2033 _cupsLangPrintf(stdout, 2034 _("\tInterface: %s/interfaces/%s"), 2035 cg->cups_serverroot, printer); 2036 else if (make_model && !strstr(make_model, "Raw Printer")) 2037 _cupsLangPrintf(stdout, 2038 _("\tInterface: %s/ppd/%s.ppd"), 2039 cg->cups_serverroot, printer); 2040 } 2041 _cupsLangPuts(stdout, _("\tOn fault: no alert")); 2042 _cupsLangPuts(stdout, _("\tAfter fault: continue")); 2043 /* TODO update to use printer-error-policy */ 2044 if (allowed) 2045 { 2046 _cupsLangPuts(stdout, _("\tUsers allowed:")); 2047 for (j = 0; j < allowed->num_values; j ++) 2048 _cupsLangPrintf(stdout, "\t\t%s", 2049 allowed->values[j].string.text); 2050 } 2051 else if (denied) 2052 { 2053 _cupsLangPuts(stdout, _("\tUsers denied:")); 2054 for (j = 0; j < denied->num_values; j ++) 2055 _cupsLangPrintf(stdout, "\t\t%s", 2056 denied->values[j].string.text); 2057 } 2058 else 2059 { 2060 _cupsLangPuts(stdout, _("\tUsers allowed:")); 2061 _cupsLangPuts(stdout, _("\t\t(all)")); 2062 } 2063 _cupsLangPuts(stdout, _("\tForms allowed:")); 2064 _cupsLangPuts(stdout, _("\t\t(none)")); 2065 _cupsLangPuts(stdout, _("\tBanner required")); 2066 _cupsLangPuts(stdout, _("\tCharset sets:")); 2067 _cupsLangPuts(stdout, _("\t\t(none)")); 2068 _cupsLangPuts(stdout, _("\tDefault pitch:")); 2069 _cupsLangPuts(stdout, _("\tDefault page size:")); 2070 _cupsLangPuts(stdout, _("\tDefault port settings:")); 2071 } 2072 } 2073 } 2074 2075 if (attr == NULL) 2076 break; 2077 } 2078 2079 ippDelete(response); 2080 } 2081 2082 return (0); 2083} 2084 2085 2086/* 2087 * 'show_scheduler()' - Show scheduler status. 2088 */ 2089 2090static void 2091show_scheduler(void) 2092{ 2093 http_t *http; /* Connection to server */ 2094 2095 2096 if ((http = httpConnectEncrypt(cupsServer(), ippPort(), 2097 cupsEncryption())) != NULL) 2098 { 2099 _cupsLangPuts(stdout, _("scheduler is running")); 2100 httpClose(http); 2101 } 2102 else 2103 _cupsLangPuts(stdout, _("scheduler is not running")); 2104} 2105 2106 2107/* 2108 * End of "$Id: lpstat.c 11433 2013-11-20 18:57:44Z msweet $". 2109 */ 2110