1/* 2 * "$Id: lpadmin.c 11560 2014-02-06 20:10:19Z msweet $" 3 * 4 * "lpadmin" 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 int add_printer_to_class(http_t *http, char *printer, char *pclass); 28static int default_printer(http_t *http, char *printer); 29static int delete_printer(http_t *http, char *printer); 30static int delete_printer_from_class(http_t *http, char *printer, 31 char *pclass); 32static int delete_printer_option(http_t *http, char *printer, 33 char *option); 34static int enable_printer(http_t *http, char *printer); 35static cups_ptype_t get_printer_type(http_t *http, char *printer, char *uri, 36 size_t urisize); 37static int set_printer_options(http_t *http, char *printer, 38 int num_options, cups_option_t *options, 39 char *file); 40static int validate_name(const char *name); 41 42 43/* 44 * 'main()' - Parse options and configure the scheduler. 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 http_t *http; /* Connection to server */ 53 char *printer, /* Destination printer */ 54 *pclass, /* Printer class name */ 55 *val; /* Pointer to allow/deny value */ 56 int num_options; /* Number of options */ 57 cups_option_t *options; /* Options */ 58 char *file; /* New PPD file/interface script */ 59 60 61 _cupsSetLocale(argv); 62 63 http = NULL; 64 printer = NULL; 65 num_options = 0; 66 options = NULL; 67 file = NULL; 68 69 for (i = 1; i < argc; i ++) 70 if (argv[i][0] == '-') 71 switch (argv[i][1]) 72 { 73 case 'c' : /* Add printer to class */ 74 if (!http) 75 { 76 http = httpConnectEncrypt(cupsServer(), ippPort(), 77 cupsEncryption()); 78 79 if (http == NULL) 80 { 81 _cupsLangPrintf(stderr, 82 _("lpadmin: Unable to connect to server: %s"), 83 strerror(errno)); 84 return (1); 85 } 86 } 87 88 if (printer == NULL) 89 { 90 _cupsLangPuts(stderr, 91 _("lpadmin: Unable to add a printer to the class:\n" 92 " You must specify a printer name " 93 "first.")); 94 return (1); 95 } 96 97 if (argv[i][2]) 98 pclass = argv[i] + 2; 99 else 100 { 101 i ++; 102 103 if (i >= argc) 104 { 105 _cupsLangPuts(stderr, 106 _("lpadmin: Expected class name after \"-c\" " 107 "option.")); 108 return (1); 109 } 110 111 pclass = argv[i]; 112 } 113 114 if (!validate_name(pclass)) 115 { 116 _cupsLangPuts(stderr, 117 _("lpadmin: Class name can only contain printable " 118 "characters.")); 119 return (1); 120 } 121 122 if (add_printer_to_class(http, printer, pclass)) 123 return (1); 124 break; 125 126 case 'd' : /* Set as default destination */ 127 if (!http) 128 { 129 http = httpConnectEncrypt(cupsServer(), ippPort(), 130 cupsEncryption()); 131 132 if (http == NULL) 133 { 134 _cupsLangPrintf(stderr, 135 _("lpadmin: Unable to connect to server: %s"), 136 strerror(errno)); 137 return (1); 138 } 139 } 140 141 if (argv[i][2]) 142 printer = argv[i] + 2; 143 else 144 { 145 i ++; 146 147 if (i >= argc) 148 { 149 _cupsLangPuts(stderr, 150 _("lpadmin: Expected printer name after \"-d\" " 151 "option.")); 152 return (1); 153 } 154 155 printer = argv[i]; 156 } 157 158 if (!validate_name(printer)) 159 { 160 _cupsLangPuts(stderr, 161 _("lpadmin: Printer name can only contain " 162 "printable characters.")); 163 return (1); 164 } 165 166 if (default_printer(http, printer)) 167 return (1); 168 169 i = argc; 170 break; 171 172 case 'h' : /* Connect to host */ 173 if (http) 174 { 175 httpClose(http); 176 http = NULL; 177 } 178 179 if (argv[i][2] != '\0') 180 cupsSetServer(argv[i] + 2); 181 else 182 { 183 i ++; 184 185 if (i >= argc) 186 { 187 _cupsLangPuts(stderr, 188 _("lpadmin: Expected hostname after \"-h\" " 189 "option.")); 190 return (1); 191 } 192 193 cupsSetServer(argv[i]); 194 } 195 break; 196 197 case 'i' : /* Use the specified interface script */ 198 if (argv[i][2]) 199 file = argv[i] + 2; 200 else 201 { 202 i ++; 203 204 if (i >= argc) 205 { 206 _cupsLangPuts(stderr, 207 _("lpadmin: Expected interface after \"-i\" " 208 "option.")); 209 return (1); 210 } 211 212 file = argv[i]; 213 } 214 break; 215 216 case 'E' : /* Enable the printer */ 217 if (printer == NULL) 218 { 219#ifdef HAVE_SSL 220 cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); 221 222 if (http) 223 httpEncryption(http, HTTP_ENCRYPT_REQUIRED); 224#else 225 _cupsLangPrintf(stderr, _("%s: Sorry, no encryption support."), 226 argv[0]); 227#endif /* HAVE_SSL */ 228 break; 229 } 230 231 if (!http) 232 { 233 http = httpConnectEncrypt(cupsServer(), ippPort(), 234 cupsEncryption()); 235 236 if (http == NULL) 237 { 238 _cupsLangPrintf(stderr, 239 _("lpadmin: Unable to connect to server: %s"), 240 strerror(errno)); 241 return (1); 242 } 243 } 244 245 if (enable_printer(http, printer)) 246 return (1); 247 break; 248 249 case 'm' : /* Use the specified standard script/PPD file */ 250 if (argv[i][2]) 251 num_options = cupsAddOption("ppd-name", argv[i] + 2, num_options, 252 &options); 253 else 254 { 255 i ++; 256 257 if (i >= argc) 258 { 259 _cupsLangPuts(stderr, 260 _("lpadmin: Expected model after \"-m\" " 261 "option.")); 262 return (1); 263 } 264 265 num_options = cupsAddOption("ppd-name", argv[i], num_options, 266 &options); 267 } 268 break; 269 270 case 'o' : /* Set option */ 271 if (argv[i][2]) 272 num_options = cupsParseOptions(argv[i] + 2, num_options, &options); 273 else 274 { 275 i ++; 276 277 if (i >= argc) 278 { 279 _cupsLangPuts(stderr, 280 _("lpadmin: Expected name=value after \"-o\" " 281 "option.")); 282 return (1); 283 } 284 285 num_options = cupsParseOptions(argv[i], num_options, &options); 286 } 287 break; 288 289 case 'p' : /* Add/modify a printer */ 290 if (argv[i][2]) 291 printer = argv[i] + 2; 292 else 293 { 294 i ++; 295 296 if (i >= argc) 297 { 298 _cupsLangPuts(stderr, 299 _("lpadmin: Expected printer after \"-p\" " 300 "option.")); 301 return (1); 302 } 303 304 printer = argv[i]; 305 } 306 307 if (!validate_name(printer)) 308 { 309 _cupsLangPuts(stderr, 310 _("lpadmin: Printer name can only contain " 311 "printable characters.")); 312 return (1); 313 } 314 break; 315 316 case 'r' : /* Remove printer from class */ 317 if (!http) 318 { 319 http = httpConnectEncrypt(cupsServer(), ippPort(), 320 cupsEncryption()); 321 322 if (http == NULL) 323 { 324 _cupsLangPrintf(stderr, 325 _("lpadmin: Unable to connect to server: %s"), 326 strerror(errno)); 327 return (1); 328 } 329 } 330 331 if (printer == NULL) 332 { 333 _cupsLangPuts(stderr, 334 _("lpadmin: Unable to remove a printer from the " 335 "class:\n" 336 " You must specify a printer name " 337 "first.")); 338 return (1); 339 } 340 341 if (argv[i][2]) 342 pclass = argv[i] + 2; 343 else 344 { 345 i ++; 346 347 if (i >= argc) 348 { 349 _cupsLangPuts(stderr, 350 _("lpadmin: Expected class after \"-r\" " 351 "option.")); 352 return (1); 353 } 354 355 pclass = argv[i]; 356 } 357 358 if (!validate_name(pclass)) 359 { 360 _cupsLangPuts(stderr, 361 _("lpadmin: Class name can only contain printable " 362 "characters.")); 363 return (1); 364 } 365 366 if (delete_printer_from_class(http, printer, pclass)) 367 return (1); 368 break; 369 370 case 'R' : /* Remove option */ 371 if (!http) 372 { 373 http = httpConnectEncrypt(cupsServer(), ippPort(), 374 cupsEncryption()); 375 376 if (http == NULL) 377 { 378 _cupsLangPrintf(stderr, 379 _("lpadmin: Unable to connect to server: %s"), 380 strerror(errno)); 381 return (1); 382 } 383 } 384 385 if (printer == NULL) 386 { 387 _cupsLangPuts(stderr, 388 _("lpadmin: Unable to delete option:\n" 389 " You must specify a printer name " 390 "first.")); 391 return (1); 392 } 393 394 if (argv[i][2]) 395 val = argv[i] + 2; 396 else 397 { 398 i ++; 399 400 if (i >= argc) 401 { 402 _cupsLangPuts(stderr, 403 _("lpadmin: Expected name after \"-R\" " 404 "option.")); 405 return (1); 406 } 407 408 val = argv[i]; 409 } 410 411 if (delete_printer_option(http, printer, val)) 412 return (1); 413 break; 414 415 case 'U' : /* Username */ 416 if (argv[i][2] != '\0') 417 cupsSetUser(argv[i] + 2); 418 else 419 { 420 i ++; 421 if (i >= argc) 422 { 423 _cupsLangPrintf(stderr, 424 _("%s: Error - expected username after " 425 "\"-U\" option."), argv[0]); 426 return (1); 427 } 428 429 cupsSetUser(argv[i]); 430 } 431 break; 432 433 case 'u' : /* Allow/deny users */ 434 if (argv[i][2]) 435 val = argv[i] + 2; 436 else 437 { 438 i ++; 439 440 if (i >= argc) 441 { 442 _cupsLangPuts(stderr, 443 _("lpadmin: Expected allow/deny:userlist after " 444 "\"-u\" option.")); 445 return (1); 446 } 447 448 val = argv[i]; 449 } 450 451 if (!_cups_strncasecmp(val, "allow:", 6)) 452 num_options = cupsAddOption("requesting-user-name-allowed", 453 val + 6, num_options, &options); 454 else if (!_cups_strncasecmp(val, "deny:", 5)) 455 num_options = cupsAddOption("requesting-user-name-denied", 456 val + 5, num_options, &options); 457 else 458 { 459 _cupsLangPrintf(stderr, 460 _("lpadmin: Unknown allow/deny option \"%s\"."), 461 val); 462 return (1); 463 } 464 break; 465 466 case 'v' : /* Set the device-uri attribute */ 467 if (argv[i][2]) 468 num_options = cupsAddOption("device-uri", argv[i] + 2, 469 num_options, &options); 470 else 471 { 472 i ++; 473 474 if (i >= argc) 475 { 476 _cupsLangPuts(stderr, 477 _("lpadmin: Expected device URI after \"-v\" " 478 "option.")); 479 return (1); 480 } 481 482 num_options = cupsAddOption("device-uri", argv[i], 483 num_options, &options); 484 } 485 break; 486 487 case 'x' : /* Delete a printer */ 488 if (!http) 489 { 490 http = httpConnectEncrypt(cupsServer(), ippPort(), 491 cupsEncryption()); 492 493 if (http == NULL) 494 { 495 _cupsLangPrintf(stderr, 496 _("lpadmin: Unable to connect to server: %s"), 497 strerror(errno)); 498 return (1); 499 } 500 } 501 502 if (argv[i][2]) 503 printer = argv[i] + 2; 504 else 505 { 506 i ++; 507 508 if (i >= argc) 509 { 510 _cupsLangPuts(stderr, 511 _("lpadmin: Expected printer or class after " 512 "\"-x\" option.")); 513 return (1); 514 } 515 516 printer = argv[i]; 517 } 518 519 if (!validate_name(printer)) 520 { 521 _cupsLangPuts(stderr, 522 _("lpadmin: Printer name can only contain " 523 "printable characters.")); 524 return (1); 525 } 526 527 if (delete_printer(http, printer)) 528 return (1); 529 530 i = argc; 531 break; 532 533 case 'D' : /* Set the printer-info attribute */ 534 if (argv[i][2]) 535 num_options = cupsAddOption("printer-info", argv[i] + 2, 536 num_options, &options); 537 else 538 { 539 i ++; 540 541 if (i >= argc) 542 { 543 _cupsLangPuts(stderr, 544 _("lpadmin: Expected description after " 545 "\"-D\" option.")); 546 return (1); 547 } 548 549 num_options = cupsAddOption("printer-info", argv[i], 550 num_options, &options); 551 } 552 break; 553 554 case 'I' : /* Set the supported file types (ignored) */ 555 i ++; 556 557 if (i >= argc) 558 { 559 _cupsLangPuts(stderr, 560 _("lpadmin: Expected file type(s) after \"-I\" " 561 "option.")); 562 return (1); 563 } 564 565 _cupsLangPuts(stderr, 566 _("lpadmin: Warning - content type list ignored.")); 567 break; 568 569 case 'L' : /* Set the printer-location attribute */ 570 if (argv[i][2]) 571 num_options = cupsAddOption("printer-location", argv[i] + 2, 572 num_options, &options); 573 else 574 { 575 i ++; 576 577 if (i >= argc) 578 { 579 _cupsLangPuts(stderr, 580 _("lpadmin: Expected location after \"-L\" " 581 "option.")); 582 return (1); 583 } 584 585 num_options = cupsAddOption("printer-location", argv[i], 586 num_options, &options); 587 } 588 break; 589 590 case 'P' : /* Use the specified PPD file */ 591 if (argv[i][2]) 592 file = argv[i] + 2; 593 else 594 { 595 i ++; 596 597 if (i >= argc) 598 { 599 _cupsLangPuts(stderr, 600 _("lpadmin: Expected PPD after \"-P\" option.")); 601 return (1); 602 } 603 604 file = argv[i]; 605 } 606 break; 607 608 default : 609 _cupsLangPrintf(stderr, 610 _("lpadmin: Unknown option \"%c\"."), argv[i][1]); 611 return (1); 612 } 613 else 614 { 615 _cupsLangPrintf(stderr, _("lpadmin: Unknown argument \"%s\"."), 616 argv[i]); 617 return (1); 618 } 619 620 /* 621 * Set options as needed... 622 */ 623 624 if (num_options || file) 625 { 626 if (!http) 627 { 628 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); 629 630 if (http == NULL) 631 { 632 _cupsLangPrintf(stderr, 633 _("lpadmin: Unable to connect to server: %s"), 634 strerror(errno)); 635 return (1); 636 } 637 } 638 639 if (printer == NULL) 640 { 641 _cupsLangPuts(stderr, 642 _("lpadmin: Unable to set the printer options:\n" 643 " You must specify a printer name first.")); 644 return (1); 645 } 646 647 if (set_printer_options(http, printer, num_options, options, file)) 648 return (1); 649 } 650 651 if (printer == NULL) 652 { 653 _cupsLangPuts(stdout, 654 _("Usage:\n" 655 "\n" 656 " lpadmin [-h server] -d destination\n" 657 " lpadmin [-h server] -x destination\n" 658 " lpadmin [-h server] -p printer [-c add-class] " 659 "[-i interface] [-m model]\n" 660 " [-r remove-class] [-v device] " 661 "[-D description]\n" 662 " [-P ppd-file] [-o name=value]\n" 663 " [-u allow:user,user] " 664 "[-u deny:user,user]")); 665 } 666 667 if (http) 668 httpClose(http); 669 670 return (0); 671} 672 673 674/* 675 * 'add_printer_to_class()' - Add a printer to a class. 676 */ 677 678static int /* O - 0 on success, 1 on fail */ 679add_printer_to_class(http_t *http, /* I - Server connection */ 680 char *printer, /* I - Printer to add */ 681 char *pclass) /* I - Class to add to */ 682{ 683 int i; /* Looping var */ 684 ipp_t *request, /* IPP Request */ 685 *response; /* IPP Response */ 686 ipp_attribute_t *attr, /* Current attribute */ 687 *members; /* Members in class */ 688 char uri[HTTP_MAX_URI]; /* URI for printer/class */ 689 690 691 DEBUG_printf(("add_printer_to_class(%p, \"%s\", \"%s\")\n", http, 692 printer, pclass)); 693 694 /* 695 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following 696 * attributes: 697 * 698 * attributes-charset 699 * attributes-natural-language 700 * printer-uri 701 * requesting-user-name 702 */ 703 704 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 705 706 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 707 "localhost", 0, "/classes/%s", pclass); 708 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 709 "printer-uri", NULL, uri); 710 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 711 NULL, cupsUser()); 712 713 /* 714 * Do the request and get back a response... 715 */ 716 717 response = cupsDoRequest(http, request, "/"); 718 719 /* 720 * Build a CUPS_ADD_MODIFY_CLASS request, which requires the following 721 * attributes: 722 * 723 * attributes-charset 724 * attributes-natural-language 725 * printer-uri 726 * requesting-user-name 727 * member-uris 728 */ 729 730 request = ippNewRequest(CUPS_ADD_MODIFY_CLASS); 731 732 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 733 "printer-uri", NULL, uri); 734 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 735 NULL, cupsUser()); 736 737 /* 738 * See if the printer is already in the class... 739 */ 740 741 if (response != NULL && 742 (members = ippFindAttribute(response, "member-names", 743 IPP_TAG_NAME)) != NULL) 744 for (i = 0; i < members->num_values; i ++) 745 if (_cups_strcasecmp(printer, members->values[i].string.text) == 0) 746 { 747 _cupsLangPrintf(stderr, 748 _("lpadmin: Printer %s is already a member of class " 749 "%s."), printer, pclass); 750 ippDelete(request); 751 ippDelete(response); 752 return (0); 753 } 754 755 /* 756 * OK, the printer isn't part of the class, so add it... 757 */ 758 759 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 760 "localhost", 0, "/printers/%s", printer); 761 762 if (response != NULL && 763 (members = ippFindAttribute(response, "member-uris", 764 IPP_TAG_URI)) != NULL) 765 { 766 /* 767 * Add the printer to the existing list... 768 */ 769 770 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, 771 "member-uris", members->num_values + 1, NULL, NULL); 772 for (i = 0; i < members->num_values; i ++) 773 attr->values[i].string.text = 774 _cupsStrAlloc(members->values[i].string.text); 775 776 attr->values[i].string.text = _cupsStrAlloc(uri); 777 } 778 else 779 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", NULL, 780 uri); 781 782 /* 783 * Then send the request... 784 */ 785 786 ippDelete(response); 787 788 ippDelete(cupsDoRequest(http, request, "/admin/")); 789 if (cupsLastError() > IPP_OK_CONFLICT) 790 { 791 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 792 793 return (1); 794 } 795 else 796 return (0); 797} 798 799 800/* 801 * 'default_printer()' - Set the default printing destination. 802 */ 803 804static int /* O - 0 on success, 1 on fail */ 805default_printer(http_t *http, /* I - Server connection */ 806 char *printer) /* I - Printer name */ 807{ 808 ipp_t *request; /* IPP Request */ 809 char uri[HTTP_MAX_URI]; /* URI for printer/class */ 810 811 812 DEBUG_printf(("default_printer(%p, \"%s\")\n", http, printer)); 813 814 /* 815 * Build a CUPS_SET_DEFAULT request, which requires the following 816 * attributes: 817 * 818 * attributes-charset 819 * attributes-natural-language 820 * printer-uri 821 * requesting-user-name 822 */ 823 824 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 825 "localhost", 0, "/printers/%s", printer); 826 827 request = ippNewRequest(CUPS_SET_DEFAULT); 828 829 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 830 "printer-uri", NULL, uri); 831 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 832 NULL, cupsUser()); 833 834 /* 835 * Do the request and get back a response... 836 */ 837 838 ippDelete(cupsDoRequest(http, request, "/admin/")); 839 840 if (cupsLastError() > IPP_OK_CONFLICT) 841 { 842 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 843 844 return (1); 845 } 846 else 847 return (0); 848} 849 850 851/* 852 * 'delete_printer()' - Delete a printer from the system... 853 */ 854 855static int /* O - 0 on success, 1 on fail */ 856delete_printer(http_t *http, /* I - Server connection */ 857 char *printer) /* I - Printer to delete */ 858{ 859 ipp_t *request; /* IPP Request */ 860 char uri[HTTP_MAX_URI]; /* URI for printer/class */ 861 862 863 DEBUG_printf(("delete_printer(%p, \"%s\")\n", http, printer)); 864 865 /* 866 * Build a CUPS_DELETE_PRINTER request, which requires the following 867 * attributes: 868 * 869 * attributes-charset 870 * attributes-natural-language 871 * printer-uri 872 * requesting-user-name 873 */ 874 875 request = ippNewRequest(CUPS_DELETE_PRINTER); 876 877 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 878 "localhost", 0, "/printers/%s", printer); 879 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 880 "printer-uri", NULL, uri); 881 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 882 NULL, cupsUser()); 883 884 /* 885 * Do the request and get back a response... 886 */ 887 888 ippDelete(cupsDoRequest(http, request, "/admin/")); 889 890 if (cupsLastError() > IPP_OK_CONFLICT) 891 { 892 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 893 894 return (1); 895 } 896 else 897 return (0); 898} 899 900 901/* 902 * 'delete_printer_from_class()' - Delete a printer from a class. 903 */ 904 905static int /* O - 0 on success, 1 on fail */ 906delete_printer_from_class( 907 http_t *http, /* I - Server connection */ 908 char *printer, /* I - Printer to remove */ 909 char *pclass) /* I - Class to remove from */ 910{ 911 int i, j, k; /* Looping vars */ 912 ipp_t *request, /* IPP Request */ 913 *response; /* IPP Response */ 914 ipp_attribute_t *attr, /* Current attribute */ 915 *members; /* Members in class */ 916 char uri[HTTP_MAX_URI]; /* URI for printer/class */ 917 918 919 DEBUG_printf(("delete_printer_from_class(%p, \"%s\", \"%s\")\n", http, 920 printer, pclass)); 921 922 /* 923 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the following 924 * attributes: 925 * 926 * attributes-charset 927 * attributes-natural-language 928 * printer-uri 929 * requesting-user-name 930 */ 931 932 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 933 934 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 935 "localhost", 0, "/classes/%s", pclass); 936 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 937 "printer-uri", NULL, uri); 938 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 939 NULL, cupsUser()); 940 941 /* 942 * Do the request and get back a response... 943 */ 944 945 if ((response = cupsDoRequest(http, request, "/classes/")) == NULL || 946 response->request.status.status_code == IPP_NOT_FOUND) 947 { 948 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 949 950 ippDelete(response); 951 952 return (1); 953 } 954 955 /* 956 * See if the printer is already in the class... 957 */ 958 959 if ((members = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) == NULL) 960 { 961 _cupsLangPuts(stderr, _("lpadmin: No member names were seen.")); 962 963 ippDelete(response); 964 965 return (1); 966 } 967 968 for (i = 0; i < members->num_values; i ++) 969 if (!_cups_strcasecmp(printer, members->values[i].string.text)) 970 break; 971 972 if (i >= members->num_values) 973 { 974 _cupsLangPrintf(stderr, 975 _("lpadmin: Printer %s is not a member of class %s."), 976 printer, pclass); 977 978 ippDelete(response); 979 980 return (1); 981 } 982 983 if (members->num_values == 1) 984 { 985 /* 986 * Build a CUPS_DELETE_CLASS request, which requires the following 987 * attributes: 988 * 989 * attributes-charset 990 * attributes-natural-language 991 * printer-uri 992 * requesting-user-name 993 */ 994 995 request = ippNewRequest(CUPS_DELETE_CLASS); 996 997 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 998 "printer-uri", NULL, uri); 999 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 1000 "requesting-user-name", NULL, cupsUser()); 1001 } 1002 else 1003 { 1004 /* 1005 * Build a CUPS_ADD_MODIFY_CLASS request, which requires the following 1006 * attributes: 1007 * 1008 * attributes-charset 1009 * attributes-natural-language 1010 * printer-uri 1011 * requesting-user-name 1012 * member-uris 1013 */ 1014 1015 request = ippNewRequest(CUPS_ADD_MODIFY_CLASS); 1016 1017 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 1018 "printer-uri", NULL, uri); 1019 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 1020 "requesting-user-name", NULL, cupsUser()); 1021 1022 /* 1023 * Delete the printer from the class... 1024 */ 1025 1026 members = ippFindAttribute(response, "member-uris", IPP_TAG_URI); 1027 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, 1028 "member-uris", members->num_values - 1, NULL, NULL); 1029 1030 for (j = 0, k = 0; j < members->num_values; j ++) 1031 if (j != i) 1032 attr->values[k ++].string.text = 1033 _cupsStrAlloc(members->values[j].string.text); 1034 } 1035 1036 /* 1037 * Then send the request... 1038 */ 1039 1040 ippDelete(response); 1041 1042 ippDelete(cupsDoRequest(http, request, "/admin/")); 1043 1044 if (cupsLastError() > IPP_OK_CONFLICT) 1045 { 1046 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 1047 1048 return (1); 1049 } 1050 else 1051 return (0); 1052} 1053 1054 1055/* 1056 * 'delete_printer_option()' - Delete a printer option. 1057 */ 1058 1059static int /* O - 0 on success, 1 on fail */ 1060delete_printer_option(http_t *http, /* I - Server connection */ 1061 char *printer, /* I - Printer */ 1062 char *option) /* I - Option to delete */ 1063{ 1064 ipp_t *request; /* IPP request */ 1065 char uri[HTTP_MAX_URI]; /* URI for printer/class */ 1066 1067 1068 /* 1069 * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which 1070 * requires the following attributes: 1071 * 1072 * attributes-charset 1073 * attributes-natural-language 1074 * printer-uri 1075 * requesting-user-name 1076 * option with deleteAttr tag 1077 */ 1078 1079 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS) 1080 request = ippNewRequest(CUPS_ADD_MODIFY_CLASS); 1081 else 1082 request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); 1083 1084 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 1085 "printer-uri", NULL, uri); 1086 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 1087 "requesting-user-name", NULL, cupsUser()); 1088 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_DELETEATTR, option, 0); 1089 1090 /* 1091 * Do the request and get back a response... 1092 */ 1093 1094 ippDelete(cupsDoRequest(http, request, "/admin/")); 1095 1096 if (cupsLastError() > IPP_OK_CONFLICT) 1097 { 1098 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 1099 1100 return (1); 1101 } 1102 else 1103 return (0); 1104} 1105 1106 1107/* 1108 * 'enable_printer()' - Enable a printer... 1109 */ 1110 1111static int /* O - 0 on success, 1 on fail */ 1112enable_printer(http_t *http, /* I - Server connection */ 1113 char *printer) /* I - Printer to enable */ 1114{ 1115 ipp_t *request; /* IPP Request */ 1116 char uri[HTTP_MAX_URI]; /* URI for printer/class */ 1117 1118 1119 DEBUG_printf(("enable_printer(%p, \"%s\")\n", http, printer)); 1120 1121 /* 1122 * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which 1123 * require the following attributes: 1124 * 1125 * attributes-charset 1126 * attributes-natural-language 1127 * printer-uri 1128 * requesting-user-name 1129 * printer-state 1130 * printer-is-accepting-jobs 1131 */ 1132 1133 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS) 1134 request = ippNewRequest(CUPS_ADD_MODIFY_CLASS); 1135 else 1136 request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); 1137 1138 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 1139 "printer-uri", NULL, uri); 1140 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 1141 "requesting-user-name", NULL, cupsUser()); 1142 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", 1143 IPP_PRINTER_IDLE); 1144 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); 1145 1146 /* 1147 * Do the request and get back a response... 1148 */ 1149 1150 ippDelete(cupsDoRequest(http, request, "/admin/")); 1151 1152 if (cupsLastError() > IPP_OK_CONFLICT) 1153 { 1154 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 1155 1156 return (1); 1157 } 1158 else 1159 return (0); 1160} 1161 1162 1163/* 1164 * 'get_printer_type()' - Determine the printer type and URI. 1165 */ 1166 1167static cups_ptype_t /* O - printer-type value */ 1168get_printer_type(http_t *http, /* I - Server connection */ 1169 char *printer, /* I - Printer name */ 1170 char *uri, /* I - URI buffer */ 1171 size_t urisize) /* I - Size of URI buffer */ 1172{ 1173 ipp_t *request, /* IPP request */ 1174 *response; /* IPP response */ 1175 ipp_attribute_t *attr; /* printer-type attribute */ 1176 cups_ptype_t type; /* printer-type value */ 1177 1178 1179 /* 1180 * Build a GET_PRINTER_ATTRIBUTES request, which requires the following 1181 * attributes: 1182 * 1183 * attributes-charset 1184 * attributes-natural-language 1185 * printer-uri 1186 * requested-attributes 1187 * requesting-user-name 1188 */ 1189 1190 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/printers/%s", printer); 1191 1192 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 1193 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 1194 "printer-uri", NULL, uri); 1195 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1196 "requested-attributes", NULL, "printer-type"); 1197 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 1198 "requesting-user-name", NULL, cupsUser()); 1199 1200 /* 1201 * Do the request... 1202 */ 1203 1204 response = cupsDoRequest(http, request, "/"); 1205 if ((attr = ippFindAttribute(response, "printer-type", 1206 IPP_TAG_ENUM)) != NULL) 1207 { 1208 type = (cups_ptype_t)attr->values[0].integer; 1209 1210 if (type & CUPS_PRINTER_CLASS) 1211 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, (int)urisize, "ipp", NULL, "localhost", ippPort(), "/classes/%s", printer); 1212 } 1213 else 1214 type = CUPS_PRINTER_LOCAL; 1215 1216 ippDelete(response); 1217 1218 return (type); 1219} 1220 1221 1222/* 1223 * 'set_printer_options()' - Set the printer options. 1224 */ 1225 1226static int /* O - 0 on success, 1 on fail */ 1227set_printer_options( 1228 http_t *http, /* I - Server connection */ 1229 char *printer, /* I - Printer */ 1230 int num_options, /* I - Number of options */ 1231 cups_option_t *options, /* I - Options */ 1232 char *file) /* I - PPD file/interface script */ 1233{ 1234 ipp_t *request; /* IPP Request */ 1235 const char *ppdfile; /* PPD filename */ 1236 int ppdchanged; /* PPD changed? */ 1237 ppd_file_t *ppd; /* PPD file */ 1238 ppd_choice_t *choice; /* Marked choice */ 1239 char uri[HTTP_MAX_URI], /* URI for printer/class */ 1240 line[1024], /* Line from PPD file */ 1241 keyword[1024], /* Keyword from Default line */ 1242 *keyptr, /* Pointer into keyword... */ 1243 tempfile[1024]; /* Temporary filename */ 1244 cups_file_t *in, /* PPD file */ 1245 *out; /* Temporary file */ 1246 const char *protocol, /* Old protocol option */ 1247 *customval, /* Custom option value */ 1248 *boolval; /* Boolean value */ 1249 int wrote_ipp_supplies = 0, /* Wrote cupsIPPSupplies keyword? */ 1250 wrote_snmp_supplies = 0;/* Wrote cupsSNMPSupplies keyword? */ 1251 1252 1253 DEBUG_printf(("set_printer_options(http=%p, printer=\"%s\", num_options=%d, " 1254 "options=%p, file=\"%s\")\n", http, printer, num_options, 1255 options, file)); 1256 1257 /* 1258 * Build a CUPS_ADD_MODIFY_PRINTER or CUPS_ADD_MODIFY_CLASS request, which 1259 * requires the following attributes: 1260 * 1261 * attributes-charset 1262 * attributes-natural-language 1263 * printer-uri 1264 * requesting-user-name 1265 * other options 1266 */ 1267 1268 if (get_printer_type(http, printer, uri, sizeof(uri)) & CUPS_PRINTER_CLASS) 1269 request = ippNewRequest(CUPS_ADD_MODIFY_CLASS); 1270 else 1271 request = ippNewRequest(CUPS_ADD_MODIFY_PRINTER); 1272 1273 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, 1274 "printer-uri", NULL, uri); 1275 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, 1276 "requesting-user-name", NULL, cupsUser()); 1277 1278 /* 1279 * Add the options... 1280 */ 1281 1282 cupsEncodeOptions2(request, num_options, options, IPP_TAG_OPERATION); 1283 cupsEncodeOptions2(request, num_options, options, IPP_TAG_PRINTER); 1284 1285 if ((protocol = cupsGetOption("protocol", num_options, options)) != NULL) 1286 { 1287 if (!_cups_strcasecmp(protocol, "bcp")) 1288 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor", 1289 NULL, "bcp"); 1290 else if (!_cups_strcasecmp(protocol, "tbcp")) 1291 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "port-monitor", 1292 NULL, "tbcp"); 1293 } 1294 1295 if (file) 1296 ppdfile = file; 1297 else if (request->request.op.operation_id == CUPS_ADD_MODIFY_PRINTER) 1298 ppdfile = cupsGetPPD(printer); 1299 else 1300 ppdfile = NULL; 1301 1302 if (ppdfile != NULL) 1303 { 1304 /* 1305 * Set default options in the PPD file... 1306 */ 1307 1308 ppd = ppdOpenFile(ppdfile); 1309 ppdMarkDefaults(ppd); 1310 cupsMarkOptions(ppd, num_options, options); 1311 1312 if ((out = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL) 1313 { 1314 _cupsLangPrintError(NULL, _("lpadmin: Unable to create temporary file")); 1315 ippDelete(request); 1316 if (ppdfile != file) 1317 unlink(ppdfile); 1318 return (1); 1319 } 1320 1321 if ((in = cupsFileOpen(ppdfile, "r")) == NULL) 1322 { 1323 _cupsLangPrintf(stderr, 1324 _("lpadmin: Unable to open PPD file \"%s\" - %s"), 1325 ppdfile, strerror(errno)); 1326 ippDelete(request); 1327 if (ppdfile != file) 1328 unlink(ppdfile); 1329 cupsFileClose(out); 1330 unlink(tempfile); 1331 return (1); 1332 } 1333 1334 ppdchanged = 0; 1335 1336 while (cupsFileGets(in, line, sizeof(line))) 1337 { 1338 if (!strncmp(line, "*cupsIPPSupplies:", 17) && 1339 (boolval = cupsGetOption("cupsIPPSupplies", num_options, 1340 options)) != NULL) 1341 { 1342 wrote_ipp_supplies = 1; 1343 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n", 1344 (!_cups_strcasecmp(boolval, "true") || 1345 !_cups_strcasecmp(boolval, "yes") || 1346 !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); 1347 } 1348 else if (!strncmp(line, "*cupsSNMPSupplies:", 18) && 1349 (boolval = cupsGetOption("cupsSNMPSupplies", num_options, 1350 options)) != NULL) 1351 { 1352 wrote_snmp_supplies = 1; 1353 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n", 1354 (!_cups_strcasecmp(boolval, "true") || 1355 !_cups_strcasecmp(boolval, "yes") || 1356 !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); 1357 } 1358 else if (strncmp(line, "*Default", 8)) 1359 cupsFilePrintf(out, "%s\n", line); 1360 else 1361 { 1362 /* 1363 * Get default option name... 1364 */ 1365 1366 strlcpy(keyword, line + 8, sizeof(keyword)); 1367 1368 for (keyptr = keyword; *keyptr; keyptr ++) 1369 if (*keyptr == ':' || isspace(*keyptr & 255)) 1370 break; 1371 1372 *keyptr++ = '\0'; 1373 while (isspace(*keyptr & 255)) 1374 keyptr ++; 1375 1376 if (!strcmp(keyword, "PageRegion") || 1377 !strcmp(keyword, "PageSize") || 1378 !strcmp(keyword, "PaperDimension") || 1379 !strcmp(keyword, "ImageableArea")) 1380 { 1381 if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) == NULL) 1382 choice = ppdFindMarkedChoice(ppd, "PageRegion"); 1383 } 1384 else 1385 choice = ppdFindMarkedChoice(ppd, keyword); 1386 1387 if (choice && strcmp(choice->choice, keyptr)) 1388 { 1389 if (strcmp(choice->choice, "Custom")) 1390 { 1391 cupsFilePrintf(out, "*Default%s: %s\n", keyword, choice->choice); 1392 ppdchanged = 1; 1393 } 1394 else if ((customval = cupsGetOption(keyword, num_options, 1395 options)) != NULL) 1396 { 1397 cupsFilePrintf(out, "*Default%s: %s\n", keyword, customval); 1398 ppdchanged = 1; 1399 } 1400 else 1401 cupsFilePrintf(out, "%s\n", line); 1402 } 1403 else 1404 cupsFilePrintf(out, "%s\n", line); 1405 } 1406 } 1407 1408 if (!wrote_ipp_supplies && 1409 (boolval = cupsGetOption("cupsIPPSupplies", num_options, 1410 options)) != NULL) 1411 { 1412 cupsFilePrintf(out, "*cupsIPPSupplies: %s\n", 1413 (!_cups_strcasecmp(boolval, "true") || 1414 !_cups_strcasecmp(boolval, "yes") || 1415 !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); 1416 } 1417 1418 if (!wrote_snmp_supplies && 1419 (boolval = cupsGetOption("cupsSNMPSupplies", num_options, 1420 options)) != NULL) 1421 { 1422 cupsFilePrintf(out, "*cupsSNMPSupplies: %s\n", 1423 (!_cups_strcasecmp(boolval, "true") || 1424 !_cups_strcasecmp(boolval, "yes") || 1425 !_cups_strcasecmp(boolval, "on")) ? "True" : "False"); 1426 } 1427 1428 cupsFileClose(in); 1429 cupsFileClose(out); 1430 ppdClose(ppd); 1431 1432 /* 1433 * Do the request... 1434 */ 1435 1436 ippDelete(cupsDoFileRequest(http, request, "/admin/", 1437 ppdchanged ? tempfile : file)); 1438 1439 /* 1440 * Clean up temp files... (TODO: catch signals in case we CTRL-C during 1441 * lpadmin) 1442 */ 1443 1444 if (ppdfile != file) 1445 unlink(ppdfile); 1446 unlink(tempfile); 1447 } 1448 else 1449 { 1450 /* 1451 * No PPD file - just set the options... 1452 */ 1453 1454 ippDelete(cupsDoRequest(http, request, "/admin/")); 1455 } 1456 1457 /* 1458 * Check the response... 1459 */ 1460 1461 if (cupsLastError() > IPP_OK_CONFLICT) 1462 { 1463 _cupsLangPrintf(stderr, _("%s: %s"), "lpadmin", cupsLastErrorString()); 1464 1465 return (1); 1466 } 1467 else 1468 return (0); 1469} 1470 1471 1472/* 1473 * 'validate_name()' - Make sure the printer name only contains valid chars. 1474 */ 1475 1476static int /* O - 0 if name is no good, 1 if name is good */ 1477validate_name(const char *name) /* I - Name to check */ 1478{ 1479 const char *ptr; /* Pointer into name */ 1480 1481 1482 /* 1483 * Scan the whole name... 1484 */ 1485 1486 for (ptr = name; *ptr; ptr ++) 1487 if (*ptr == '@') 1488 break; 1489 else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || 1490 *ptr == '#') 1491 return (0); 1492 1493 /* 1494 * All the characters are good; validate the length, too... 1495 */ 1496 1497 return ((ptr - name) < 128); 1498} 1499 1500 1501/* 1502 * End of "$Id: lpadmin.c 11560 2014-02-06 20:10:19Z msweet $". 1503 */ 1504