1/* 2 * "$Id: admin.c 12131 2014-08-28 23:38:16Z msweet $" 3 * 4 * Administration CGI for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 1997-2007 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 "cgi-private.h" 21#include <cups/adminutil.h> 22#include <cups/ppd.h> 23#include <errno.h> 24#include <unistd.h> 25#include <fcntl.h> 26#include <sys/wait.h> 27#include <limits.h> 28 29 30/* 31 * Local globals... 32 */ 33 34static int current_device = 0; /* Current device shown */ 35 36 37/* 38 * Local functions... 39 */ 40 41static void choose_device_cb(const char *device_class, 42 const char *device_id, const char *device_info, 43 const char *device_make_and_model, 44 const char *device_uri, 45 const char *device_location, 46 const char *title); 47static void do_add_rss_subscription(http_t *http); 48static void do_am_class(http_t *http, int modify); 49static void do_am_printer(http_t *http, int modify); 50static void do_cancel_subscription(http_t *http); 51static void do_config_server(http_t *http); 52static void do_delete_class(http_t *http); 53static void do_delete_printer(http_t *http); 54static void do_export(http_t *http); 55static void do_list_printers(http_t *http); 56static void do_menu(http_t *http); 57static void do_set_allowed_users(http_t *http); 58static void do_set_default(http_t *http); 59static void do_set_options(http_t *http, int is_class); 60static void do_set_sharing(http_t *http); 61static char *get_option_value(ppd_file_t *ppd, const char *name, 62 char *buffer, size_t bufsize); 63static double get_points(double number, const char *uval); 64 65 66/* 67 * 'main()' - Main entry for CGI. 68 */ 69 70int /* O - Exit status */ 71main(void) 72{ 73 http_t *http; /* Connection to the server */ 74 const char *op; /* Operation name */ 75 76 77 /* 78 * Connect to the HTTP server... 79 */ 80 81 fputs("DEBUG: admin.cgi started...\n", stderr); 82 83 http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); 84 85 if (!http) 86 { 87 perror("ERROR: Unable to connect to cupsd"); 88 fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n", 89 cupsServer() ? cupsServer() : "(null)"); 90 fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort()); 91 fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption()); 92 exit(1); 93 } 94 95 fprintf(stderr, "DEBUG: http=%p\n", http); 96 97 /* 98 * Set the web interface section... 99 */ 100 101 cgiSetVariable("SECTION", "admin"); 102 cgiSetVariable("REFRESH_PAGE", ""); 103 104 /* 105 * See if we have form data... 106 */ 107 108 if (!cgiInitialize() || !cgiGetVariable("OP")) 109 { 110 /* 111 * Nope, send the administration menu... 112 */ 113 114 fputs("DEBUG: No form data, showing main menu...\n", stderr); 115 116 do_menu(http); 117 } 118 else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST()) 119 { 120 /* 121 * Do the operation... 122 */ 123 124 fprintf(stderr, "DEBUG: op=\"%s\"...\n", op); 125 126 if (!*op) 127 { 128 const char *printer = getenv("PRINTER_NAME"), 129 /* Printer or class name */ 130 *server_port = getenv("SERVER_PORT"); 131 /* Port number string */ 132 int port = atoi(server_port ? server_port : "0"); 133 /* Port number */ 134 char uri[1024]; /* URL */ 135 136 if (printer) 137 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), 138 getenv("HTTPS") ? "https" : "http", NULL, 139 getenv("SERVER_NAME"), port, "/%s/%s", 140 cgiGetVariable("IS_CLASS") ? "classes" : "printers", 141 printer); 142 else 143 httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), 144 getenv("HTTPS") ? "https" : "http", NULL, 145 getenv("SERVER_NAME"), port, "/admin"); 146 147 printf("Location: %s\n\n", uri); 148 } 149 else if (!strcmp(op, "set-allowed-users")) 150 do_set_allowed_users(http); 151 else if (!strcmp(op, "set-as-default")) 152 do_set_default(http); 153 else if (!strcmp(op, "set-sharing")) 154 do_set_sharing(http); 155 else if (!strcmp(op, "find-new-printers") || 156 !strcmp(op, "list-available-printers")) 157 do_list_printers(http); 158 else if (!strcmp(op, "add-class")) 159 do_am_class(http, 0); 160 else if (!strcmp(op, "add-printer")) 161 do_am_printer(http, 0); 162 else if (!strcmp(op, "modify-class")) 163 do_am_class(http, 1); 164 else if (!strcmp(op, "modify-printer")) 165 do_am_printer(http, 1); 166 else if (!strcmp(op, "delete-class")) 167 do_delete_class(http); 168 else if (!strcmp(op, "delete-printer")) 169 do_delete_printer(http); 170 else if (!strcmp(op, "set-class-options")) 171 do_set_options(http, 1); 172 else if (!strcmp(op, "set-printer-options")) 173 do_set_options(http, 0); 174 else if (!strcmp(op, "config-server")) 175 do_config_server(http); 176 else if (!strcmp(op, "export-samba")) 177 do_export(http); 178 else if (!strcmp(op, "add-rss-subscription")) 179 do_add_rss_subscription(http); 180 else if (!strcmp(op, "cancel-subscription")) 181 do_cancel_subscription(http); 182 else 183 { 184 /* 185 * Bad operation code - display an error... 186 */ 187 188 cgiStartHTML(cgiText(_("Administration"))); 189 cgiCopyTemplateLang("error-op.tmpl"); 190 cgiEndHTML(); 191 } 192 } 193 else if (op && !strcmp(op, "redirect")) 194 { 195 const char *url; /* Redirection URL... */ 196 char prefix[1024]; /* URL prefix */ 197 198 199 if (getenv("HTTPS")) 200 snprintf(prefix, sizeof(prefix), "https://%s:%s", 201 getenv("SERVER_NAME"), getenv("SERVER_PORT")); 202 else 203 snprintf(prefix, sizeof(prefix), "http://%s:%s", 204 getenv("SERVER_NAME"), getenv("SERVER_PORT")); 205 206 fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix); 207 208 if ((url = cgiGetVariable("URL")) != NULL) 209 { 210 char encoded[1024], /* Encoded URL string */ 211 *ptr; /* Pointer into encoded string */ 212 213 214 ptr = encoded; 215 if (*url != '/') 216 *ptr++ = '/'; 217 218 for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++) 219 { 220 if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128) 221 { 222 /* 223 * Percent-encode this character; safe because we have at least 4 224 * bytes left in the array... 225 */ 226 227 sprintf(ptr, "%%%02X", *url & 255); 228 ptr += 3; 229 } 230 else 231 *ptr++ = *url; 232 } 233 234 *ptr = '\0'; 235 236 if (*url) 237 { 238 /* 239 * URL was too long, just redirect to the admin page... 240 */ 241 242 printf("Location: %s/admin\n\n", prefix); 243 } 244 else 245 { 246 /* 247 * URL is OK, redirect there... 248 */ 249 250 printf("Location: %s%s\n\n", prefix, encoded); 251 } 252 } 253 else 254 printf("Location: %s/admin\n\n", prefix); 255 } 256 else 257 { 258 /* 259 * Form data but no operation code - display an error... 260 */ 261 262 cgiStartHTML(cgiText(_("Administration"))); 263 cgiCopyTemplateLang("error-op.tmpl"); 264 cgiEndHTML(); 265 } 266 267 /* 268 * Close the HTTP server connection... 269 */ 270 271 httpClose(http); 272 273 /* 274 * Return with no errors... 275 */ 276 277 return (0); 278} 279 280 281/* 282 * 'choose_device_cb()' - Add a device to the device selection page. 283 */ 284 285static void 286choose_device_cb( 287 const char *device_class, /* I - Class */ 288 const char *device_id, /* I - 1284 device ID */ 289 const char *device_info, /* I - Description */ 290 const char *device_make_and_model, /* I - Make and model */ 291 const char *device_uri, /* I - Device URI */ 292 const char *device_location, /* I - Location */ 293 const char *title) /* I - Page title */ 294{ 295 /* 296 * For modern browsers, start a multi-part page so we can show that something 297 * is happening. Non-modern browsers just get everything at the end... 298 */ 299 300 if (current_device == 0 && cgiSupportsMultipart()) 301 { 302 cgiStartMultipart(); 303 cgiStartHTML(title); 304 cgiCopyTemplateLang("choose-device.tmpl"); 305 cgiEndHTML(); 306 fflush(stdout); 307 } 308 309 310 /* 311 * Add the device to the array... 312 */ 313 314 cgiSetArray("device_class", current_device, device_class); 315 cgiSetArray("device_id", current_device, device_id); 316 cgiSetArray("device_info", current_device, device_info); 317 cgiSetArray("device_make_and_model", current_device, device_make_and_model); 318 cgiSetArray("device_uri", current_device, device_uri); 319 cgiSetArray("device_location", current_device, device_location); 320 321 current_device ++; 322} 323 324 325/* 326 * 'do_add_rss_subscription()' - Add a RSS subscription. 327 */ 328 329static void 330do_add_rss_subscription(http_t *http) /* I - HTTP connection */ 331{ 332 ipp_t *request, /* IPP request data */ 333 *response; /* IPP response data */ 334 char rss_uri[1024]; /* RSS notify-recipient URI */ 335 int num_events; /* Number of events */ 336 const char *events[12], /* Subscribed events */ 337 *subscription_name, /* Subscription name */ 338 *printer_uri, /* Printer URI */ 339 *ptr, /* Pointer into name */ 340 *user; /* Username */ 341 int max_events; /* Maximum number of events */ 342 343 344 /* 345 * See if we have all of the required information... 346 */ 347 348 subscription_name = cgiGetVariable("SUBSCRIPTION_NAME"); 349 printer_uri = cgiGetVariable("PRINTER_URI"); 350 num_events = 0; 351 352 if (cgiGetVariable("EVENT_JOB_CREATED")) 353 events[num_events ++] = "job-created"; 354 if (cgiGetVariable("EVENT_JOB_COMPLETED")) 355 events[num_events ++] = "job-completed"; 356 if (cgiGetVariable("EVENT_JOB_STOPPED")) 357 events[num_events ++] = "job-stopped"; 358 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED")) 359 events[num_events ++] = "job-config-changed"; 360 if (cgiGetVariable("EVENT_PRINTER_STOPPED")) 361 events[num_events ++] = "printer-stopped"; 362 if (cgiGetVariable("EVENT_PRINTER_ADDED")) 363 events[num_events ++] = "printer-added"; 364 if (cgiGetVariable("EVENT_PRINTER_MODIFIED")) 365 events[num_events ++] = "printer-modified"; 366 if (cgiGetVariable("EVENT_PRINTER_DELETED")) 367 events[num_events ++] = "printer-deleted"; 368 if (cgiGetVariable("EVENT_SERVER_STARTED")) 369 events[num_events ++] = "server-started"; 370 if (cgiGetVariable("EVENT_SERVER_STOPPED")) 371 events[num_events ++] = "server-stopped"; 372 if (cgiGetVariable("EVENT_SERVER_RESTARTED")) 373 events[num_events ++] = "server-restarted"; 374 if (cgiGetVariable("EVENT_SERVER_AUDIT")) 375 events[num_events ++] = "server-audit"; 376 377 if ((ptr = cgiGetVariable("MAX_EVENTS")) != NULL) 378 max_events = atoi(ptr); 379 else 380 max_events = 0; 381 382 if (!subscription_name || !printer_uri || !num_events || 383 max_events <= 0 || max_events > 9999) 384 { 385 /* 386 * Don't have everything we need, so get the available printers 387 * and classes and (re)show the add page... 388 */ 389 390 if (cgiGetVariable("EVENT_JOB_CREATED")) 391 cgiSetVariable("EVENT_JOB_CREATED", "CHECKED"); 392 if (cgiGetVariable("EVENT_JOB_COMPLETED")) 393 cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED"); 394 if (cgiGetVariable("EVENT_JOB_STOPPED")) 395 cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED"); 396 if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED")) 397 cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED"); 398 if (cgiGetVariable("EVENT_PRINTER_STOPPED")) 399 cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED"); 400 if (cgiGetVariable("EVENT_PRINTER_ADDED")) 401 cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED"); 402 if (cgiGetVariable("EVENT_PRINTER_MODIFIED")) 403 cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED"); 404 if (cgiGetVariable("EVENT_PRINTER_DELETED")) 405 cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED"); 406 if (cgiGetVariable("EVENT_SERVER_STARTED")) 407 cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED"); 408 if (cgiGetVariable("EVENT_SERVER_STOPPED")) 409 cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED"); 410 if (cgiGetVariable("EVENT_SERVER_RESTARTED")) 411 cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED"); 412 if (cgiGetVariable("EVENT_SERVER_AUDIT")) 413 cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED"); 414 415 request = ippNewRequest(CUPS_GET_PRINTERS); 416 response = cupsDoRequest(http, request, "/"); 417 418 cgiSetIPPVars(response, NULL, NULL, NULL, 0); 419 420 ippDelete(response); 421 422 cgiStartHTML(cgiText(_("Add RSS Subscription"))); 423 424 cgiCopyTemplateLang("add-rss-subscription.tmpl"); 425 426 cgiEndHTML(); 427 return; 428 } 429 430 /* 431 * Make sure we have a username... 432 */ 433 434 if ((user = getenv("REMOTE_USER")) == NULL) 435 { 436 puts("Status: 401\n"); 437 exit(0); 438 } 439 440 /* 441 * Validate the subscription name... 442 */ 443 444 for (ptr = subscription_name; *ptr; ptr ++) 445 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || 446 *ptr == '?' || *ptr == '#') 447 break; 448 449 if (*ptr) 450 { 451 cgiSetVariable("ERROR", 452 cgiText(_("The subscription name may not " 453 "contain spaces, slashes (/), question marks (?), " 454 "or the pound sign (#)."))); 455 cgiStartHTML(_("Add RSS Subscription")); 456 cgiCopyTemplateLang("error.tmpl"); 457 cgiEndHTML(); 458 return; 459 } 460 461 /* 462 * Add the subscription... 463 */ 464 465 ptr = subscription_name + strlen(subscription_name) - 4; 466 if (ptr < subscription_name || strcmp(ptr, ".rss")) 467 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss", 468 NULL, NULL, 0, "/%s.rss?max_events=%d", subscription_name, 469 max_events); 470 else 471 httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss", 472 NULL, NULL, 0, "/%s?max_events=%d", subscription_name, 473 max_events); 474 475 request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION); 476 477 if (!_cups_strcasecmp(printer_uri, "#ALL#")) 478 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 479 NULL, "ipp://localhost/"); 480 else 481 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 482 NULL, printer_uri); 483 484 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 485 NULL, user); 486 487 ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, 488 "notify-recipient-uri", NULL, rss_uri); 489 ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events", 490 num_events, NULL, events); 491 ippAddInteger(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, 492 "notify-lease-duration", 0); 493 494 ippDelete(cupsDoRequest(http, request, "/")); 495 496 if (cupsLastError() == IPP_NOT_AUTHORIZED) 497 { 498 puts("Status: 401\n"); 499 exit(0); 500 } 501 else if (cupsLastError() > IPP_OK_CONFLICT) 502 { 503 cgiStartHTML(_("Add RSS Subscription")); 504 cgiShowIPPError(_("Unable to add RSS subscription")); 505 } 506 else 507 { 508 /* 509 * Redirect successful updates back to the admin page... 510 */ 511 512 cgiSetVariable("refresh_page", "5;URL=/admin"); 513 cgiStartHTML(_("Add RSS Subscription")); 514 cgiCopyTemplateLang("subscription-added.tmpl"); 515 } 516 517 cgiEndHTML(); 518} 519 520 521/* 522 * 'do_am_class()' - Add or modify a class. 523 */ 524 525static void 526do_am_class(http_t *http, /* I - HTTP connection */ 527 int modify) /* I - Modify the printer? */ 528{ 529 int i, j; /* Looping vars */ 530 int element; /* Element number */ 531 int num_printers; /* Number of printers */ 532 ipp_t *request, /* IPP request */ 533 *response; /* IPP response */ 534 ipp_attribute_t *attr; /* member-uris attribute */ 535 char uri[HTTP_MAX_URI]; /* Device or printer URI */ 536 const char *name, /* Pointer to class name */ 537 *op, /* Operation name */ 538 *ptr; /* Pointer to CGI variable */ 539 const char *title; /* Title of page */ 540 static const char * const pattrs[] = /* Requested printer attributes */ 541 { 542 "member-names", 543 "printer-info", 544 "printer-location" 545 }; 546 547 548 title = cgiText(modify ? _("Modify Class") : _("Add Class")); 549 op = cgiGetVariable("OP"); 550 name = cgiGetVariable("PRINTER_NAME"); 551 552 if (cgiGetVariable("PRINTER_LOCATION") == NULL) 553 { 554 /* 555 * Build a CUPS_GET_PRINTERS request, which requires the 556 * following attributes: 557 * 558 * attributes-charset 559 * attributes-natural-language 560 */ 561 562 request = ippNewRequest(CUPS_GET_PRINTERS); 563 564 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", 565 CUPS_PRINTER_LOCAL); 566 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", 567 CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); 568 569 /* 570 * Do the request and get back a response... 571 */ 572 573 cgiClearVariables(); 574 if (op) 575 cgiSetVariable("OP", op); 576 if (name) 577 cgiSetVariable("PRINTER_NAME", name); 578 579 if ((response = cupsDoRequest(http, request, "/")) != NULL) 580 { 581 /* 582 * Create MEMBER_URIS and MEMBER_NAMES arrays... 583 */ 584 585 for (element = 0, attr = response->attrs; 586 attr != NULL; 587 attr = attr->next) 588 if (attr->name && !strcmp(attr->name, "printer-uri-supported")) 589 { 590 if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL && 591 (!name || _cups_strcasecmp(name, ptr + 1))) 592 { 593 /* 594 * Don't show the current class... 595 */ 596 597 cgiSetArray("MEMBER_URIS", element, attr->values[0].string.text); 598 element ++; 599 } 600 } 601 602 for (element = 0, attr = response->attrs; 603 attr != NULL; 604 attr = attr->next) 605 if (attr->name && !strcmp(attr->name, "printer-name")) 606 { 607 if (!name || _cups_strcasecmp(name, attr->values[0].string.text)) 608 { 609 /* 610 * Don't show the current class... 611 */ 612 613 cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text); 614 element ++; 615 } 616 } 617 618 num_printers = cgiGetSize("MEMBER_URIS"); 619 620 ippDelete(response); 621 } 622 else 623 num_printers = 0; 624 625 if (modify) 626 { 627 /* 628 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the 629 * following attributes: 630 * 631 * attributes-charset 632 * attributes-natural-language 633 * printer-uri 634 */ 635 636 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 637 638 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 639 "localhost", 0, "/classes/%s", name); 640 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 641 NULL, uri); 642 643 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 644 "requested-attributes", 645 (int)(sizeof(pattrs) / sizeof(pattrs[0])), 646 NULL, pattrs); 647 648 /* 649 * Do the request and get back a response... 650 */ 651 652 if ((response = cupsDoRequest(http, request, "/")) != NULL) 653 { 654 if ((attr = ippFindAttribute(response, "member-names", 655 IPP_TAG_NAME)) != NULL) 656 { 657 /* 658 * Mark any current members in the class... 659 */ 660 661 for (j = 0; j < num_printers; j ++) 662 cgiSetArray("MEMBER_SELECTED", j, ""); 663 664 for (i = 0; i < attr->num_values; i ++) 665 { 666 for (j = 0; j < num_printers; j ++) 667 { 668 if (!_cups_strcasecmp(attr->values[i].string.text, 669 cgiGetArray("MEMBER_NAMES", j))) 670 { 671 cgiSetArray("MEMBER_SELECTED", j, "SELECTED"); 672 break; 673 } 674 } 675 } 676 } 677 678 if ((attr = ippFindAttribute(response, "printer-info", 679 IPP_TAG_TEXT)) != NULL) 680 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text); 681 682 if ((attr = ippFindAttribute(response, "printer-location", 683 IPP_TAG_TEXT)) != NULL) 684 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text); 685 686 ippDelete(response); 687 } 688 689 /* 690 * Update the location and description of an existing printer... 691 */ 692 693 cgiStartHTML(title); 694 cgiCopyTemplateLang("modify-class.tmpl"); 695 } 696 else 697 { 698 /* 699 * Get the name, location, and description for a new printer... 700 */ 701 702 cgiStartHTML(title); 703 cgiCopyTemplateLang("add-class.tmpl"); 704 } 705 706 cgiEndHTML(); 707 708 return; 709 } 710 711 if (!name) 712 { 713 cgiStartHTML(title); 714 cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); 715 cgiCopyTemplateLang("error.tmpl"); 716 cgiEndHTML(); 717 return; 718 } 719 720 for (ptr = name; *ptr; ptr ++) 721 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') 722 break; 723 724 if (*ptr || ptr == name || strlen(name) > 127) 725 { 726 cgiSetVariable("ERROR", 727 cgiText(_("The class name may only contain up to " 728 "127 printable characters and may not " 729 "contain spaces, slashes (/), or the " 730 "pound sign (#)."))); 731 cgiStartHTML(title); 732 cgiCopyTemplateLang("error.tmpl"); 733 cgiEndHTML(); 734 return; 735 } 736 737 /* 738 * Build a CUPS_ADD_CLASS request, which requires the following 739 * attributes: 740 * 741 * attributes-charset 742 * attributes-natural-language 743 * printer-uri 744 * printer-location 745 * printer-info 746 * printer-is-accepting-jobs 747 * printer-state 748 * member-uris 749 */ 750 751 request = ippNewRequest(CUPS_ADD_CLASS); 752 753 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 754 "localhost", 0, "/classes/%s", name); 755 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 756 NULL, uri); 757 758 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", 759 NULL, cgiGetVariable("PRINTER_LOCATION")); 760 761 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", 762 NULL, cgiGetVariable("PRINTER_INFO")); 763 764 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); 765 766 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", 767 IPP_PRINTER_IDLE); 768 769 if ((num_printers = cgiGetSize("MEMBER_URIS")) > 0) 770 { 771 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", 772 num_printers, NULL, NULL); 773 for (i = 0; i < num_printers; i ++) 774 attr->values[i].string.text = _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i)); 775 } 776 777 /* 778 * Do the request and get back a response... 779 */ 780 781 ippDelete(cupsDoRequest(http, request, "/admin/")); 782 783 if (cupsLastError() == IPP_NOT_AUTHORIZED) 784 { 785 puts("Status: 401\n"); 786 exit(0); 787 } 788 else if (cupsLastError() > IPP_OK_CONFLICT) 789 { 790 cgiStartHTML(title); 791 cgiShowIPPError(modify ? _("Unable to modify class") : 792 _("Unable to add class")); 793 } 794 else 795 { 796 /* 797 * Redirect successful updates back to the class page... 798 */ 799 800 char refresh[1024]; /* Refresh URL */ 801 802 cgiFormEncode(uri, name, sizeof(uri)); 803 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s", 804 uri); 805 cgiSetVariable("refresh_page", refresh); 806 807 cgiStartHTML(title); 808 809 if (modify) 810 cgiCopyTemplateLang("class-modified.tmpl"); 811 else 812 cgiCopyTemplateLang("class-added.tmpl"); 813 } 814 815 cgiEndHTML(); 816} 817 818 819/* 820 * 'do_am_printer()' - Add or modify a printer. 821 */ 822 823static void 824do_am_printer(http_t *http, /* I - HTTP connection */ 825 int modify) /* I - Modify the printer? */ 826{ 827 int i; /* Looping var */ 828 ipp_attribute_t *attr; /* Current attribute */ 829 ipp_t *request, /* IPP request */ 830 *response, /* IPP response */ 831 *oldinfo; /* Old printer information */ 832 const cgi_file_t *file; /* Uploaded file, if any */ 833 const char *var; /* CGI variable */ 834 char uri[HTTP_MAX_URI], /* Device or printer URI */ 835 *uriptr; /* Pointer into URI */ 836 int maxrate; /* Maximum baud rate */ 837 char baudrate[255]; /* Baud rate string */ 838 const char *name, /* Pointer to class name */ 839 *ptr; /* Pointer to CGI variable */ 840 const char *title; /* Title of page */ 841 static int baudrates[] = /* Baud rates */ 842 { 843 1200, 844 2400, 845 4800, 846 9600, 847 19200, 848 38400, 849 57600, 850 115200, 851 230400, 852 460800 853 }; 854 855 856 ptr = cgiGetVariable("DEVICE_URI"); 857 fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n", 858 ptr ? ptr : "(null)"); 859 860 title = cgiText(modify ? _("Modify Printer") : _("Add Printer")); 861 862 if (modify) 863 { 864 /* 865 * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the 866 * following attributes: 867 * 868 * attributes-charset 869 * attributes-natural-language 870 * printer-uri 871 */ 872 873 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 874 875 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 876 "localhost", 0, "/printers/%s", 877 cgiGetVariable("PRINTER_NAME")); 878 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 879 NULL, uri); 880 881 /* 882 * Do the request and get back a response... 883 */ 884 885 oldinfo = cupsDoRequest(http, request, "/"); 886 } 887 else 888 oldinfo = NULL; 889 890 file = cgiGetFile(); 891 892 if (file) 893 { 894 fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile); 895 fprintf(stderr, "DEBUG: file->name=%s\n", file->name); 896 fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename); 897 fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype); 898 } 899 900 if ((name = cgiGetVariable("PRINTER_NAME")) != NULL) 901 { 902 for (ptr = name; *ptr; ptr ++) 903 if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') 904 break; 905 906 if (*ptr || ptr == name || strlen(name) > 127) 907 { 908 cgiSetVariable("ERROR", 909 cgiText(_("The printer name may only contain up to " 910 "127 printable characters and may not " 911 "contain spaces, slashes (/), or the " 912 "pound sign (#)."))); 913 cgiStartHTML(title); 914 cgiCopyTemplateLang("error.tmpl"); 915 cgiEndHTML(); 916 return; 917 } 918 } 919 920 if ((var = cgiGetVariable("DEVICE_URI")) != NULL) 921 { 922 if ((uriptr = strrchr(var, '|')) != NULL) 923 { 924 /* 925 * Extract make and make/model from device URI string... 926 */ 927 928 char make[1024], /* Make string */ 929 *makeptr; /* Pointer into make */ 930 931 932 *uriptr++ = '\0'; 933 934 strlcpy(make, uriptr, sizeof(make)); 935 936 if ((makeptr = strchr(make, ' ')) != NULL) 937 *makeptr = '\0'; 938 else if ((makeptr = strchr(make, '-')) != NULL) 939 *makeptr = '\0'; 940 else if (!_cups_strncasecmp(make, "laserjet", 8) || 941 !_cups_strncasecmp(make, "deskjet", 7) || 942 !_cups_strncasecmp(make, "designjet", 9)) 943 strlcpy(make, "HP", sizeof(make)); 944 else if (!_cups_strncasecmp(make, "phaser", 6)) 945 strlcpy(make, "Xerox", sizeof(make)); 946 else if (!_cups_strncasecmp(make, "stylus", 6)) 947 strlcpy(make, "Epson", sizeof(make)); 948 else 949 strlcpy(make, "Generic", sizeof(make)); 950 951 if (!cgiGetVariable("CURRENT_MAKE")) 952 cgiSetVariable("CURRENT_MAKE", make); 953 954 if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL")) 955 cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr); 956 957 if (!modify) 958 { 959 char template[128], /* Template name */ 960 *tptr; /* Pointer into template name */ 961 962 cgiSetVariable("PRINTER_INFO", uriptr); 963 964 for (tptr = template; 965 tptr < (template + sizeof(template) - 1) && *uriptr; 966 uriptr ++) 967 if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' || 968 *uriptr == '.') 969 *tptr++ = *uriptr; 970 else if ((*uriptr == ' ' || *uriptr == '/') && tptr > template && 971 tptr[-1] != '_') 972 *tptr++ = '_'; 973 else if (*uriptr == '?' || *uriptr == '(') 974 break; 975 976 *tptr = '\0'; 977 978 cgiSetVariable("TEMPLATE_NAME", template); 979 } 980 } 981 } 982 983 if (!var) 984 { 985 /* 986 * Look for devices so the user can pick something... 987 */ 988 989 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) 990 { 991 strlcpy(uri, attr->values[0].string.text, sizeof(uri)); 992 if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0) 993 *uriptr = '\0'; 994 995 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); 996 cgiSetVariable("CURRENT_DEVICE_SCHEME", uri); 997 } 998 999 /* 1000 * Scan for devices for up to 30 seconds... 1001 */ 1002 1003 fputs("DEBUG: Getting list of devices...\n", stderr); 1004 1005 current_device = 0; 1006 if (cupsGetDevices(http, 5, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE, 1007 (cups_device_cb_t)choose_device_cb, 1008 (void *)title) == IPP_OK) 1009 { 1010 fputs("DEBUG: Got device list!\n", stderr); 1011 1012 if (cgiSupportsMultipart()) 1013 cgiStartMultipart(); 1014 1015 cgiSetVariable("CUPS_GET_DEVICES_DONE", "1"); 1016 cgiStartHTML(title); 1017 cgiCopyTemplateLang("choose-device.tmpl"); 1018 cgiEndHTML(); 1019 1020 if (cgiSupportsMultipart()) 1021 cgiEndMultipart(); 1022 } 1023 else 1024 { 1025 fprintf(stderr, 1026 "ERROR: CUPS-Get-Devices request failed with status %x: %s\n", 1027 cupsLastError(), cupsLastErrorString()); 1028 if (cupsLastError() == IPP_NOT_AUTHORIZED) 1029 { 1030 puts("Status: 401\n"); 1031 exit(0); 1032 } 1033 else 1034 { 1035 cgiStartHTML(title); 1036 cgiShowIPPError(modify ? _("Unable to modify printer") : 1037 _("Unable to add printer")); 1038 cgiEndHTML(); 1039 return; 1040 } 1041 } 1042 } 1043 else if (!strchr(var, '/') || 1044 (!strncmp(var, "lpd://", 6) && !strchr(var + 6, '/'))) 1045 { 1046 if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) 1047 { 1048 /* 1049 * Set the current device URI for the form to the old one... 1050 */ 1051 1052 if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0) 1053 cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); 1054 } 1055 1056 /* 1057 * User needs to set the full URI... 1058 */ 1059 1060 cgiStartHTML(title); 1061 cgiCopyTemplateLang("choose-uri.tmpl"); 1062 cgiEndHTML(); 1063 } 1064 else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE")) 1065 { 1066 /* 1067 * Need baud rate, parity, etc. 1068 */ 1069 1070 if ((var = strchr(var, '?')) != NULL && 1071 strncmp(var, "?baud=", 6) == 0) 1072 maxrate = atoi(var + 6); 1073 else 1074 maxrate = 19200; 1075 1076 for (i = 0; i < 10; i ++) 1077 if (baudrates[i] > maxrate) 1078 break; 1079 else 1080 { 1081 sprintf(baudrate, "%d", baudrates[i]); 1082 cgiSetArray("BAUDRATES", i, baudrate); 1083 } 1084 1085 cgiStartHTML(title); 1086 cgiCopyTemplateLang("choose-serial.tmpl"); 1087 cgiEndHTML(); 1088 } 1089 else if (!name || !cgiGetVariable("PRINTER_LOCATION")) 1090 { 1091 cgiStartHTML(title); 1092 1093 if (modify) 1094 { 1095 /* 1096 * Update the location and description of an existing printer... 1097 */ 1098 1099 if (oldinfo) 1100 { 1101 if ((attr = ippFindAttribute(oldinfo, "printer-info", 1102 IPP_TAG_TEXT)) != NULL) 1103 cgiSetVariable("PRINTER_INFO", attr->values[0].string.text); 1104 1105 if ((attr = ippFindAttribute(oldinfo, "printer-location", 1106 IPP_TAG_TEXT)) != NULL) 1107 cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text); 1108 1109 if ((attr = ippFindAttribute(oldinfo, "printer-is-shared", 1110 IPP_TAG_BOOLEAN)) != NULL) 1111 cgiSetVariable("PRINTER_IS_SHARED", 1112 attr->values[0].boolean ? "1" : "0"); 1113 } 1114 1115 cgiCopyTemplateLang("modify-printer.tmpl"); 1116 } 1117 else 1118 { 1119 /* 1120 * Get the name, location, and description for a new printer... 1121 */ 1122 1123#ifdef __APPLE__ 1124 if (!strncmp(var, "usb:", 4)) 1125 cgiSetVariable("printer_is_shared", "1"); 1126 else 1127#endif /* __APPLE__ */ 1128 cgiSetVariable("printer_is_shared", "0"); 1129 1130 cgiCopyTemplateLang("add-printer.tmpl"); 1131 } 1132 1133 cgiEndHTML(); 1134 1135 if (oldinfo) 1136 ippDelete(oldinfo); 1137 1138 return; 1139 } 1140 else if (!file && 1141 (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE"))) 1142 { 1143 if (modify && !cgiGetVariable("SELECT_MAKE")) 1144 { 1145 /* 1146 * Get the PPD file... 1147 */ 1148 1149 int fd; /* PPD file */ 1150 char filename[1024]; /* PPD filename */ 1151 ppd_file_t *ppd; /* PPD information */ 1152 char buffer[1024]; /* Buffer */ 1153 ssize_t bytes; /* Number of bytes */ 1154 http_status_t get_status; /* Status of GET */ 1155 1156 1157 /* TODO: Use cupsGetFile() API... */ 1158 snprintf(uri, sizeof(uri), "/printers/%s.ppd", name); 1159 1160 if (httpGet(http, uri)) 1161 httpGet(http, uri); 1162 1163 while ((get_status = httpUpdate(http)) == HTTP_CONTINUE); 1164 1165 if (get_status != HTTP_OK) 1166 { 1167 httpFlush(http); 1168 1169 fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n", 1170 uri, get_status, httpStatus(get_status)); 1171 } 1172 else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0) 1173 { 1174 while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) 1175 write(fd, buffer, (size_t)bytes); 1176 1177 close(fd); 1178 1179 if ((ppd = ppdOpenFile(filename)) != NULL) 1180 { 1181 if (ppd->manufacturer) 1182 cgiSetVariable("CURRENT_MAKE", ppd->manufacturer); 1183 1184 if (ppd->nickname) 1185 cgiSetVariable("CURRENT_MAKE_AND_MODEL", ppd->nickname); 1186 1187 ppdClose(ppd); 1188 unlink(filename); 1189 } 1190 else 1191 { 1192 int linenum; /* Line number */ 1193 1194 fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n", 1195 filename, ppdErrorString(ppdLastError(&linenum))); 1196 } 1197 } 1198 else 1199 { 1200 httpFlush(http); 1201 1202 fprintf(stderr, 1203 "ERROR: Unable to create temporary file for PPD file: %s\n", 1204 strerror(errno)); 1205 } 1206 } 1207 1208 /* 1209 * Build a CUPS_GET_PPDS request, which requires the following 1210 * attributes: 1211 * 1212 * attributes-charset 1213 * attributes-natural-language 1214 * printer-uri 1215 */ 1216 1217 request = ippNewRequest(CUPS_GET_PPDS); 1218 1219 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 1220 NULL, "ipp://localhost/printers/"); 1221 1222 if ((var = cgiGetVariable("PPD_MAKE")) == NULL) 1223 var = cgiGetVariable("CURRENT_MAKE"); 1224 if (var && !cgiGetVariable("SELECT_MAKE")) 1225 { 1226 const char *make_model; /* Make and model */ 1227 1228 1229 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, 1230 "ppd-make", NULL, var); 1231 1232 if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL) 1233 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, 1234 "ppd-make-and-model", NULL, make_model); 1235 } 1236 else 1237 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1238 "requested-attributes", NULL, "ppd-make"); 1239 1240 /* 1241 * Do the request and get back a response... 1242 */ 1243 1244 if ((response = cupsDoRequest(http, request, "/")) != NULL) 1245 { 1246 /* 1247 * Got the list of PPDs, see if the user has selected a make... 1248 */ 1249 1250 if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify) 1251 { 1252 /* 1253 * No PPD files with this make, try again with all makes... 1254 */ 1255 1256 ippDelete(response); 1257 1258 request = ippNewRequest(CUPS_GET_PPDS); 1259 1260 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 1261 NULL, "ipp://localhost/printers/"); 1262 1263 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 1264 "requested-attributes", NULL, "ppd-make"); 1265 1266 if ((response = cupsDoRequest(http, request, "/")) != NULL) 1267 cgiSetIPPVars(response, NULL, NULL, NULL, 0); 1268 1269 cgiStartHTML(title); 1270 cgiCopyTemplateLang("choose-make.tmpl"); 1271 cgiEndHTML(); 1272 } 1273 else if (!var || cgiGetVariable("SELECT_MAKE")) 1274 { 1275 cgiStartHTML(title); 1276 cgiCopyTemplateLang("choose-make.tmpl"); 1277 cgiEndHTML(); 1278 } 1279 else 1280 { 1281 /* 1282 * Let the user choose a model... 1283 */ 1284 1285 cgiStartHTML(title); 1286 if (!cgiGetVariable("PPD_MAKE")) 1287 cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE")); 1288 if (!modify) 1289 cgiSetVariable("CURRENT_MAKE_AND_MODEL", 1290 cgiGetArray("PPD_MAKE_AND_MODEL", 0)); 1291 cgiCopyTemplateLang("choose-model.tmpl"); 1292 cgiEndHTML(); 1293 } 1294 1295 ippDelete(response); 1296 } 1297 else 1298 { 1299 cgiStartHTML(title); 1300 cgiShowIPPError(_("Unable to get list of printer drivers")); 1301 cgiCopyTemplateLang("error.tmpl"); 1302 cgiEndHTML(); 1303 } 1304 } 1305 else 1306 { 1307 /* 1308 * Build a CUPS_ADD_PRINTER request, which requires the following 1309 * attributes: 1310 * 1311 * attributes-charset 1312 * attributes-natural-language 1313 * printer-uri 1314 * printer-location 1315 * printer-info 1316 * ppd-name 1317 * device-uri 1318 * printer-is-accepting-jobs 1319 * printer-is-shared 1320 * printer-state 1321 */ 1322 1323 request = ippNewRequest(CUPS_ADD_PRINTER); 1324 1325 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 1326 "localhost", 0, "/printers/%s", 1327 cgiGetVariable("PRINTER_NAME")); 1328 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 1329 NULL, uri); 1330 1331 if (!file) 1332 { 1333 var = cgiGetVariable("PPD_NAME"); 1334 if (strcmp(var, "__no_change__")) 1335 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", 1336 NULL, var); 1337 } 1338 1339 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", 1340 NULL, cgiGetVariable("PRINTER_LOCATION")); 1341 1342 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", 1343 NULL, cgiGetVariable("PRINTER_INFO")); 1344 1345 strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri)); 1346 1347 /* 1348 * Strip make and model from URI... 1349 */ 1350 1351 if ((uriptr = strrchr(uri, '|')) != NULL) 1352 *uriptr = '\0'; 1353 1354 if (!strncmp(uri, "serial:", 7)) 1355 { 1356 /* 1357 * Update serial port URI to include baud rate, etc. 1358 */ 1359 1360 if ((uriptr = strchr(uri, '?')) == NULL) 1361 uriptr = uri + strlen(uri); 1362 1363 snprintf(uriptr, sizeof(uri) - (size_t)(uriptr - uri), 1364 "?baud=%s+bits=%s+parity=%s+flow=%s", 1365 cgiGetVariable("BAUDRATE"), cgiGetVariable("BITS"), 1366 cgiGetVariable("PARITY"), cgiGetVariable("FLOW")); 1367 } 1368 1369 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", 1370 NULL, uri); 1371 1372 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); 1373 1374 var = cgiGetVariable("printer_is_shared"); 1375 ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared", 1376 var && (!strcmp(var, "1") || !strcmp(var, "on"))); 1377 1378 ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", 1379 IPP_PRINTER_IDLE); 1380 1381 /* 1382 * Do the request and get back a response... 1383 */ 1384 1385 if (file) 1386 ippDelete(cupsDoFileRequest(http, request, "/admin/", file->tempfile)); 1387 else 1388 ippDelete(cupsDoRequest(http, request, "/admin/")); 1389 1390 if (cupsLastError() == IPP_NOT_AUTHORIZED) 1391 { 1392 puts("Status: 401\n"); 1393 exit(0); 1394 } 1395 else if (cupsLastError() > IPP_OK_CONFLICT) 1396 { 1397 cgiStartHTML(title); 1398 cgiShowIPPError(modify ? _("Unable to modify printer") : 1399 _("Unable to add printer")); 1400 } 1401 else if (modify) 1402 { 1403 /* 1404 * Redirect successful updates back to the printer page... 1405 */ 1406 1407 char refresh[1024]; /* Refresh URL */ 1408 1409 1410 cgiFormEncode(uri, name, sizeof(uri)); 1411 1412 snprintf(refresh, sizeof(refresh), 1413 "5;/admin/?OP=redirect&URL=/printers/%s", uri); 1414 1415 cgiSetVariable("refresh_page", refresh); 1416 1417 cgiStartHTML(title); 1418 1419 cgiCopyTemplateLang("printer-modified.tmpl"); 1420 } 1421 else 1422 { 1423 /* 1424 * Set the printer options... 1425 */ 1426 1427 cgiSetVariable("OP", "set-printer-options"); 1428 do_set_options(http, 0); 1429 return; 1430 } 1431 1432 cgiEndHTML(); 1433 } 1434 1435 if (oldinfo) 1436 ippDelete(oldinfo); 1437} 1438 1439 1440/* 1441 * 'do_cancel_subscription()' - Cancel a subscription. 1442 */ 1443 1444static void 1445do_cancel_subscription(http_t *http)/* I - HTTP connection */ 1446{ 1447 ipp_t *request; /* IPP request data */ 1448 const char *var, /* Form variable */ 1449 *user; /* Username */ 1450 int id; /* Subscription ID */ 1451 1452 1453 /* 1454 * See if we have all of the required information... 1455 */ 1456 1457 if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL) 1458 id = atoi(var); 1459 else 1460 id = 0; 1461 1462 if (id <= 0) 1463 { 1464 cgiSetVariable("ERROR", cgiText(_("Bad subscription ID"))); 1465 cgiStartHTML(_("Cancel RSS Subscription")); 1466 cgiCopyTemplateLang("error.tmpl"); 1467 cgiEndHTML(); 1468 return; 1469 } 1470 1471 /* 1472 * Require a username... 1473 */ 1474 1475 if ((user = getenv("REMOTE_USER")) == NULL) 1476 { 1477 puts("Status: 401\n"); 1478 exit(0); 1479 } 1480 1481 /* 1482 * Cancel the subscription... 1483 */ 1484 1485 request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION); 1486 1487 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 1488 NULL, "ipp://localhost/"); 1489 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, 1490 "notify-subscription-id", id); 1491 1492 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", 1493 NULL, user); 1494 1495 ippDelete(cupsDoRequest(http, request, "/")); 1496 1497 if (cupsLastError() == IPP_NOT_AUTHORIZED) 1498 { 1499 puts("Status: 401\n"); 1500 exit(0); 1501 } 1502 else if (cupsLastError() > IPP_OK_CONFLICT) 1503 { 1504 cgiStartHTML(_("Cancel RSS Subscription")); 1505 cgiShowIPPError(_("Unable to cancel RSS subscription")); 1506 } 1507 else 1508 { 1509 /* 1510 * Redirect successful updates back to the admin page... 1511 */ 1512 1513 cgiSetVariable("refresh_page", "5;URL=/admin"); 1514 cgiStartHTML(_("Cancel RSS Subscription")); 1515 cgiCopyTemplateLang("subscription-canceled.tmpl"); 1516 } 1517 1518 cgiEndHTML(); 1519} 1520 1521 1522/* 1523 * 'do_config_server()' - Configure server settings. 1524 */ 1525 1526static void 1527do_config_server(http_t *http) /* I - HTTP connection */ 1528{ 1529 if (cgiGetVariable("CHANGESETTINGS")) 1530 { 1531 /* 1532 * Save basic setting changes... 1533 */ 1534 1535 int num_settings; /* Number of server settings */ 1536 cups_option_t *settings; /* Server settings */ 1537 int advanced, /* Advanced settings shown? */ 1538 changed; /* Have settings changed? */ 1539 const char *debug_logging, /* DEBUG_LOGGING value */ 1540 *preserve_jobs = NULL, 1541 /* PRESERVE_JOBS value */ 1542 *remote_admin, /* REMOTE_ADMIN value */ 1543 *remote_any, /* REMOTE_ANY value */ 1544 *share_printers,/* SHARE_PRINTERS value */ 1545 *user_cancel_any, 1546 /* USER_CANCEL_ANY value */ 1547 *browse_web_if = NULL, 1548 /* BrowseWebIF value */ 1549 *preserve_job_history = NULL, 1550 /* PreserveJobHistory value */ 1551 *preserve_job_files = NULL, 1552 /* PreserveJobFiles value */ 1553 *max_clients = NULL, 1554 /* MaxClients value */ 1555 *max_jobs = NULL, 1556 /* MaxJobs value */ 1557 *max_log_size = NULL; 1558 /* MaxLogSize value */ 1559 const char *current_browse_web_if, 1560 /* BrowseWebIF value */ 1561 *current_preserve_job_history, 1562 /* PreserveJobHistory value */ 1563 *current_preserve_job_files, 1564 /* PreserveJobFiles value */ 1565 *current_max_clients, 1566 /* MaxClients value */ 1567 *current_max_jobs, 1568 /* MaxJobs value */ 1569 *current_max_log_size; 1570 /* MaxLogSize value */ 1571#ifdef HAVE_GSSAPI 1572 char default_auth_type[255]; 1573 /* DefaultAuthType value */ 1574 const char *val; /* Setting value */ 1575#endif /* HAVE_GSSAPI */ 1576 1577 1578 /* 1579 * Get the checkbox values from the form... 1580 */ 1581 1582 debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0"; 1583 remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0"; 1584 remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0"; 1585 share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0"; 1586 user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0"; 1587 1588 advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL; 1589 if (advanced) 1590 { 1591 /* 1592 * Get advanced settings... 1593 */ 1594 1595 browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No"; 1596 max_clients = cgiGetVariable("MAX_CLIENTS"); 1597 max_log_size = cgiGetVariable("MAX_LOG_SIZE"); 1598 preserve_jobs = cgiGetVariable("PRESERVE_JOBS"); 1599 1600 if (preserve_jobs) 1601 { 1602 max_jobs = cgiGetVariable("MAX_JOBS"); 1603 preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY"); 1604 preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES"); 1605 1606 if (!max_jobs || atoi(max_jobs) < 0) 1607 max_jobs = "500"; 1608 1609 if (!preserve_job_history) 1610 preserve_job_history = "On"; 1611 1612 if (!preserve_job_files) 1613 preserve_job_files = "1d"; 1614 } 1615 else 1616 { 1617 max_jobs = "0"; 1618 preserve_job_history = "No"; 1619 preserve_job_files = "No"; 1620 } 1621 1622 if (!max_clients || atoi(max_clients) <= 0) 1623 max_clients = "100"; 1624 1625 if (!max_log_size || atoi(max_log_size) <= 0.0) 1626 max_log_size = "1m"; 1627 } 1628 1629 /* 1630 * Get the current server settings... 1631 */ 1632 1633 if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) 1634 { 1635 cgiStartHTML(cgiText(_("Change Settings"))); 1636 cgiSetVariable("MESSAGE", 1637 cgiText(_("Unable to change server settings"))); 1638 cgiSetVariable("ERROR", cupsLastErrorString()); 1639 cgiCopyTemplateLang("error.tmpl"); 1640 cgiEndHTML(); 1641 return; 1642 } 1643 1644#ifdef HAVE_GSSAPI 1645 /* 1646 * Get authentication settings... 1647 */ 1648 1649 if (cgiGetVariable("KERBEROS")) 1650 strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type)); 1651 else 1652 { 1653 val = cupsGetOption("DefaultAuthType", num_settings, settings); 1654 1655 if (!val || !_cups_strcasecmp(val, "Negotiate")) 1656 strlcpy(default_auth_type, "Basic", sizeof(default_auth_type)); 1657 else 1658 strlcpy(default_auth_type, val, sizeof(default_auth_type)); 1659 } 1660 1661 fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type); 1662#endif /* HAVE_GSSAPI */ 1663 1664 if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings, 1665 settings)) == NULL) 1666 current_browse_web_if = "No"; 1667 1668 if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory", 1669 num_settings, 1670 settings)) == NULL) 1671 current_preserve_job_history = "Yes"; 1672 1673 if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles", 1674 num_settings, 1675 settings)) == NULL) 1676 current_preserve_job_files = "1d"; 1677 1678 if ((current_max_clients = cupsGetOption("MaxClients", num_settings, 1679 settings)) == NULL) 1680 current_max_clients = "100"; 1681 1682 if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings, 1683 settings)) == NULL) 1684 current_max_jobs = "500"; 1685 1686 if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings, 1687 settings)) == NULL) 1688 current_max_log_size = "1m"; 1689 1690 /* 1691 * See if the settings have changed... 1692 */ 1693 1694 changed = strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, 1695 num_settings, settings)) || 1696 strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, 1697 num_settings, settings)) || 1698 strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY, 1699 num_settings, settings)) || 1700 strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, 1701 num_settings, settings)) || 1702#ifdef HAVE_GSSAPI 1703 !cupsGetOption("DefaultAuthType", num_settings, settings) || 1704 strcmp(default_auth_type, cupsGetOption("DefaultAuthType", 1705 num_settings, settings)) || 1706#endif /* HAVE_GSSAPI */ 1707 strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, 1708 num_settings, settings)); 1709 1710 if (advanced && !changed) 1711 changed = _cups_strcasecmp(browse_web_if, current_browse_web_if) || 1712 _cups_strcasecmp(preserve_job_history, current_preserve_job_history) || 1713 _cups_strcasecmp(preserve_job_files, current_preserve_job_files) || 1714 _cups_strcasecmp(max_clients, current_max_clients) || 1715 _cups_strcasecmp(max_jobs, current_max_jobs) || 1716 _cups_strcasecmp(max_log_size, current_max_log_size); 1717 1718 if (changed) 1719 { 1720 /* 1721 * Settings *have* changed, so save the changes... 1722 */ 1723 1724 cupsFreeOptions(num_settings, settings); 1725 1726 num_settings = 0; 1727 num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, 1728 debug_logging, num_settings, &settings); 1729 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, 1730 remote_admin, num_settings, &settings); 1731 num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, 1732 remote_any, num_settings, &settings); 1733 num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, 1734 share_printers, num_settings, &settings); 1735 num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, 1736 user_cancel_any, num_settings, &settings); 1737#ifdef HAVE_GSSAPI 1738 num_settings = cupsAddOption("DefaultAuthType", default_auth_type, 1739 num_settings, &settings); 1740#endif /* HAVE_GSSAPI */ 1741 1742 if (advanced) 1743 { 1744 /* 1745 * Add advanced settings... 1746 */ 1747 1748 if (_cups_strcasecmp(browse_web_if, current_browse_web_if)) 1749 num_settings = cupsAddOption("BrowseWebIF", browse_web_if, 1750 num_settings, &settings); 1751 if (_cups_strcasecmp(preserve_job_history, current_preserve_job_history)) 1752 num_settings = cupsAddOption("PreserveJobHistory", 1753 preserve_job_history, num_settings, 1754 &settings); 1755 if (_cups_strcasecmp(preserve_job_files, current_preserve_job_files)) 1756 num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files, 1757 num_settings, &settings); 1758 if (_cups_strcasecmp(max_clients, current_max_clients)) 1759 num_settings = cupsAddOption("MaxClients", max_clients, num_settings, 1760 &settings); 1761 if (_cups_strcasecmp(max_jobs, current_max_jobs)) 1762 num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings, 1763 &settings); 1764 if (_cups_strcasecmp(max_log_size, current_max_log_size)) 1765 num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings, 1766 &settings); 1767 } 1768 1769 if (!cupsAdminSetServerSettings(http, num_settings, settings)) 1770 { 1771 if (cupsLastError() == IPP_NOT_AUTHORIZED) 1772 { 1773 puts("Status: 401\n"); 1774 exit(0); 1775 } 1776 1777 cgiStartHTML(cgiText(_("Change Settings"))); 1778 cgiSetVariable("MESSAGE", 1779 cgiText(_("Unable to change server settings"))); 1780 cgiSetVariable("ERROR", cupsLastErrorString()); 1781 cgiCopyTemplateLang("error.tmpl"); 1782 } 1783 else 1784 { 1785 if (advanced) 1786 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&" 1787 "URL=/admin/?ADVANCEDSETTINGS=YES"); 1788 else 1789 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); 1790 cgiStartHTML(cgiText(_("Change Settings"))); 1791 cgiCopyTemplateLang("restart.tmpl"); 1792 } 1793 } 1794 else 1795 { 1796 /* 1797 * No changes... 1798 */ 1799 1800 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); 1801 cgiStartHTML(cgiText(_("Change Settings"))); 1802 cgiCopyTemplateLang("norestart.tmpl"); 1803 } 1804 1805 cupsFreeOptions(num_settings, settings); 1806 1807 cgiEndHTML(); 1808 } 1809 else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF")) 1810 { 1811 /* 1812 * Save hand-edited config file... 1813 */ 1814 1815 http_status_t status; /* PUT status */ 1816 char tempfile[1024]; /* Temporary new cupsd.conf */ 1817 int tempfd; /* Temporary file descriptor */ 1818 cups_file_t *temp; /* Temporary file */ 1819 const char *start, /* Start of line */ 1820 *end; /* End of line */ 1821 1822 1823 /* 1824 * Create a temporary file for the new cupsd.conf file... 1825 */ 1826 1827 if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) 1828 { 1829 cgiStartHTML(cgiText(_("Edit Configuration File"))); 1830 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file"))); 1831 cgiSetVariable("ERROR", strerror(errno)); 1832 cgiCopyTemplateLang("error.tmpl"); 1833 cgiEndHTML(); 1834 1835 perror(tempfile); 1836 return; 1837 } 1838 1839 if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL) 1840 { 1841 cgiStartHTML(cgiText(_("Edit Configuration File"))); 1842 cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file"))); 1843 cgiSetVariable("ERROR", strerror(errno)); 1844 cgiCopyTemplateLang("error.tmpl"); 1845 cgiEndHTML(); 1846 1847 perror(tempfile); 1848 close(tempfd); 1849 unlink(tempfile); 1850 return; 1851 } 1852 1853 /* 1854 * Copy the cupsd.conf text from the form variable... 1855 */ 1856 1857 start = cgiGetVariable("CUPSDCONF"); 1858 while (start) 1859 { 1860 if ((end = strstr(start, "\r\n")) == NULL) 1861 if ((end = strstr(start, "\n")) == NULL) 1862 end = start + strlen(start); 1863 1864 cupsFileWrite(temp, start, (size_t)(end - start)); 1865 cupsFilePutChar(temp, '\n'); 1866 1867 if (*end == '\r') 1868 start = end + 2; 1869 else if (*end == '\n') 1870 start = end + 1; 1871 else 1872 start = NULL; 1873 } 1874 1875 cupsFileClose(temp); 1876 1877 /* 1878 * Upload the configuration file to the server... 1879 */ 1880 1881 status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); 1882 1883 if (status == HTTP_UNAUTHORIZED) 1884 { 1885 puts("Status: 401\n"); 1886 unlink(tempfile); 1887 exit(0); 1888 } 1889 else if (status != HTTP_CREATED) 1890 { 1891 cgiSetVariable("MESSAGE", 1892 cgiText(_("Unable to upload cupsd.conf file"))); 1893 cgiSetVariable("ERROR", httpStatus(status)); 1894 1895 cgiStartHTML(cgiText(_("Edit Configuration File"))); 1896 cgiCopyTemplateLang("error.tmpl"); 1897 } 1898 else 1899 { 1900 cgiSetVariable("refresh_page", "5;URL=/admin/"); 1901 1902 cgiStartHTML(cgiText(_("Edit Configuration File"))); 1903 cgiCopyTemplateLang("restart.tmpl"); 1904 } 1905 1906 cgiEndHTML(); 1907 1908 unlink(tempfile); 1909 } 1910 else 1911 { 1912 struct stat info; /* cupsd.conf information */ 1913 cups_file_t *cupsd; /* cupsd.conf file */ 1914 char *buffer, /* Buffer for entire file */ 1915 *bufptr, /* Pointer into buffer */ 1916 *bufend; /* End of buffer */ 1917 int ch; /* Character from file */ 1918 char filename[1024]; /* Filename */ 1919 const char *server_root; /* Location of config files */ 1920 1921 1922 /* 1923 * Locate the cupsd.conf file... 1924 */ 1925 1926 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) 1927 server_root = CUPS_SERVERROOT; 1928 1929 snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root); 1930 1931 /* 1932 * Figure out the size... 1933 */ 1934 1935 if (stat(filename, &info)) 1936 { 1937 cgiStartHTML(cgiText(_("Edit Configuration File"))); 1938 cgiSetVariable("MESSAGE", 1939 cgiText(_("Unable to access cupsd.conf file"))); 1940 cgiSetVariable("ERROR", strerror(errno)); 1941 cgiCopyTemplateLang("error.tmpl"); 1942 cgiEndHTML(); 1943 1944 perror(filename); 1945 return; 1946 } 1947 1948 if (info.st_size > (1024 * 1024)) 1949 { 1950 cgiStartHTML(cgiText(_("Edit Configuration File"))); 1951 cgiSetVariable("MESSAGE", 1952 cgiText(_("Unable to access cupsd.conf file"))); 1953 cgiSetVariable("ERROR", 1954 cgiText(_("Unable to edit cupsd.conf files larger than " 1955 "1MB"))); 1956 cgiCopyTemplateLang("error.tmpl"); 1957 cgiEndHTML(); 1958 1959 fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename, 1960 (long)info.st_size); 1961 return; 1962 } 1963 1964 /* 1965 * Open the cupsd.conf file... 1966 */ 1967 1968 if ((cupsd = cupsFileOpen(filename, "r")) == NULL) 1969 { 1970 /* 1971 * Unable to open - log an error... 1972 */ 1973 1974 cgiStartHTML(cgiText(_("Edit Configuration File"))); 1975 cgiSetVariable("MESSAGE", 1976 cgiText(_("Unable to access cupsd.conf file"))); 1977 cgiSetVariable("ERROR", strerror(errno)); 1978 cgiCopyTemplateLang("error.tmpl"); 1979 cgiEndHTML(); 1980 1981 perror(filename); 1982 return; 1983 } 1984 1985 /* 1986 * Allocate memory and load the file into a string buffer... 1987 */ 1988 1989 if ((buffer = calloc(1, (size_t)info.st_size + 1)) != NULL) 1990 { 1991 cupsFileRead(cupsd, buffer, (size_t)info.st_size); 1992 cgiSetVariable("CUPSDCONF", buffer); 1993 free(buffer); 1994 } 1995 1996 cupsFileClose(cupsd); 1997 1998 /* 1999 * Then get the default cupsd.conf file and put that into a string as 2000 * well... 2001 */ 2002 2003 strlcat(filename, ".default", sizeof(filename)); 2004 2005 if (!stat(filename, &info) && info.st_size < (1024 * 1024) && 2006 (cupsd = cupsFileOpen(filename, "r")) != NULL) 2007 { 2008 if ((buffer = calloc(1, 2 * (size_t)info.st_size + 1)) != NULL) 2009 { 2010 bufend = buffer + 2 * info.st_size - 1; 2011 2012 for (bufptr = buffer; 2013 bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;) 2014 { 2015 if (ch == '\\' || ch == '\"') 2016 { 2017 *bufptr++ = '\\'; 2018 *bufptr++ = (char)ch; 2019 } 2020 else if (ch == '\n') 2021 { 2022 *bufptr++ = '\\'; 2023 *bufptr++ = 'n'; 2024 } 2025 else if (ch == '\t') 2026 { 2027 *bufptr++ = '\\'; 2028 *bufptr++ = 't'; 2029 } 2030 else if (ch >= ' ') 2031 *bufptr++ = (char)ch; 2032 } 2033 2034 *bufptr = '\0'; 2035 2036 cgiSetVariable("CUPSDCONF_DEFAULT", buffer); 2037 free(buffer); 2038 } 2039 2040 cupsFileClose(cupsd); 2041 } 2042 2043 /* 2044 * Show the current config file... 2045 */ 2046 2047 cgiStartHTML(cgiText(_("Edit Configuration File"))); 2048 2049 cgiCopyTemplateLang("edit-config.tmpl"); 2050 2051 cgiEndHTML(); 2052 } 2053} 2054 2055 2056/* 2057 * 'do_delete_class()' - Delete a class. 2058 */ 2059 2060static void 2061do_delete_class(http_t *http) /* I - HTTP connection */ 2062{ 2063 ipp_t *request; /* IPP request */ 2064 char uri[HTTP_MAX_URI]; /* Job URI */ 2065 const char *pclass; /* Printer class name */ 2066 2067 2068 /* 2069 * Get form variables... 2070 */ 2071 2072 if (cgiGetVariable("CONFIRM") == NULL) 2073 { 2074 cgiStartHTML(cgiText(_("Delete Class"))); 2075 cgiCopyTemplateLang("class-confirm.tmpl"); 2076 cgiEndHTML(); 2077 return; 2078 } 2079 2080 if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL) 2081 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 2082 "localhost", 0, "/classes/%s", pclass); 2083 else 2084 { 2085 cgiStartHTML(cgiText(_("Delete Class"))); 2086 cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); 2087 cgiCopyTemplateLang("error.tmpl"); 2088 cgiEndHTML(); 2089 return; 2090 } 2091 2092 /* 2093 * Build a CUPS_DELETE_CLASS request, which requires the following 2094 * attributes: 2095 * 2096 * attributes-charset 2097 * attributes-natural-language 2098 * printer-uri 2099 */ 2100 2101 request = ippNewRequest(CUPS_DELETE_CLASS); 2102 2103 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 2104 NULL, uri); 2105 2106 /* 2107 * Do the request and get back a response... 2108 */ 2109 2110 ippDelete(cupsDoRequest(http, request, "/admin/")); 2111 2112 /* 2113 * Show the results... 2114 */ 2115 2116 if (cupsLastError() == IPP_NOT_AUTHORIZED) 2117 { 2118 puts("Status: 401\n"); 2119 exit(0); 2120 } 2121 else if (cupsLastError() <= IPP_OK_CONFLICT) 2122 { 2123 /* 2124 * Redirect successful updates back to the classes page... 2125 */ 2126 2127 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes"); 2128 } 2129 2130 cgiStartHTML(cgiText(_("Delete Class"))); 2131 2132 if (cupsLastError() > IPP_OK_CONFLICT) 2133 cgiShowIPPError(_("Unable to delete class")); 2134 else 2135 cgiCopyTemplateLang("class-deleted.tmpl"); 2136 2137 cgiEndHTML(); 2138} 2139 2140 2141/* 2142 * 'do_delete_printer()' - Delete a printer. 2143 */ 2144 2145static void 2146do_delete_printer(http_t *http) /* I - HTTP connection */ 2147{ 2148 ipp_t *request; /* IPP request */ 2149 char uri[HTTP_MAX_URI]; /* Job URI */ 2150 const char *printer; /* Printer printer name */ 2151 2152 2153 /* 2154 * Get form variables... 2155 */ 2156 2157 if (cgiGetVariable("CONFIRM") == NULL) 2158 { 2159 cgiStartHTML(cgiText(_("Delete Printer"))); 2160 cgiCopyTemplateLang("printer-confirm.tmpl"); 2161 cgiEndHTML(); 2162 return; 2163 } 2164 2165 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) 2166 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 2167 "localhost", 0, "/printers/%s", printer); 2168 else 2169 { 2170 cgiStartHTML(cgiText(_("Delete Printer"))); 2171 cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); 2172 cgiCopyTemplateLang("error.tmpl"); 2173 cgiEndHTML(); 2174 return; 2175 } 2176 2177 /* 2178 * Build a CUPS_DELETE_PRINTER request, which requires the following 2179 * attributes: 2180 * 2181 * attributes-charset 2182 * attributes-natural-language 2183 * printer-uri 2184 */ 2185 2186 request = ippNewRequest(CUPS_DELETE_PRINTER); 2187 2188 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 2189 NULL, uri); 2190 2191 /* 2192 * Do the request and get back a response... 2193 */ 2194 2195 ippDelete(cupsDoRequest(http, request, "/admin/")); 2196 2197 /* 2198 * Show the results... 2199 */ 2200 2201 if (cupsLastError() == IPP_NOT_AUTHORIZED) 2202 { 2203 puts("Status: 401\n"); 2204 exit(0); 2205 } 2206 else if (cupsLastError() <= IPP_OK_CONFLICT) 2207 { 2208 /* 2209 * Redirect successful updates back to the printers page... 2210 */ 2211 2212 cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers"); 2213 } 2214 2215 cgiStartHTML(cgiText(_("Delete Printer"))); 2216 2217 if (cupsLastError() > IPP_OK_CONFLICT) 2218 cgiShowIPPError(_("Unable to delete printer")); 2219 else 2220 cgiCopyTemplateLang("printer-deleted.tmpl"); 2221 2222 cgiEndHTML(); 2223} 2224 2225 2226/* 2227 * 'do_export()' - Export printers to Samba. 2228 */ 2229 2230static void 2231do_export(http_t *http) /* I - HTTP connection */ 2232{ 2233 int i, j; /* Looping vars */ 2234 ipp_t *request, /* IPP request */ 2235 *response; /* IPP response */ 2236 const char *username, /* Samba username */ 2237 *password, /* Samba password */ 2238 *export_all; /* Export all printers? */ 2239 int export_count, /* Number of printers to export */ 2240 printer_count; /* Number of available printers */ 2241 const char *name, /* What name to pull */ 2242 *dest; /* Current destination */ 2243 char ppd[1024]; /* PPD file */ 2244 2245 2246 /* 2247 * Get form data... 2248 */ 2249 2250 username = cgiGetVariable("USERNAME"); 2251 password = cgiGetVariable("PASSWORD"); 2252 export_all = cgiGetVariable("EXPORT_ALL"); 2253 export_count = cgiGetSize("EXPORT_NAME"); 2254 2255 /* 2256 * Get list of available printers... 2257 */ 2258 2259 cgiSetSize("PRINTER_NAME", 0); 2260 cgiSetSize("PRINTER_EXPORT", 0); 2261 2262 request = ippNewRequest(CUPS_GET_PRINTERS); 2263 2264 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, 2265 "printer-type", 0); 2266 2267 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, 2268 "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); 2269 2270 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 2271 "requested-attributes", NULL, "printer-name"); 2272 2273 if ((response = cupsDoRequest(http, request, "/")) != NULL) 2274 { 2275 cgiSetIPPVars(response, NULL, NULL, NULL, 0); 2276 ippDelete(response); 2277 2278 if (!export_all) 2279 { 2280 printer_count = cgiGetSize("PRINTER_NAME"); 2281 2282 for (i = 0; i < printer_count; i ++) 2283 { 2284 dest = cgiGetArray("PRINTER_NAME", i); 2285 2286 for (j = 0; j < export_count; j ++) 2287 if (!_cups_strcasecmp(dest, cgiGetArray("EXPORT_NAME", j))) 2288 break; 2289 2290 cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : ""); 2291 } 2292 } 2293 } 2294 2295 /* 2296 * Export or get the printers to export... 2297 */ 2298 2299 if (username && *username && password && *password && 2300 (export_all || export_count > 0)) 2301 { 2302 /* 2303 * Do export... 2304 */ 2305 2306 fputs("DEBUG: Export printers...\n", stderr); 2307 2308 if (export_all) 2309 { 2310 name = "PRINTER_NAME"; 2311 export_count = cgiGetSize("PRINTER_NAME"); 2312 } 2313 else 2314 name = "EXPORT_NAME"; 2315 2316 for (i = 0; i < export_count; i ++) 2317 { 2318 dest = cgiGetArray(name, i); 2319 2320 if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd))) 2321 break; 2322 2323 j = cupsAdminExportSamba(dest, ppd, "localhost", username, password, 2324 stderr); 2325 2326 unlink(ppd); 2327 2328 if (!j) 2329 break; 2330 } 2331 2332 if (i < export_count) 2333 cgiSetVariable("ERROR", cupsLastErrorString()); 2334 else 2335 { 2336 cgiStartHTML(cgiText(_("Export Printers to Samba"))); 2337 cgiCopyTemplateLang("samba-exported.tmpl"); 2338 cgiEndHTML(); 2339 return; 2340 } 2341 } 2342 else if (username && !*username) 2343 cgiSetVariable("ERROR", 2344 cgiText(_("A Samba username is required to export " 2345 "printer drivers"))); 2346 else if (username && (!password || !*password)) 2347 cgiSetVariable("ERROR", 2348 cgiText(_("A Samba password is required to export " 2349 "printer drivers"))); 2350 2351 /* 2352 * Show form... 2353 */ 2354 2355 cgiStartHTML(cgiText(_("Export Printers to Samba"))); 2356 cgiCopyTemplateLang("samba-export.tmpl"); 2357 cgiEndHTML(); 2358} 2359 2360 2361/* 2362 * 'do_list_printers()' - List available printers. 2363 */ 2364 2365static void 2366do_list_printers(http_t *http) /* I - HTTP connection */ 2367{ 2368 ipp_t *request, /* IPP request */ 2369 *response; /* IPP response */ 2370 ipp_attribute_t *attr; /* IPP attribute */ 2371 2372 2373 cgiStartHTML(cgiText(_("List Available Printers"))); 2374 fflush(stdout); 2375 2376 /* 2377 * Get the list of printers and their devices... 2378 */ 2379 2380 request = ippNewRequest(CUPS_GET_PRINTERS); 2381 2382 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 2383 "requested-attributes", NULL, "device-uri"); 2384 2385 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", 2386 CUPS_PRINTER_LOCAL); 2387 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", 2388 CUPS_PRINTER_LOCAL); 2389 2390 if ((response = cupsDoRequest(http, request, "/")) != NULL) 2391 { 2392 /* 2393 * Got the printer list, now load the devices... 2394 */ 2395 2396 int i; /* Looping var */ 2397 cups_array_t *printer_devices; /* Printer devices for local printers */ 2398 char *printer_device; /* Current printer device */ 2399 2400 2401 /* 2402 * Allocate an array and copy the device strings... 2403 */ 2404 2405 printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL); 2406 2407 for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI); 2408 attr; 2409 attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI)) 2410 { 2411 cupsArrayAdd(printer_devices, _cupsStrAlloc(attr->values[0].string.text)); 2412 } 2413 2414 /* 2415 * Free the printer list and get the device list... 2416 */ 2417 2418 ippDelete(response); 2419 2420 request = ippNewRequest(CUPS_GET_DEVICES); 2421 2422 if ((response = cupsDoRequest(http, request, "/")) != NULL) 2423 { 2424 /* 2425 * Got the device list, let's parse it... 2426 */ 2427 2428 const char *device_uri, /* device-uri attribute value */ 2429 *device_make_and_model, /* device-make-and-model value */ 2430 *device_info; /* device-info value */ 2431 2432 2433 for (i = 0, attr = response->attrs; attr; attr = attr->next) 2434 { 2435 /* 2436 * Skip leading attributes until we hit a device... 2437 */ 2438 2439 while (attr && attr->group_tag != IPP_TAG_PRINTER) 2440 attr = attr->next; 2441 2442 if (!attr) 2443 break; 2444 2445 /* 2446 * Pull the needed attributes from this device... 2447 */ 2448 2449 device_info = NULL; 2450 device_make_and_model = NULL; 2451 device_uri = NULL; 2452 2453 while (attr && attr->group_tag == IPP_TAG_PRINTER) 2454 { 2455 if (!strcmp(attr->name, "device-info") && 2456 attr->value_tag == IPP_TAG_TEXT) 2457 device_info = attr->values[0].string.text; 2458 2459 if (!strcmp(attr->name, "device-make-and-model") && 2460 attr->value_tag == IPP_TAG_TEXT) 2461 device_make_and_model = attr->values[0].string.text; 2462 2463 if (!strcmp(attr->name, "device-uri") && 2464 attr->value_tag == IPP_TAG_URI) 2465 device_uri = attr->values[0].string.text; 2466 2467 attr = attr->next; 2468 } 2469 2470 /* 2471 * See if we have everything needed... 2472 */ 2473 2474 if (device_info && device_make_and_model && device_uri && 2475 _cups_strcasecmp(device_make_and_model, "unknown") && 2476 strchr(device_uri, ':')) 2477 { 2478 /* 2479 * Yes, now see if there is already a printer for this 2480 * device... 2481 */ 2482 2483 if (!cupsArrayFind(printer_devices, (void *)device_uri)) 2484 { 2485 /* 2486 * Not found, so it must be a new printer... 2487 */ 2488 2489 char option[1024], /* Form variables for this device */ 2490 *option_ptr; /* Pointer into string */ 2491 const char *ptr; /* Pointer into device string */ 2492 2493 2494 /* 2495 * Format the printer name variable for this device... 2496 * 2497 * We use the device-info string first, then device-uri, 2498 * and finally device-make-and-model to come up with a 2499 * suitable name. 2500 */ 2501 2502 if (_cups_strncasecmp(device_info, "unknown", 7)) 2503 ptr = device_info; 2504 else if ((ptr = strstr(device_uri, "://")) != NULL) 2505 ptr += 3; 2506 else 2507 ptr = device_make_and_model; 2508 2509 for (option_ptr = option; 2510 option_ptr < (option + sizeof(option) - 1) && *ptr; 2511 ptr ++) 2512 if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || 2513 *ptr == '.') 2514 *option_ptr++ = *ptr; 2515 else if ((*ptr == ' ' || *ptr == '/') && option_ptr > option && 2516 option_ptr[-1] != '_') 2517 *option_ptr++ = '_'; 2518 else if (*ptr == '?' || *ptr == '(') 2519 break; 2520 2521 *option_ptr = '\0'; 2522 2523 cgiSetArray("TEMPLATE_NAME", i, option); 2524 2525 /* 2526 * Finally, set the form variables for this printer... 2527 */ 2528 2529 cgiSetArray("device_info", i, device_info); 2530 cgiSetArray("device_make_and_model", i, device_make_and_model); 2531 cgiSetArray("device_uri", i, device_uri); 2532 i ++; 2533 } 2534 } 2535 2536 if (!attr) 2537 break; 2538 } 2539 2540 ippDelete(response); 2541 2542 /* 2543 * Free the device list... 2544 */ 2545 2546 for (printer_device = (char *)cupsArrayFirst(printer_devices); 2547 printer_device; 2548 printer_device = (char *)cupsArrayNext(printer_devices)) 2549 _cupsStrFree(printer_device); 2550 2551 cupsArrayDelete(printer_devices); 2552 } 2553 } 2554 2555 /* 2556 * Finally, show the printer list... 2557 */ 2558 2559 cgiCopyTemplateLang("list-available-printers.tmpl"); 2560 2561 cgiEndHTML(); 2562} 2563 2564 2565/* 2566 * 'do_menu()' - Show the main menu. 2567 */ 2568 2569static void 2570do_menu(http_t *http) /* I - HTTP connection */ 2571{ 2572 int num_settings; /* Number of server settings */ 2573 cups_option_t *settings; /* Server settings */ 2574 const char *val; /* Setting value */ 2575 char filename[1024]; /* Temporary filename */ 2576 const char *datadir; /* Location of data files */ 2577 ipp_t *request, /* IPP request */ 2578 *response; /* IPP response */ 2579 2580 2581 /* 2582 * Get the current server settings... 2583 */ 2584 2585 if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) 2586 { 2587 cgiSetVariable("SETTINGS_MESSAGE", 2588 cgiText(_("Unable to open cupsd.conf file:"))); 2589 cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString()); 2590 } 2591 2592 if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings, 2593 settings)) != NULL && atoi(val)) 2594 cgiSetVariable("DEBUG_LOGGING", "CHECKED"); 2595 2596 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings, 2597 settings)) != NULL && atoi(val)) 2598 cgiSetVariable("REMOTE_ADMIN", "CHECKED"); 2599 2600 if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, 2601 settings)) != NULL && atoi(val)) 2602 cgiSetVariable("REMOTE_ANY", "CHECKED"); 2603 2604 if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings, 2605 settings)) != NULL && atoi(val)) 2606 cgiSetVariable("SHARE_PRINTERS", "CHECKED"); 2607 2608 if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings, 2609 settings)) != NULL && atoi(val)) 2610 cgiSetVariable("USER_CANCEL_ANY", "CHECKED"); 2611 2612#ifdef HAVE_GSSAPI 2613 cgiSetVariable("HAVE_GSSAPI", "1"); 2614 2615 if ((val = cupsGetOption("DefaultAuthType", num_settings, 2616 settings)) != NULL && !_cups_strcasecmp(val, "Negotiate")) 2617 cgiSetVariable("KERBEROS", "CHECKED"); 2618 else 2619#endif /* HAVE_GSSAPI */ 2620 cgiSetVariable("KERBEROS", ""); 2621 2622 if ((val = cupsGetOption("BrowseWebIF", num_settings, 2623 settings)) == NULL) 2624 val = "No"; 2625 2626 if (!_cups_strcasecmp(val, "yes") || !_cups_strcasecmp(val, "on") || 2627 !_cups_strcasecmp(val, "true")) 2628 cgiSetVariable("BROWSE_WEB_IF", "CHECKED"); 2629 2630 if ((val = cupsGetOption("PreserveJobHistory", num_settings, 2631 settings)) == NULL) 2632 val = "Yes"; 2633 2634 if (val && 2635 (!_cups_strcasecmp(val, "0") || !_cups_strcasecmp(val, "no") || 2636 !_cups_strcasecmp(val, "off") || !_cups_strcasecmp(val, "false") || 2637 !_cups_strcasecmp(val, "disabled"))) 2638 { 2639 cgiSetVariable("PRESERVE_JOB_HISTORY", "0"); 2640 cgiSetVariable("PRESERVE_JOB_FILES", "0"); 2641 } 2642 else 2643 { 2644 cgiSetVariable("PRESERVE_JOBS", "CHECKED"); 2645 cgiSetVariable("PRESERVE_JOB_HISTORY", val); 2646 2647 if ((val = cupsGetOption("PreserveJobFiles", num_settings, 2648 settings)) == NULL) 2649 val = "1d"; 2650 2651 cgiSetVariable("PRESERVE_JOB_FILES", val); 2652 2653 } 2654 2655 if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL) 2656 val = "100"; 2657 2658 cgiSetVariable("MAX_CLIENTS", val); 2659 2660 if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL) 2661 val = "500"; 2662 2663 cgiSetVariable("MAX_JOBS", val); 2664 2665 if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL) 2666 val = "1m"; 2667 2668 cgiSetVariable("MAX_LOG_SIZE", val); 2669 2670 cupsFreeOptions(num_settings, settings); 2671 2672 /* 2673 * See if Samba and the Windows drivers are installed... 2674 */ 2675 2676 if ((datadir = getenv("CUPS_DATADIR")) == NULL) 2677 datadir = CUPS_DATADIR; 2678 2679 snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir); 2680 if (!access(filename, R_OK)) 2681 { 2682 /* 2683 * Found Windows 2000 driver file, see if we have smbclient and 2684 * rpcclient... 2685 */ 2686 2687 if (cupsFileFind("smbclient", getenv("PATH"), 1, filename, 2688 sizeof(filename)) && 2689 cupsFileFind("rpcclient", getenv("PATH"), 1, filename, 2690 sizeof(filename))) 2691 cgiSetVariable("HAVE_SAMBA", "Y"); 2692 else 2693 { 2694 if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename, 2695 sizeof(filename))) 2696 fputs("ERROR: smbclient not found!\n", stderr); 2697 2698 if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename, 2699 sizeof(filename))) 2700 fputs("ERROR: rpcclient not found!\n", stderr); 2701 } 2702 } 2703 else 2704 perror(filename); 2705 2706 /* 2707 * Subscriptions... 2708 */ 2709 2710 request = ippNewRequest(IPP_GET_SUBSCRIPTIONS); 2711 2712 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 2713 NULL, "ipp://localhost/"); 2714 2715 if ((response = cupsDoRequest(http, request, "/")) != NULL) 2716 { 2717 cgiSetIPPVars(response, NULL, NULL, NULL, 0); 2718 ippDelete(response); 2719 } 2720 2721 /* 2722 * Finally, show the main menu template... 2723 */ 2724 2725 cgiStartHTML(cgiText(_("Administration"))); 2726 2727 cgiCopyTemplateLang("admin.tmpl"); 2728 2729 cgiEndHTML(); 2730} 2731 2732 2733/* 2734 * 'do_set_allowed_users()' - Set the allowed/denied users for a queue. 2735 */ 2736 2737static void 2738do_set_allowed_users(http_t *http) /* I - HTTP connection */ 2739{ 2740 int i; /* Looping var */ 2741 ipp_t *request, /* IPP request */ 2742 *response; /* IPP response */ 2743 char uri[HTTP_MAX_URI]; /* Printer URI */ 2744 const char *printer, /* Printer name (purge-jobs) */ 2745 *is_class, /* Is a class? */ 2746 *users, /* List of users or groups */ 2747 *type; /* Allow/deny type */ 2748 int num_users; /* Number of users */ 2749 char *ptr, /* Pointer into users string */ 2750 *end, /* Pointer to end of users string */ 2751 quote; /* Quote character */ 2752 ipp_attribute_t *attr; /* Attribute */ 2753 static const char * const attrs[] = /* Requested attributes */ 2754 { 2755 "requesting-user-name-allowed", 2756 "requesting-user-name-denied" 2757 }; 2758 2759 2760 is_class = cgiGetVariable("IS_CLASS"); 2761 printer = cgiGetVariable("PRINTER_NAME"); 2762 2763 if (!printer) 2764 { 2765 cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); 2766 cgiStartHTML(cgiText(_("Set Allowed Users"))); 2767 cgiCopyTemplateLang("error.tmpl"); 2768 cgiEndHTML(); 2769 return; 2770 } 2771 2772 users = cgiGetVariable("users"); 2773 type = cgiGetVariable("type"); 2774 2775 if (!users || !type || 2776 (strcmp(type, "requesting-user-name-allowed") && 2777 strcmp(type, "requesting-user-name-denied"))) 2778 { 2779 /* 2780 * Build a Get-Printer-Attributes request, which requires the following 2781 * attributes: 2782 * 2783 * attributes-charset 2784 * attributes-natural-language 2785 * printer-uri 2786 * requested-attributes 2787 */ 2788 2789 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 2790 2791 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 2792 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", 2793 printer); 2794 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 2795 NULL, uri); 2796 2797 ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, 2798 "requested-attributes", 2799 (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); 2800 2801 /* 2802 * Do the request and get back a response... 2803 */ 2804 2805 if ((response = cupsDoRequest(http, request, "/")) != NULL) 2806 { 2807 cgiSetIPPVars(response, NULL, NULL, NULL, 0); 2808 2809 ippDelete(response); 2810 } 2811 2812 cgiStartHTML(cgiText(_("Set Allowed Users"))); 2813 2814 if (cupsLastError() == IPP_NOT_AUTHORIZED) 2815 { 2816 puts("Status: 401\n"); 2817 exit(0); 2818 } 2819 else if (cupsLastError() > IPP_OK_CONFLICT) 2820 cgiShowIPPError(_("Unable to get printer attributes")); 2821 else 2822 cgiCopyTemplateLang("users.tmpl"); 2823 2824 cgiEndHTML(); 2825 } 2826 else 2827 { 2828 /* 2829 * Save the changes... 2830 */ 2831 2832 for (num_users = 0, ptr = (char *)users; *ptr; num_users ++) 2833 { 2834 /* 2835 * Skip whitespace and commas... 2836 */ 2837 2838 while (*ptr == ',' || isspace(*ptr & 255)) 2839 ptr ++; 2840 2841 if (!*ptr) 2842 break; 2843 2844 if (*ptr == '\'' || *ptr == '\"') 2845 { 2846 /* 2847 * Scan quoted name... 2848 */ 2849 2850 quote = *ptr++; 2851 2852 for (end = ptr; *end; end ++) 2853 if (*end == quote) 2854 break; 2855 } 2856 else 2857 { 2858 /* 2859 * Scan space or comma-delimited name... 2860 */ 2861 2862 for (end = ptr; *end; end ++) 2863 if (isspace(*end & 255) || *end == ',') 2864 break; 2865 } 2866 2867 /* 2868 * Advance to the next name... 2869 */ 2870 2871 ptr = end; 2872 } 2873 2874 /* 2875 * Build a CUPS-Add-Printer/Class request, which requires the following 2876 * attributes: 2877 * 2878 * attributes-charset 2879 * attributes-natural-language 2880 * printer-uri 2881 * requesting-user-name-{allowed,denied} 2882 */ 2883 2884 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER); 2885 2886 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 2887 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", 2888 printer); 2889 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 2890 NULL, uri); 2891 2892 if (num_users == 0) 2893 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, 2894 "requesting-user-name-allowed", NULL, "all"); 2895 else 2896 { 2897 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, 2898 type, num_users, NULL, NULL); 2899 2900 for (i = 0, ptr = (char *)users; *ptr; i ++) 2901 { 2902 /* 2903 * Skip whitespace and commas... 2904 */ 2905 2906 while (*ptr == ',' || isspace(*ptr & 255)) 2907 ptr ++; 2908 2909 if (!*ptr) 2910 break; 2911 2912 if (*ptr == '\'' || *ptr == '\"') 2913 { 2914 /* 2915 * Scan quoted name... 2916 */ 2917 2918 quote = *ptr++; 2919 2920 for (end = ptr; *end; end ++) 2921 if (*end == quote) 2922 break; 2923 } 2924 else 2925 { 2926 /* 2927 * Scan space or comma-delimited name... 2928 */ 2929 2930 for (end = ptr; *end; end ++) 2931 if (isspace(*end & 255) || *end == ',') 2932 break; 2933 } 2934 2935 /* 2936 * Terminate the name... 2937 */ 2938 2939 if (*end) 2940 *end++ = '\0'; 2941 2942 /* 2943 * Add the name... 2944 */ 2945 2946 attr->values[i].string.text = _cupsStrAlloc(ptr); 2947 2948 /* 2949 * Advance to the next name... 2950 */ 2951 2952 ptr = end; 2953 } 2954 } 2955 2956 /* 2957 * Do the request and get back a response... 2958 */ 2959 2960 ippDelete(cupsDoRequest(http, request, "/admin/")); 2961 2962 if (cupsLastError() == IPP_NOT_AUTHORIZED) 2963 { 2964 puts("Status: 401\n"); 2965 exit(0); 2966 } 2967 else if (cupsLastError() > IPP_OK_CONFLICT) 2968 { 2969 cgiStartHTML(cgiText(_("Set Allowed Users"))); 2970 cgiShowIPPError(_("Unable to change printer")); 2971 } 2972 else 2973 { 2974 /* 2975 * Redirect successful updates back to the printer page... 2976 */ 2977 2978 char url[1024], /* Printer/class URL */ 2979 refresh[1024]; /* Refresh URL */ 2980 2981 2982 cgiRewriteURL(uri, url, sizeof(url), NULL); 2983 cgiFormEncode(uri, url, sizeof(uri)); 2984 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", 2985 uri); 2986 cgiSetVariable("refresh_page", refresh); 2987 2988 cgiStartHTML(cgiText(_("Set Allowed Users"))); 2989 2990 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" : 2991 "printer-modified.tmpl"); 2992 } 2993 2994 cgiEndHTML(); 2995 } 2996} 2997 2998 2999/* 3000 * 'do_set_default()' - Set the server default printer/class. 3001 */ 3002 3003static void 3004do_set_default(http_t *http) /* I - HTTP connection */ 3005{ 3006 const char *title; /* Page title */ 3007 ipp_t *request; /* IPP request */ 3008 char uri[HTTP_MAX_URI]; /* Printer URI */ 3009 const char *printer, /* Printer name (purge-jobs) */ 3010 *is_class; /* Is a class? */ 3011 3012 3013 is_class = cgiGetVariable("IS_CLASS"); 3014 printer = cgiGetVariable("PRINTER_NAME"); 3015 title = cgiText(_("Set As Server Default")); 3016 3017 if (!printer) 3018 { 3019 cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); 3020 cgiStartHTML(title); 3021 cgiCopyTemplateLang("error.tmpl"); 3022 cgiEndHTML(); 3023 return; 3024 } 3025 3026 /* 3027 * Build a printer request, which requires the following 3028 * attributes: 3029 * 3030 * attributes-charset 3031 * attributes-natural-language 3032 * printer-uri 3033 */ 3034 3035 request = ippNewRequest(CUPS_SET_DEFAULT); 3036 3037 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 3038 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", 3039 printer); 3040 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 3041 NULL, uri); 3042 3043 /* 3044 * Do the request and get back a response... 3045 */ 3046 3047 ippDelete(cupsDoRequest(http, request, "/admin/")); 3048 3049 if (cupsLastError() == IPP_NOT_AUTHORIZED) 3050 { 3051 puts("Status: 401\n"); 3052 exit(0); 3053 } 3054 else if (cupsLastError() > IPP_OK_CONFLICT) 3055 { 3056 cgiStartHTML(title); 3057 cgiShowIPPError(_("Unable to set server default")); 3058 } 3059 else 3060 { 3061 /* 3062 * Redirect successful updates back to the printer page... 3063 */ 3064 3065 char url[1024], /* Printer/class URL */ 3066 refresh[1024]; /* Refresh URL */ 3067 3068 3069 cgiRewriteURL(uri, url, sizeof(url), NULL); 3070 cgiFormEncode(uri, url, sizeof(uri)); 3071 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri); 3072 cgiSetVariable("refresh_page", refresh); 3073 3074 cgiStartHTML(title); 3075 cgiCopyTemplateLang("printer-default.tmpl"); 3076 } 3077 3078 cgiEndHTML(); 3079} 3080 3081 3082/* 3083 * 'do_set_options()' - Configure the default options for a queue. 3084 */ 3085 3086static void 3087do_set_options(http_t *http, /* I - HTTP connection */ 3088 int is_class) /* I - Set options for class? */ 3089{ 3090 int i, j, k, m; /* Looping vars */ 3091 int have_options; /* Have options? */ 3092 ipp_t *request, /* IPP request */ 3093 *response; /* IPP response */ 3094 ipp_attribute_t *attr; /* IPP attribute */ 3095 char uri[HTTP_MAX_URI]; /* Job URI */ 3096 const char *var; /* Variable value */ 3097 const char *printer; /* Printer printer name */ 3098 const char *filename; /* PPD filename */ 3099 char tempfile[1024]; /* Temporary filename */ 3100 cups_file_t *in, /* Input file */ 3101 *out; /* Output file */ 3102 char line[1024], /* Line from PPD file */ 3103 value[1024], /* Option value */ 3104 keyword[1024], /* Keyword from Default line */ 3105 *keyptr; /* Pointer into keyword... */ 3106 ppd_file_t *ppd; /* PPD file */ 3107 ppd_group_t *group; /* Option group */ 3108 ppd_option_t *option; /* Option */ 3109 ppd_coption_t *coption; /* Custom option */ 3110 ppd_cparam_t *cparam; /* Custom parameter */ 3111 ppd_attr_t *ppdattr; /* PPD attribute */ 3112 const char *title; /* Page title */ 3113 3114 3115 title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options")); 3116 3117 fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http, 3118 is_class); 3119 3120 /* 3121 * Get the printer name... 3122 */ 3123 3124 if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) 3125 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 3126 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", 3127 printer); 3128 else 3129 { 3130 cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); 3131 cgiStartHTML(title); 3132 cgiCopyTemplateLang("error.tmpl"); 3133 cgiEndHTML(); 3134 return; 3135 } 3136 3137 fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri); 3138 3139 /* 3140 * If the user clicks on the Auto-Configure button, send an AutoConfigure 3141 * command file to the printer... 3142 */ 3143 3144 if (cgiGetVariable("AUTOCONFIGURE")) 3145 { 3146 cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options"); 3147 return; 3148 } 3149 3150 /* 3151 * Get the PPD file... 3152 */ 3153 3154 if (is_class) 3155 filename = NULL; 3156 else 3157 filename = cupsGetPPD2(http, printer); 3158 3159 if (filename) 3160 { 3161 fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename); 3162 3163 if ((ppd = ppdOpenFile(filename)) == NULL) 3164 { 3165 cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i))); 3166 cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file"))); 3167 cgiStartHTML(title); 3168 cgiCopyTemplateLang("error.tmpl"); 3169 cgiEndHTML(); 3170 return; 3171 } 3172 } 3173 else 3174 { 3175 fputs("DEBUG: No PPD file\n", stderr); 3176 ppd = NULL; 3177 } 3178 3179 if (cgiGetVariable("job_sheets_start") != NULL || 3180 cgiGetVariable("job_sheets_end") != NULL) 3181 have_options = 1; 3182 else 3183 have_options = 0; 3184 3185 if (ppd) 3186 { 3187 ppdMarkDefaults(ppd); 3188 3189 for (option = ppdFirstOption(ppd); 3190 option; 3191 option = ppdNextOption(ppd)) 3192 { 3193 if ((var = cgiGetVariable(option->keyword)) != NULL) 3194 { 3195 have_options = 1; 3196 ppdMarkOption(ppd, option->keyword, var); 3197 fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var); 3198 } 3199 else 3200 fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword); 3201 } 3202 } 3203 3204 if (!have_options || ppdConflicts(ppd)) 3205 { 3206 /* 3207 * Show the options to the user... 3208 */ 3209 3210 fputs("DEBUG: Showing options...\n", stderr); 3211 3212 /* 3213 * Show auto-configure button if supported... 3214 */ 3215 3216 if (ppd) 3217 { 3218 if (ppd->num_filters == 0 || 3219 ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL && 3220 ppdattr->value && strstr(ppdattr->value, "AutoConfigure"))) 3221 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES"); 3222 else 3223 { 3224 for (i = 0; i < ppd->num_filters; i ++) 3225 if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31)) 3226 { 3227 cgiSetVariable("HAVE_AUTOCONFIGURE", "YES"); 3228 break; 3229 } 3230 } 3231 } 3232 3233 /* 3234 * Get the printer attributes... 3235 */ 3236 3237 request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); 3238 3239 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 3240 "localhost", 0, "/printers/%s", printer); 3241 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 3242 NULL, uri); 3243 3244 response = cupsDoRequest(http, request, "/"); 3245 3246 /* 3247 * List the groups used as "tabs"... 3248 */ 3249 3250 i = 0; 3251 3252 if (ppd) 3253 { 3254 for (group = ppd->groups; 3255 i < ppd->num_groups; 3256 i ++, group ++) 3257 { 3258 cgiSetArray("GROUP_ID", i, group->name); 3259 3260 if (!strcmp(group->name, "InstallableOptions")) 3261 cgiSetArray("GROUP", i, cgiText(_("Options Installed"))); 3262 else 3263 cgiSetArray("GROUP", i, group->text); 3264 } 3265 } 3266 3267 if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) 3268 { 3269 cgiSetArray("GROUP_ID", i, "CUPS_BANNERS"); 3270 cgiSetArray("GROUP", i ++, cgiText(_("Banners"))); 3271 } 3272 3273 if (ippFindAttribute(response, "printer-error-policy-supported", 3274 IPP_TAG_ZERO) || 3275 ippFindAttribute(response, "printer-op-policy-supported", 3276 IPP_TAG_ZERO)) 3277 { 3278 cgiSetArray("GROUP_ID", i, "CUPS_POLICIES"); 3279 cgiSetArray("GROUP", i ++, cgiText(_("Policies"))); 3280 } 3281 3282 if ((attr = ippFindAttribute(response, "port-monitor-supported", 3283 IPP_TAG_NAME)) != NULL && attr->num_values > 1) 3284 { 3285 cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR"); 3286 cgiSetArray("GROUP", i, cgiText(_("Port Monitor"))); 3287 } 3288 3289 cgiStartHTML(cgiText(_("Set Printer Options"))); 3290 cgiCopyTemplateLang("set-printer-options-header.tmpl"); 3291 3292 if (ppd) 3293 { 3294 ppdLocalize(ppd); 3295 3296 if (ppdConflicts(ppd)) 3297 { 3298 for (i = ppd->num_groups, k = 0, group = ppd->groups; 3299 i > 0; 3300 i --, group ++) 3301 for (j = group->num_options, option = group->options; 3302 j > 0; 3303 j --, option ++) 3304 if (option->conflicted) 3305 { 3306 cgiSetArray("ckeyword", k, option->keyword); 3307 cgiSetArray("ckeytext", k, option->text); 3308 3309 for (m = 0; m < option->num_choices; m ++) 3310 { 3311 if (option->choices[m].marked) 3312 { 3313 cgiSetArray("cchoice", k, option->choices[m].text); 3314 break; 3315 } 3316 } 3317 3318 k ++; 3319 } 3320 3321 cgiCopyTemplateLang("option-conflict.tmpl"); 3322 } 3323 3324 for (i = ppd->num_groups, group = ppd->groups; 3325 i > 0; 3326 i --, group ++) 3327 { 3328 for (j = group->num_options, option = group->options; 3329 j > 0; 3330 j --, option ++) 3331 { 3332 if (!strcmp(option->keyword, "PageRegion")) 3333 continue; 3334 3335 if (option->num_choices > 1) 3336 break; 3337 } 3338 3339 if (j == 0) 3340 continue; 3341 3342 cgiSetVariable("GROUP_ID", group->name); 3343 3344 if (!strcmp(group->name, "InstallableOptions")) 3345 cgiSetVariable("GROUP", cgiText(_("Options Installed"))); 3346 else 3347 cgiSetVariable("GROUP", group->text); 3348 3349 cgiCopyTemplateLang("option-header.tmpl"); 3350 3351 for (j = group->num_options, option = group->options; 3352 j > 0; 3353 j --, option ++) 3354 { 3355 if (!strcmp(option->keyword, "PageRegion") || option->num_choices < 2) 3356 continue; 3357 3358 cgiSetVariable("KEYWORD", option->keyword); 3359 cgiSetVariable("KEYTEXT", option->text); 3360 3361 if (option->conflicted) 3362 cgiSetVariable("CONFLICTED", "1"); 3363 else 3364 cgiSetVariable("CONFLICTED", "0"); 3365 3366 cgiSetSize("CHOICES", 0); 3367 cgiSetSize("TEXT", 0); 3368 for (k = 0, m = 0; k < option->num_choices; k ++) 3369 { 3370 cgiSetArray("CHOICES", m, option->choices[k].choice); 3371 cgiSetArray("TEXT", m, option->choices[k].text); 3372 3373 m ++; 3374 3375 if (option->choices[k].marked) 3376 cgiSetVariable("DEFCHOICE", option->choices[k].choice); 3377 } 3378 3379 cgiSetSize("PARAMS", 0); 3380 cgiSetSize("PARAMTEXT", 0); 3381 cgiSetSize("PARAMVALUE", 0); 3382 cgiSetSize("INPUTTYPE", 0); 3383 3384 if ((coption = ppdFindCustomOption(ppd, option->keyword))) 3385 { 3386 const char *units = NULL; /* Units value, if any */ 3387 3388 cgiSetVariable("ISCUSTOM", "1"); 3389 3390 for (cparam = ppdFirstCustomParam(coption), m = 0; 3391 cparam; 3392 cparam = ppdNextCustomParam(coption), m ++) 3393 { 3394 if (!_cups_strcasecmp(option->keyword, "PageSize") && 3395 _cups_strcasecmp(cparam->name, "Width") && 3396 _cups_strcasecmp(cparam->name, "Height")) 3397 { 3398 m --; 3399 continue; 3400 } 3401 3402 cgiSetArray("PARAMS", m, cparam->name); 3403 cgiSetArray("PARAMTEXT", m, cparam->text); 3404 cgiSetArray("INPUTTYPE", m, "text"); 3405 3406 switch (cparam->type) 3407 { 3408 case PPD_CUSTOM_POINTS : 3409 if (!_cups_strncasecmp(option->defchoice, "Custom.", 7)) 3410 { 3411 units = option->defchoice + strlen(option->defchoice) - 2; 3412 3413 if (strcmp(units, "mm") && strcmp(units, "cm") && 3414 strcmp(units, "in") && strcmp(units, "ft")) 3415 { 3416 if (units[1] == 'm') 3417 units ++; 3418 else 3419 units = "pt"; 3420 } 3421 } 3422 else 3423 units = "pt"; 3424 3425 if (!strcmp(units, "mm")) 3426 snprintf(value, sizeof(value), "%g", 3427 cparam->current.custom_points / 72.0 * 25.4); 3428 else if (!strcmp(units, "cm")) 3429 snprintf(value, sizeof(value), "%g", 3430 cparam->current.custom_points / 72.0 * 2.54); 3431 else if (!strcmp(units, "in")) 3432 snprintf(value, sizeof(value), "%g", 3433 cparam->current.custom_points / 72.0); 3434 else if (!strcmp(units, "ft")) 3435 snprintf(value, sizeof(value), "%g", 3436 cparam->current.custom_points / 72.0 / 12.0); 3437 else if (!strcmp(units, "m")) 3438 snprintf(value, sizeof(value), "%g", 3439 cparam->current.custom_points / 72.0 * 0.0254); 3440 else 3441 snprintf(value, sizeof(value), "%g", 3442 cparam->current.custom_points); 3443 cgiSetArray("PARAMVALUE", m, value); 3444 break; 3445 3446 case PPD_CUSTOM_CURVE : 3447 case PPD_CUSTOM_INVCURVE : 3448 case PPD_CUSTOM_REAL : 3449 snprintf(value, sizeof(value), "%g", 3450 cparam->current.custom_real); 3451 cgiSetArray("PARAMVALUE", m, value); 3452 break; 3453 3454 case PPD_CUSTOM_INT: 3455 snprintf(value, sizeof(value), "%d", 3456 cparam->current.custom_int); 3457 cgiSetArray("PARAMVALUE", m, value); 3458 break; 3459 3460 case PPD_CUSTOM_PASSCODE: 3461 case PPD_CUSTOM_PASSWORD: 3462 if (cparam->current.custom_password) 3463 cgiSetArray("PARAMVALUE", m, 3464 cparam->current.custom_password); 3465 else 3466 cgiSetArray("PARAMVALUE", m, ""); 3467 cgiSetArray("INPUTTYPE", m, "password"); 3468 break; 3469 3470 case PPD_CUSTOM_STRING: 3471 if (cparam->current.custom_string) 3472 cgiSetArray("PARAMVALUE", m, 3473 cparam->current.custom_string); 3474 else 3475 cgiSetArray("PARAMVALUE", m, ""); 3476 break; 3477 } 3478 } 3479 3480 if (units) 3481 { 3482 cgiSetArray("PARAMS", m, "Units"); 3483 cgiSetArray("PARAMTEXT", m, cgiText(_("Units"))); 3484 cgiSetArray("PARAMVALUE", m, units); 3485 } 3486 } 3487 else 3488 cgiSetVariable("ISCUSTOM", "0"); 3489 3490 switch (option->ui) 3491 { 3492 case PPD_UI_BOOLEAN : 3493 cgiCopyTemplateLang("option-boolean.tmpl"); 3494 break; 3495 case PPD_UI_PICKONE : 3496 cgiCopyTemplateLang("option-pickone.tmpl"); 3497 break; 3498 case PPD_UI_PICKMANY : 3499 cgiCopyTemplateLang("option-pickmany.tmpl"); 3500 break; 3501 } 3502 } 3503 3504 cgiCopyTemplateLang("option-trailer.tmpl"); 3505 } 3506 } 3507 3508 if ((attr = ippFindAttribute(response, "job-sheets-supported", 3509 IPP_TAG_ZERO)) != NULL) 3510 { 3511 /* 3512 * Add the job sheets options... 3513 */ 3514 3515 cgiSetVariable("GROUP_ID", "CUPS_BANNERS"); 3516 cgiSetVariable("GROUP", cgiText(_("Banners"))); 3517 cgiCopyTemplateLang("option-header.tmpl"); 3518 3519 cgiSetSize("CHOICES", attr->num_values); 3520 cgiSetSize("TEXT", attr->num_values); 3521 for (k = 0; k < attr->num_values; k ++) 3522 { 3523 cgiSetArray("CHOICES", k, attr->values[k].string.text); 3524 cgiSetArray("TEXT", k, attr->values[k].string.text); 3525 } 3526 3527 attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO); 3528 3529 cgiSetVariable("KEYWORD", "job_sheets_start"); 3530 cgiSetVariable("KEYTEXT", 3531 /* TRANSLATORS: Banner/cover sheet before the print job. */ 3532 cgiText(_("Starting Banner"))); 3533 cgiSetVariable("DEFCHOICE", attr != NULL ? 3534 attr->values[0].string.text : ""); 3535 3536 cgiCopyTemplateLang("option-pickone.tmpl"); 3537 3538 cgiSetVariable("KEYWORD", "job_sheets_end"); 3539 cgiSetVariable("KEYTEXT", 3540 /* TRANSLATORS: Banner/cover sheet after the print job. */ 3541 cgiText(_("Ending Banner"))); 3542 cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ? 3543 attr->values[1].string.text : ""); 3544 3545 cgiCopyTemplateLang("option-pickone.tmpl"); 3546 3547 cgiCopyTemplateLang("option-trailer.tmpl"); 3548 } 3549 3550 if (ippFindAttribute(response, "printer-error-policy-supported", 3551 IPP_TAG_ZERO) || 3552 ippFindAttribute(response, "printer-op-policy-supported", 3553 IPP_TAG_ZERO)) 3554 { 3555 /* 3556 * Add the error and operation policy options... 3557 */ 3558 3559 cgiSetVariable("GROUP_ID", "CUPS_POLICIES"); 3560 cgiSetVariable("GROUP", cgiText(_("Policies"))); 3561 cgiCopyTemplateLang("option-header.tmpl"); 3562 3563 /* 3564 * Error policy... 3565 */ 3566 3567 attr = ippFindAttribute(response, "printer-error-policy-supported", 3568 IPP_TAG_ZERO); 3569 3570 if (attr) 3571 { 3572 cgiSetSize("CHOICES", attr->num_values); 3573 cgiSetSize("TEXT", attr->num_values); 3574 for (k = 0; k < attr->num_values; k ++) 3575 { 3576 cgiSetArray("CHOICES", k, attr->values[k].string.text); 3577 cgiSetArray("TEXT", k, attr->values[k].string.text); 3578 } 3579 3580 attr = ippFindAttribute(response, "printer-error-policy", 3581 IPP_TAG_ZERO); 3582 3583 cgiSetVariable("KEYWORD", "printer_error_policy"); 3584 cgiSetVariable("KEYTEXT", cgiText(_("Error Policy"))); 3585 cgiSetVariable("DEFCHOICE", attr == NULL ? 3586 "" : attr->values[0].string.text); 3587 } 3588 3589 cgiCopyTemplateLang("option-pickone.tmpl"); 3590 3591 /* 3592 * Operation policy... 3593 */ 3594 3595 attr = ippFindAttribute(response, "printer-op-policy-supported", 3596 IPP_TAG_ZERO); 3597 3598 if (attr) 3599 { 3600 cgiSetSize("CHOICES", attr->num_values); 3601 cgiSetSize("TEXT", attr->num_values); 3602 for (k = 0; k < attr->num_values; k ++) 3603 { 3604 cgiSetArray("CHOICES", k, attr->values[k].string.text); 3605 cgiSetArray("TEXT", k, attr->values[k].string.text); 3606 } 3607 3608 attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO); 3609 3610 cgiSetVariable("KEYWORD", "printer_op_policy"); 3611 cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy"))); 3612 cgiSetVariable("DEFCHOICE", attr == NULL ? 3613 "" : attr->values[0].string.text); 3614 3615 cgiCopyTemplateLang("option-pickone.tmpl"); 3616 } 3617 3618 cgiCopyTemplateLang("option-trailer.tmpl"); 3619 } 3620 3621 /* 3622 * Binary protocol support... 3623 */ 3624 3625 if ((attr = ippFindAttribute(response, "port-monitor-supported", 3626 IPP_TAG_NAME)) != NULL && attr->num_values > 1) 3627 { 3628 cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR"); 3629 cgiSetVariable("GROUP", cgiText(_("Port Monitor"))); 3630 3631 cgiSetSize("CHOICES", attr->num_values); 3632 cgiSetSize("TEXT", attr->num_values); 3633 3634 for (i = 0; i < attr->num_values; i ++) 3635 { 3636 cgiSetArray("CHOICES", i, attr->values[i].string.text); 3637 cgiSetArray("TEXT", i, attr->values[i].string.text); 3638 } 3639 3640 attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME); 3641 cgiSetVariable("KEYWORD", "port_monitor"); 3642 cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor"))); 3643 cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none"); 3644 3645 cgiCopyTemplateLang("option-header.tmpl"); 3646 cgiCopyTemplateLang("option-pickone.tmpl"); 3647 cgiCopyTemplateLang("option-trailer.tmpl"); 3648 } 3649 3650 cgiCopyTemplateLang("set-printer-options-trailer.tmpl"); 3651 cgiEndHTML(); 3652 3653 ippDelete(response); 3654 } 3655 else 3656 { 3657 /* 3658 * Set default options... 3659 */ 3660 3661 fputs("DEBUG: Setting options...\n", stderr); 3662 3663 if (filename) 3664 { 3665 out = cupsTempFile2(tempfile, sizeof(tempfile)); 3666 in = cupsFileOpen(filename, "r"); 3667 3668 if (!in || !out) 3669 { 3670 cgiSetVariable("ERROR", strerror(errno)); 3671 cgiStartHTML(cgiText(_("Set Printer Options"))); 3672 cgiCopyTemplateLang("error.tmpl"); 3673 cgiEndHTML(); 3674 3675 if (in) 3676 cupsFileClose(in); 3677 3678 if (out) 3679 { 3680 cupsFileClose(out); 3681 unlink(tempfile); 3682 } 3683 3684 unlink(filename); 3685 return; 3686 } 3687 3688 while (cupsFileGets(in, line, sizeof(line))) 3689 { 3690 if (!strncmp(line, "*cupsProtocol:", 14)) 3691 continue; 3692 else if (strncmp(line, "*Default", 8)) 3693 cupsFilePrintf(out, "%s\n", line); 3694 else 3695 { 3696 /* 3697 * Get default option name... 3698 */ 3699 3700 strlcpy(keyword, line + 8, sizeof(keyword)); 3701 3702 for (keyptr = keyword; *keyptr; keyptr ++) 3703 if (*keyptr == ':' || isspace(*keyptr & 255)) 3704 break; 3705 3706 *keyptr = '\0'; 3707 3708 if (!strcmp(keyword, "PageRegion") || 3709 !strcmp(keyword, "PaperDimension") || 3710 !strcmp(keyword, "ImageableArea")) 3711 var = get_option_value(ppd, "PageSize", value, sizeof(value)); 3712 else 3713 var = get_option_value(ppd, keyword, value, sizeof(value)); 3714 3715 if (!var) 3716 cupsFilePrintf(out, "%s\n", line); 3717 else 3718 cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); 3719 } 3720 } 3721 3722 cupsFileClose(in); 3723 cupsFileClose(out); 3724 } 3725 else 3726 { 3727 /* 3728 * Make sure temporary filename is cleared when there is no PPD... 3729 */ 3730 3731 tempfile[0] = '\0'; 3732 } 3733 3734 /* 3735 * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the 3736 * following attributes: 3737 * 3738 * attributes-charset 3739 * attributes-natural-language 3740 * printer-uri 3741 * job-sheets-default 3742 * printer-error-policy 3743 * printer-op-policy 3744 * [ppd file] 3745 */ 3746 3747 request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS : 3748 CUPS_ADD_MODIFY_PRINTER); 3749 3750 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 3751 NULL, uri); 3752 3753 attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, 3754 "job-sheets-default", 2, NULL, NULL); 3755 attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start")); 3756 attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end")); 3757 3758 if ((var = cgiGetVariable("printer_error_policy")) != NULL) 3759 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, 3760 "printer-error-policy", NULL, var); 3761 3762 if ((var = cgiGetVariable("printer_op_policy")) != NULL) 3763 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, 3764 "printer-op-policy", NULL, var); 3765 3766 if ((var = cgiGetVariable("port_monitor")) != NULL) 3767 ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, 3768 "port-monitor", NULL, var); 3769 3770 /* 3771 * Do the request and get back a response... 3772 */ 3773 3774 if (filename) 3775 ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile)); 3776 else 3777 ippDelete(cupsDoRequest(http, request, "/admin/")); 3778 3779 if (cupsLastError() == IPP_NOT_AUTHORIZED) 3780 { 3781 puts("Status: 401\n"); 3782 exit(0); 3783 } 3784 else if (cupsLastError() > IPP_OK_CONFLICT) 3785 { 3786 cgiStartHTML(title); 3787 cgiShowIPPError(_("Unable to set options")); 3788 } 3789 else 3790 { 3791 /* 3792 * Redirect successful updates back to the printer page... 3793 */ 3794 3795 char refresh[1024]; /* Refresh URL */ 3796 3797 3798 cgiFormEncode(uri, printer, sizeof(uri)); 3799 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s", 3800 is_class ? "classes" : "printers", uri); 3801 cgiSetVariable("refresh_page", refresh); 3802 3803 cgiStartHTML(title); 3804 3805 cgiCopyTemplateLang("printer-configured.tmpl"); 3806 } 3807 3808 cgiEndHTML(); 3809 3810 if (filename) 3811 unlink(tempfile); 3812 } 3813 3814 if (filename) 3815 unlink(filename); 3816} 3817 3818 3819/* 3820 * 'do_set_sharing()' - Set printer-is-shared value. 3821 */ 3822 3823static void 3824do_set_sharing(http_t *http) /* I - HTTP connection */ 3825{ 3826 ipp_t *request, /* IPP request */ 3827 *response; /* IPP response */ 3828 char uri[HTTP_MAX_URI]; /* Printer URI */ 3829 const char *printer, /* Printer name */ 3830 *is_class, /* Is a class? */ 3831 *shared; /* Sharing value */ 3832 3833 3834 is_class = cgiGetVariable("IS_CLASS"); 3835 printer = cgiGetVariable("PRINTER_NAME"); 3836 shared = cgiGetVariable("SHARED"); 3837 3838 if (!printer || !shared) 3839 { 3840 cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); 3841 cgiStartHTML(cgiText(_("Set Publishing"))); 3842 cgiCopyTemplateLang("error.tmpl"); 3843 cgiEndHTML(); 3844 return; 3845 } 3846 3847 /* 3848 * Build a CUPS-Add-Printer/CUPS-Add-Class request, which requires the 3849 * following attributes: 3850 * 3851 * attributes-charset 3852 * attributes-natural-language 3853 * printer-uri 3854 * printer-is-shared 3855 */ 3856 3857 request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER); 3858 3859 httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, 3860 "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", 3861 printer); 3862 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", 3863 NULL, uri); 3864 3865 ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", (char)atoi(shared)); 3866 3867 /* 3868 * Do the request and get back a response... 3869 */ 3870 3871 if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) 3872 { 3873 cgiSetIPPVars(response, NULL, NULL, NULL, 0); 3874 3875 ippDelete(response); 3876 } 3877 3878 if (cupsLastError() == IPP_NOT_AUTHORIZED) 3879 { 3880 puts("Status: 401\n"); 3881 exit(0); 3882 } 3883 else if (cupsLastError() > IPP_OK_CONFLICT) 3884 { 3885 cgiStartHTML(cgiText(_("Set Publishing"))); 3886 cgiShowIPPError(_("Unable to change printer-is-shared attribute")); 3887 } 3888 else 3889 { 3890 /* 3891 * Redirect successful updates back to the printer page... 3892 */ 3893 3894 char url[1024], /* Printer/class URL */ 3895 refresh[1024]; /* Refresh URL */ 3896 3897 3898 cgiRewriteURL(uri, url, sizeof(url), NULL); 3899 cgiFormEncode(uri, url, sizeof(uri)); 3900 snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri); 3901 cgiSetVariable("refresh_page", refresh); 3902 3903 cgiStartHTML(cgiText(_("Set Publishing"))); 3904 cgiCopyTemplateLang(is_class ? "class-modified.tmpl" : 3905 "printer-modified.tmpl"); 3906 } 3907 3908 cgiEndHTML(); 3909} 3910 3911 3912/* 3913 * 'get_option_value()' - Return the value of an option. 3914 * 3915 * This function also handles generation of custom option values. 3916 */ 3917 3918static char * /* O - Value string or NULL on error */ 3919get_option_value( 3920 ppd_file_t *ppd, /* I - PPD file */ 3921 const char *name, /* I - Option name */ 3922 char *buffer, /* I - String buffer */ 3923 size_t bufsize) /* I - Size of buffer */ 3924{ 3925 char *bufptr, /* Pointer into buffer */ 3926 *bufend; /* End of buffer */ 3927 ppd_coption_t *coption; /* Custom option */ 3928 ppd_cparam_t *cparam; /* Current custom parameter */ 3929 char keyword[256]; /* Parameter name */ 3930 const char *val, /* Parameter value */ 3931 *uval; /* Units value */ 3932 long integer; /* Integer value */ 3933 double number, /* Number value */ 3934 number_points; /* Number in points */ 3935 3936 3937 /* 3938 * See if we have a custom option choice... 3939 */ 3940 3941 if ((val = cgiGetVariable(name)) == NULL) 3942 { 3943 /* 3944 * Option not found! 3945 */ 3946 3947 return (NULL); 3948 } 3949 else if (_cups_strcasecmp(val, "Custom") || 3950 (coption = ppdFindCustomOption(ppd, name)) == NULL) 3951 { 3952 /* 3953 * Not a custom choice... 3954 */ 3955 3956 strlcpy(buffer, val, bufsize); 3957 return (buffer); 3958 } 3959 3960 /* 3961 * OK, we have a custom option choice, format it... 3962 */ 3963 3964 *buffer = '\0'; 3965 3966 if (!strcmp(coption->keyword, "PageSize")) 3967 { 3968 const char *lval; /* Length string value */ 3969 double width, /* Width value */ 3970 width_points, /* Width in points */ 3971 length, /* Length value */ 3972 length_points; /* Length in points */ 3973 3974 3975 val = cgiGetVariable("PageSize.Width"); 3976 lval = cgiGetVariable("PageSize.Height"); 3977 uval = cgiGetVariable("PageSize.Units"); 3978 3979 if (!val || !lval || !uval || 3980 (width = strtod(val, NULL)) == 0.0 || 3981 (length = strtod(lval, NULL)) == 0.0 || 3982 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && 3983 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) 3984 return (NULL); 3985 3986 width_points = get_points(width, uval); 3987 length_points = get_points(length, uval); 3988 3989 if (width_points < ppd->custom_min[0] || 3990 width_points > ppd->custom_max[0] || 3991 length_points < ppd->custom_min[1] || 3992 length_points > ppd->custom_max[1]) 3993 return (NULL); 3994 3995 snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval); 3996 } 3997 else if (cupsArrayCount(coption->params) == 1) 3998 { 3999 cparam = ppdFirstCustomParam(coption); 4000 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name); 4001 4002 if ((val = cgiGetVariable(keyword)) == NULL) 4003 return (NULL); 4004 4005 switch (cparam->type) 4006 { 4007 case PPD_CUSTOM_CURVE : 4008 case PPD_CUSTOM_INVCURVE : 4009 case PPD_CUSTOM_REAL : 4010 if ((number = strtod(val, NULL)) == 0.0 || 4011 number < cparam->minimum.custom_real || 4012 number > cparam->maximum.custom_real) 4013 return (NULL); 4014 4015 snprintf(buffer, bufsize, "Custom.%g", number); 4016 break; 4017 4018 case PPD_CUSTOM_INT : 4019 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || 4020 integer == LONG_MAX || 4021 integer < cparam->minimum.custom_int || 4022 integer > cparam->maximum.custom_int) 4023 return (NULL); 4024 4025 snprintf(buffer, bufsize, "Custom.%ld", integer); 4026 break; 4027 4028 case PPD_CUSTOM_POINTS : 4029 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); 4030 4031 if ((number = strtod(val, NULL)) == 0.0 || 4032 (uval = cgiGetVariable(keyword)) == NULL || 4033 (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && 4034 strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) 4035 return (NULL); 4036 4037 number_points = get_points(number, uval); 4038 if (number_points < cparam->minimum.custom_points || 4039 number_points > cparam->maximum.custom_points) 4040 return (NULL); 4041 4042 snprintf(buffer, bufsize, "Custom.%g%s", number, uval); 4043 break; 4044 4045 case PPD_CUSTOM_PASSCODE : 4046 for (uval = val; *uval; uval ++) 4047 if (!isdigit(*uval & 255)) 4048 return (NULL); 4049 4050 case PPD_CUSTOM_PASSWORD : 4051 case PPD_CUSTOM_STRING : 4052 integer = (long)strlen(val); 4053 if (integer < cparam->minimum.custom_string || 4054 integer > cparam->maximum.custom_string) 4055 return (NULL); 4056 4057 snprintf(buffer, bufsize, "Custom.%s", val); 4058 break; 4059 } 4060 } 4061 else 4062 { 4063 const char *prefix = "{"; /* Prefix string */ 4064 4065 4066 bufptr = buffer; 4067 bufend = buffer + bufsize; 4068 4069 for (cparam = ppdFirstCustomParam(coption); 4070 cparam; 4071 cparam = ppdNextCustomParam(coption)) 4072 { 4073 snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, 4074 cparam->name); 4075 4076 if ((val = cgiGetVariable(keyword)) == NULL) 4077 return (NULL); 4078 4079 snprintf(bufptr, (size_t)(bufend - bufptr), "%s%s=", prefix, cparam->name); 4080 bufptr += strlen(bufptr); 4081 prefix = " "; 4082 4083 switch (cparam->type) 4084 { 4085 case PPD_CUSTOM_CURVE : 4086 case PPD_CUSTOM_INVCURVE : 4087 case PPD_CUSTOM_REAL : 4088 if ((number = strtod(val, NULL)) == 0.0 || 4089 number < cparam->minimum.custom_real || 4090 number > cparam->maximum.custom_real) 4091 return (NULL); 4092 4093 snprintf(bufptr, (size_t)(bufend - bufptr), "%g", number); 4094 break; 4095 4096 case PPD_CUSTOM_INT : 4097 if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || 4098 integer == LONG_MAX || 4099 integer < cparam->minimum.custom_int || 4100 integer > cparam->maximum.custom_int) 4101 return (NULL); 4102 4103 snprintf(bufptr, (size_t)(bufend - bufptr), "%ld", integer); 4104 break; 4105 4106 case PPD_CUSTOM_POINTS : 4107 snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); 4108 4109 if ((number = strtod(val, NULL)) == 0.0 || 4110 (uval = cgiGetVariable(keyword)) == NULL || 4111 (strcmp(uval, "pt") && strcmp(uval, "in") && 4112 strcmp(uval, "ft") && strcmp(uval, "cm") && 4113 strcmp(uval, "mm") && strcmp(uval, "m"))) 4114 return (NULL); 4115 4116 number_points = get_points(number, uval); 4117 if (number_points < cparam->minimum.custom_points || 4118 number_points > cparam->maximum.custom_points) 4119 return (NULL); 4120 4121 snprintf(bufptr, (size_t)(bufend - bufptr), "%g%s", number, uval); 4122 break; 4123 4124 case PPD_CUSTOM_PASSCODE : 4125 for (uval = val; *uval; uval ++) 4126 if (!isdigit(*uval & 255)) 4127 return (NULL); 4128 4129 case PPD_CUSTOM_PASSWORD : 4130 case PPD_CUSTOM_STRING : 4131 integer = (long)strlen(val); 4132 if (integer < cparam->minimum.custom_string || 4133 integer > cparam->maximum.custom_string) 4134 return (NULL); 4135 4136 if ((bufptr + 2) > bufend) 4137 return (NULL); 4138 4139 bufend --; 4140 *bufptr++ = '\"'; 4141 4142 while (*val && bufptr < bufend) 4143 { 4144 if (*val == '\\' || *val == '\"') 4145 { 4146 if ((bufptr + 1) >= bufend) 4147 return (NULL); 4148 4149 *bufptr++ = '\\'; 4150 } 4151 4152 *bufptr++ = *val++; 4153 } 4154 4155 if (bufptr >= bufend) 4156 return (NULL); 4157 4158 *bufptr++ = '\"'; 4159 *bufptr = '\0'; 4160 bufend ++; 4161 break; 4162 } 4163 4164 bufptr += strlen(bufptr); 4165 } 4166 4167 if (bufptr == buffer || (bufend - bufptr) < 2) 4168 return (NULL); 4169 4170 memcpy(bufptr, "}", 2); 4171 } 4172 4173 return (buffer); 4174} 4175 4176 4177/* 4178 * 'get_points()' - Get a value in points. 4179 */ 4180 4181static double /* O - Number in points */ 4182get_points(double number, /* I - Original number */ 4183 const char *uval) /* I - Units */ 4184{ 4185 if (!strcmp(uval, "mm")) /* Millimeters */ 4186 return (number * 72.0 / 25.4); 4187 else if (!strcmp(uval, "cm")) /* Centimeters */ 4188 return (number * 72.0 / 2.54); 4189 else if (!strcmp(uval, "in")) /* Inches */ 4190 return (number * 72.0); 4191 else if (!strcmp(uval, "ft")) /* Feet */ 4192 return (number * 72.0 * 12.0); 4193 else if (!strcmp(uval, "m")) /* Meters */ 4194 return (number * 72.0 / 0.0254); 4195 else /* Points */ 4196 return (number); 4197} 4198 4199 4200/* 4201 * End of "$Id: admin.c 12131 2014-08-28 23:38:16Z msweet $". 4202 */ 4203