X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=cgi-bin%2Fadmin.c;h=bddc2d03841ea948b988f6de705d7bac972c8dc1;hb=5f64df29828e9ca71164342efd357e9debfb6e44;hp=01252ba5cf65b356d87b803da37bb9fdbd9c7a28;hpb=fa73b22906f71080fa5056485d8204612717adac;p=thirdparty%2Fcups.git diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index 01252ba5c..bddc2d038 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -1,40 +1,36 @@ /* - * "$Id: admin.c 4943 2006-01-18 20:30:42Z mike $" + * "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $" * * Administration CGI for the Common UNIX Printing System (CUPS). * - * Copyright 1997-2006 by Easy Software Products. + * Copyright 2007-2008 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the - * property of Easy Software Products and are protected by Federal - * copyright law. Distribution and use rights are outlined in the file - * "LICENSE.txt" which should have been included with this file. If this - * file is missing or damaged please contact Easy Software Products - * at: - * - * Attn: CUPS Licensing Information - * Easy Software Products - * 44141 Airport View Drive, Suite 204 - * Hollywood, Maryland 20636 USA - * - * Voice: (301) 373-9600 - * EMail: cups-info@cups.org - * WWW: http://www.cups.org + * property of Apple Inc. and are protected by Federal copyright + * law. Distribution and use rights are outlined in the file "LICENSE.txt" + * which should have been included with this file. If this file is + * file is missing or damaged, see the license at "http://www.cups.org/". * * Contents: * * main() - Main entry for CGI. + * do_add_rss_subscription() - Add a RSS subscription. * do_am_class() - Add or modify a class. * do_am_printer() - Add or modify a printer. - * do_config_printer() - Configure the default options for a printer. + * do_cancel_subscription() - Cancel a subscription. * do_config_server() - Configure server settings. - * do_delete_class() - Delete a class... - * do_delete_printer() - Delete a printer... - * do_export() - Export printers to Samba... - * do_menu() - Show the main menu... + * do_delete_class() - Delete a class. + * do_delete_printer() - Delete a printer. + * do_export() - Export printers to Samba. + * do_list_printers() - List available printers. + * do_menu() - Show the main menu. * do_printer_op() - Do a printer operation. * do_set_allowed_users() - Set the allowed/denied users for a queue. - * do_set_sharing() - Set printer-is-shared value... + * do_set_options() - Configure the default options for a queue. + * do_set_sharing() - Set printer-is-shared value. + * get_option_value() - Return the value of an option. + * get_points() - Get a value in points. * match_string() - Return the number of matching characters. */ @@ -43,29 +39,37 @@ */ #include "cgi-private.h" +#include #include #include #include #include #include +#include /* * Local functions... */ +static void do_add_rss_subscription(http_t *http); static void do_am_class(http_t *http, int modify); static void do_am_printer(http_t *http, int modify); -static void do_config_printer(http_t *http); +static void do_cancel_subscription(http_t *http); +static void do_set_options(http_t *http, int is_class); static void do_config_server(http_t *http); static void do_delete_class(http_t *http); static void do_delete_printer(http_t *http); static void do_export(http_t *http); +static void do_list_printers(http_t *http); static void do_menu(http_t *http); static void do_printer_op(http_t *http, ipp_op_t op, const char *title); static void do_set_allowed_users(http_t *http); static void do_set_sharing(http_t *http); +static char *get_option_value(ppd_file_t *ppd, const char *name, + char *buffer, size_t bufsize); +static double get_points(double number, const char *uval); static int match_string(const char *a, const char *b); @@ -85,8 +89,22 @@ main(int argc, /* I - Number of command-line arguments */ * Connect to the HTTP server... */ + fputs("DEBUG: admin.cgi started...\n", stderr); + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + if (!http) + { + perror("ERROR: Unable to connect to cupsd"); + fprintf(stderr, "DEBUG: cupsServer()=\"%s\"\n", + cupsServer() ? cupsServer() : "(null)"); + fprintf(stderr, "DEBUG: ippPort()=%d\n", ippPort()); + fprintf(stderr, "DEBUG: cupsEncryption()=%d\n", cupsEncryption()); + exit(1); + } + + fprintf(stderr, "DEBUG: http=%p\n", http); + /* * Set the web interface section... */ @@ -103,25 +121,19 @@ main(int argc, /* I - Number of command-line arguments */ * Nope, send the administration menu... */ + fputs("DEBUG: No form data, showing main menu...\n", stderr); + do_menu(http); } - else if ((op = cgiGetVariable("OP")) != NULL) + else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST()) { /* * Do the operation... */ - if (!strcmp(op, "redirect")) - { - const char *url; /* Redirection URL... */ - + fprintf(stderr, "DEBUG: op=\"%s\"...\n", op); - if ((url = cgiGetVariable("URL")) != NULL) - printf("Location: %s\n\n", url); - else - puts("Location: /admin\n"); - } - else if (!strcmp(op, "start-printer")) + if (!strcmp(op, "start-printer")) do_printer_op(http, IPP_RESUME_PRINTER, cgiText(_("Start Printer"))); else if (!strcmp(op, "stop-printer")) do_printer_op(http, IPP_PAUSE_PRINTER, cgiText(_("Stop Printer"))); @@ -141,6 +153,9 @@ main(int argc, /* I - Number of command-line arguments */ do_printer_op(http, CUPS_SET_DEFAULT, cgiText(_("Set As Default"))); else if (!strcmp(op, "set-sharing")) do_set_sharing(http); + else if (!strcmp(op, "find-new-printers") || + !strcmp(op, "list-available-printers")) + do_list_printers(http); else if (!strcmp(op, "add-class")) do_am_class(http, 0); else if (!strcmp(op, "add-printer")) @@ -153,16 +168,22 @@ main(int argc, /* I - Number of command-line arguments */ do_delete_class(http); else if (!strcmp(op, "delete-printer")) do_delete_printer(http); + else if (!strcmp(op, "set-class-options")) + do_set_options(http, 1); else if (!strcmp(op, "set-printer-options")) - do_config_printer(http); + do_set_options(http, 0); else if (!strcmp(op, "config-server")) do_config_server(http); else if (!strcmp(op, "export-samba")) do_export(http); + else if (!strcmp(op, "add-rss-subscription")) + do_add_rss_subscription(http); + else if (!strcmp(op, "cancel-subscription")) + do_cancel_subscription(http); else { /* - * Bad operation code... Display an error... + * Bad operation code - display an error... */ cgiStartHTML(cgiText(_("Administration"))); @@ -170,10 +191,28 @@ main(int argc, /* I - Number of command-line arguments */ cgiEndHTML(); } } + else if (op && !strcmp(op, "redirect")) + { + const char *url; /* Redirection URL... */ + char prefix[1024]; /* URL prefix */ + + + if (getenv("HTTPS")) + snprintf(prefix, sizeof(prefix), "https://%s:%s", + getenv("SERVER_NAME"), getenv("SERVER_PORT")); + else + snprintf(prefix, sizeof(prefix), "http://%s:%s", + getenv("SERVER_NAME"), getenv("SERVER_PORT")); + + if ((url = cgiGetVariable("URL")) != NULL) + printf("Location: %s%s\n\n", prefix, url); + else + printf("Location: %s/admin\n\n", prefix); + } else { /* - * Form data but no operation code... Display an error... + * Form data but no operation code - display an error... */ cgiStartHTML(cgiText(_("Administration"))); @@ -195,6 +234,177 @@ main(int argc, /* I - Number of command-line arguments */ } +/* + * 'do_add_rss_subscription()' - Add a RSS subscription. + */ + +static void +do_add_rss_subscription(http_t *http) /* I - HTTP connection */ +{ + ipp_t *request, /* IPP request data */ + *response; /* IPP response data */ + char rss_uri[1024]; /* RSS notify-recipient URI */ + int num_events; /* Number of events */ + const char *events[12], /* Subscribed events */ + *subscription_name, /* Subscription name */ + *printer_uri, /* Printer URI */ + *ptr, /* Pointer into name */ + *user; /* Username */ + int max_events; /* Maximum number of events */ + + + /* + * See if we have all of the required information... + */ + + subscription_name = cgiGetVariable("SUBSCRIPTION_NAME"); + printer_uri = cgiGetVariable("PRINTER_URI"); + num_events = 0; + + if (cgiGetVariable("EVENT_JOB_CREATED")) + events[num_events ++] = "job-created"; + if (cgiGetVariable("EVENT_JOB_COMPLETED")) + events[num_events ++] = "job-completed"; + if (cgiGetVariable("EVENT_JOB_STOPPED")) + events[num_events ++] = "job-stopped"; + if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED")) + events[num_events ++] = "job-config-changed"; + if (cgiGetVariable("EVENT_PRINTER_STOPPED")) + events[num_events ++] = "printer-stopped"; + if (cgiGetVariable("EVENT_PRINTER_ADDED")) + events[num_events ++] = "printer-added"; + if (cgiGetVariable("EVENT_PRINTER_MODIFIED")) + events[num_events ++] = "printer-modified"; + if (cgiGetVariable("EVENT_PRINTER_DELETED")) + events[num_events ++] = "printer-deleted"; + if (cgiGetVariable("EVENT_SERVER_STARTED")) + events[num_events ++] = "server-started"; + if (cgiGetVariable("EVENT_SERVER_STOPPED")) + events[num_events ++] = "server-stopped"; + if (cgiGetVariable("EVENT_SERVER_RESTARTED")) + events[num_events ++] = "server-restarted"; + if (cgiGetVariable("EVENT_SERVER_AUDIT")) + events[num_events ++] = "server-audit"; + + if ((ptr = cgiGetVariable("MAX_EVENTS")) != NULL) + max_events = atoi(ptr); + else + max_events = 0; + + if (!subscription_name || !printer_uri || !num_events || + max_events <= 0 || max_events > 9999) + { + /* + * Don't have everything we need, so get the available printers + * and classes and (re)show the add page... + */ + + request = ippNewRequest(CUPS_GET_PRINTERS); + response = cupsDoRequest(http, request, "/"); + + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + + cgiStartHTML(cgiText(_("Add RSS Subscription"))); + + cgiCopyTemplateLang("add-rss-subscription.tmpl"); + + cgiEndHTML(); + return; + } + + /* + * Make sure we have a username... + */ + + if ((user = getenv("REMOTE_USER")) == NULL) + { + puts("Status: 401\n"); + exit(0); + } + + /* + * Validate the subscription name... + */ + + for (ptr = subscription_name; *ptr; ptr ++) + if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || + *ptr == '?' || *ptr == '#') + break; + + if (*ptr) + { + cgiSetVariable("ERROR", + cgiText(_("The subscription name may not " + "contain spaces, slashes (/), question marks (?), " + "or the pound sign (#)."))); + cgiStartHTML(_("Add RSS Subscription")); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + /* + * Add the subscription... + */ + + ptr = subscription_name + strlen(subscription_name) - 4; + if (ptr < subscription_name || strcmp(ptr, ".rss")) + httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss", + NULL, NULL, 0, "/%s.rss?max_events=%d", subscription_name, + max_events); + else + httpAssembleURIf(HTTP_URI_CODING_ALL, rss_uri, sizeof(rss_uri), "rss", + NULL, NULL, 0, "/%s?max_events=%d", subscription_name, + max_events); + + request = ippNewRequest(IPP_CREATE_PRINTER_SUBSCRIPTION); + + if (!strcasecmp(printer_uri, "#ALL#")) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/"); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, printer_uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, user); + + ippAddString(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, + "notify-recipient-uri", NULL, rss_uri); + ippAddStrings(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, "notify-events", + num_events, NULL, events); + ippAddInteger(request, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-lease-duration", 0); + + ippDelete(cupsDoRequest(http, request, "/")); + + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) + { + cgiStartHTML(_("Add RSS Subscription")); + cgiShowIPPError(_("Unable to add RSS subscription:")); + } + else + { + /* + * Redirect successful updates back to the admin page... + */ + + cgiSetVariable("refresh_page", "5;URL=/admin"); + cgiStartHTML(_("Add RSS Subscription")); + cgiCopyTemplateLang("subscription-added.tmpl"); + } + + cgiEndHTML(); +} + + /* * 'do_am_class()' - Add or modify a class. */ @@ -232,14 +442,10 @@ do_am_class(http_t *http, /* I - HTTP connection */ * * attributes-charset * attributes-natural-language - * printer-uri */ request = ippNewRequest(CUPS_GET_PRINTERS); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, "ipp://localhost/printers"); - /* * Do the request and get back a response... */ @@ -303,8 +509,8 @@ do_am_class(http_t *http, /* I - HTTP connection */ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/classes/%s", name); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, "/classes/%s", name); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -319,7 +525,8 @@ do_am_class(http_t *http, /* I - HTTP connection */ if ((response = cupsDoRequest(http, request, "/")) != NULL) { - if ((attr = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) != NULL) + if ((attr = ippFindAttribute(response, "member-names", + IPP_TAG_NAME)) != NULL) { /* * Mark any current members in the class... @@ -408,8 +615,9 @@ do_am_class(http_t *http, /* I - HTTP connection */ request = ippNewRequest(CUPS_ADD_CLASS); - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/classes/%s", cgiGetVariable("PRINTER_NAME")); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, "/classes/%s", + cgiGetVariable("PRINTER_NAME")); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -438,7 +646,12 @@ do_am_class(http_t *http, /* I - HTTP connection */ ippDelete(cupsDoRequest(http, request, "/admin/")); - if (cupsLastError() > IPP_OK_CONFLICT) + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) { cgiStartHTML(title); cgiShowIPPError(modify ? _("Unable to modify class:") : @@ -453,7 +666,7 @@ do_am_class(http_t *http, /* I - HTTP connection */ char refresh[1024]; /* Refresh URL */ cgiFormEncode(uri, name, sizeof(uri)); - snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=/classes/%s", + snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/classes/%s", uri); cgiSetVariable("refresh_page", refresh); @@ -478,9 +691,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ int modify) /* I - Modify the printer? */ { int i; /* Looping var */ - int element; /* Element number */ - ipp_attribute_t *attr, /* Current attribute */ - *last; /* Last attribute */ + ipp_attribute_t *attr; /* Current attribute */ ipp_t *request, /* IPP request */ *response, /* IPP response */ *oldinfo; /* Old printer information */ @@ -508,8 +719,9 @@ do_am_printer(http_t *http, /* I - HTTP connection */ }; + ptr = cgiGetVariable("DEVICE_URI"); fprintf(stderr, "DEBUG: do_am_printer: DEVICE_URI=\"%s\"\n", - cgiGetVariable("DEVICE_URI")); + ptr ? ptr : "(null)"); title = cgiText(modify ? _("Modify Printer") : _("Add Printer")); @@ -526,8 +738,9 @@ do_am_printer(http_t *http, /* I - HTTP connection */ request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/printers/%s", cgiGetVariable("PRINTER_NAME")); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, "/printers/%s", + cgiGetVariable("PRINTER_NAME")); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -540,67 +753,101 @@ do_am_printer(http_t *http, /* I - HTTP connection */ else oldinfo = NULL; - if ((name = cgiGetVariable("PRINTER_NAME")) == NULL || - cgiGetVariable("PRINTER_LOCATION") == NULL) - { - cgiStartHTML(title); + file = cgiGetFile(); - if (modify) - { - /* - * Update the location and description of an existing printer... - */ + if (file) + { + fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile); + fprintf(stderr, "DEBUG: file->name=%s\n", file->name); + fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename); + fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype); + } - if (oldinfo) - cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0); + if ((name = cgiGetVariable("PRINTER_NAME")) != NULL) + { + for (ptr = name; *ptr; ptr ++) + if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') + break; - cgiCopyTemplateLang("modify-printer.tmpl"); + if (*ptr || ptr == name || strlen(name) > 127) + { + cgiSetVariable("ERROR", + cgiText(_("The printer name may only contain up to " + "127 printable characters and may not " + "contain spaces, slashes (/), or the " + "pound sign (#)."))); + cgiStartHTML(title); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; } - else + } + + if ((var = cgiGetVariable("DEVICE_URI")) != NULL) + { + if ((uriptr = strrchr(var, '|')) != NULL) { /* - * Get the name, location, and description for a new printer... + * Extract make and make/model from device URI string... */ - cgiCopyTemplateLang("add-printer.tmpl"); - } + char make[1024], /* Make string */ + *makeptr; /* Pointer into make */ - cgiEndHTML(); - if (oldinfo) - ippDelete(oldinfo); + *uriptr++ = '\0'; - return; - } + strlcpy(make, uriptr, sizeof(make)); - for (ptr = name; *ptr; ptr ++) - if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') - break; + if ((makeptr = strchr(make, ' ')) != NULL) + *makeptr = '\0'; + else if ((makeptr = strchr(make, '-')) != NULL) + *makeptr = '\0'; + else if (!strncasecmp(make, "laserjet", 8) || + !strncasecmp(make, "deskjet", 7) || + !strncasecmp(make, "designjet", 9)) + strcpy(make, "HP"); + else if (!strncasecmp(make, "phaser", 6)) + strcpy(make, "Xerox"); + else if (!strncasecmp(make, "stylus", 6)) + strcpy(make, "Epson"); + else + strcpy(make, "Generic"); - if (*ptr || ptr == name || strlen(name) > 127) - { - cgiSetVariable("ERROR", - cgiText(_("The printer name may only contain up to " - "127 printable characters and may not " - "contain spaces, slashes (/), or the " - "pound sign (#)."))); - cgiStartHTML(title); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; - } + if (!cgiGetVariable("CURRENT_MAKE")) + cgiSetVariable("CURRENT_MAKE", make); - file = cgiGetFile(); + cgiSetVariable("PPD_MAKE", make); - if (file) - { - fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile); - fprintf(stderr, "DEBUG: file->name=%s\n", file->name); - fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename); - fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype); + if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL")) + cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr); + + if (!modify) + { + char template[128], /* Template name */ + *tptr; /* Pointer into template name */ + + cgiSetVariable("PRINTER_INFO", uriptr); + + for (tptr = template; + tptr < (template + sizeof(template) - 1) && *uriptr; + uriptr ++) + if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' || + *uriptr == '.') + *tptr++ = *uriptr; + else if ((*uriptr == ' ' || *uriptr == '/') && tptr[-1] != '_') + *tptr++ = '_'; + else if (*uriptr == '?' || *uriptr == '(') + break; + + *tptr = '\0'; + + cgiSetVariable("TEMPLATE_NAME", template); + } + } } - if ((var = cgiGetVariable("DEVICE_URI")) == NULL) + if (!var) { /* * Build a CUPS_GET_DEVICES request, which requires the following @@ -611,6 +858,8 @@ do_am_printer(http_t *http, /* I - HTTP connection */ * printer-uri */ + fputs("DEBUG: Getting list of devices...\n", stderr); + request = ippNewRequest(CUPS_GET_DEVICES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", @@ -622,9 +871,15 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if ((response = cupsDoRequest(http, request, "/")) != NULL) { + fputs("DEBUG: Got device list!\n", stderr); + cgiSetIPPVars(response, NULL, NULL, NULL, 0); ippDelete(response); } + else + fprintf(stderr, + "ERROR: CUPS-Get-Devices request failed with status %x: %s\n", + cupsLastError(), cupsLastErrorString()); /* * Let the user choose... @@ -689,7 +944,38 @@ do_am_printer(http_t *http, /* I - HTTP connection */ cgiCopyTemplateLang("choose-serial.tmpl"); cgiEndHTML(); } - else if (!file && (var = cgiGetVariable("PPD_NAME")) == NULL) + else if (!name || !cgiGetVariable("PRINTER_LOCATION")) + { + cgiStartHTML(title); + + if (modify) + { + /* + * Update the location and description of an existing printer... + */ + + if (oldinfo) + cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0); + + cgiCopyTemplateLang("modify-printer.tmpl"); + } + else + { + /* + * Get the name, location, and description for a new printer... + */ + + cgiCopyTemplateLang("add-printer.tmpl"); + } + + cgiEndHTML(); + + if (oldinfo) + ippDelete(oldinfo); + + return; + } + else if (!file && !cgiGetVariable("PPD_NAME")) { if (modify) { @@ -705,6 +991,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ http_status_t get_status; /* Status of GET */ + /* TODO: Use cupsGetFile() API... */ snprintf(uri, sizeof(uri), "/printers/%s.ppd", name); if (httpGet(http, uri)) @@ -719,7 +1006,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ } else if ((fd = cupsTempFd(filename, sizeof(filename))) >= 0) { - while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0) + while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0) write(fd, buffer, bytes); close(fd); @@ -750,39 +1037,6 @@ do_am_printer(http_t *http, /* I - HTTP connection */ strerror(errno)); } } - else if ((uriptr = strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL) - { - /* - * Extract make and make/model from device URI string... - */ - - char make[1024], /* Make string */ - *makeptr; /* Pointer into make */ - - - *uriptr++ = '\0'; - - strlcpy(make, uriptr, sizeof(make)); - - if ((makeptr = strchr(make, ' ')) != NULL) - *makeptr = '\0'; - else if ((makeptr = strchr(make, '-')) != NULL) - *makeptr = '\0'; - else if (!strncasecmp(make, "laserjet", 8) || - !strncasecmp(make, "deskjet", 7) || - !strncasecmp(make, "designjet", 9)) - strcpy(make, "HP"); - else if (!strncasecmp(make, "phaser", 6)) - strcpy(make, "Xerox"); - else if (!strncasecmp(make, "stylus", 6)) - strcpy(make, "Epson"); - else - strcpy(make, "Generic"); - - cgiSetVariable("CURRENT_MAKE", make); - cgiSetVariable("PPD_MAKE", make); - cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr); - } /* * Build a CUPS_GET_PPDS request, which requires the following @@ -798,7 +1052,9 @@ do_am_printer(http_t *http, /* I - HTTP connection */ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "ipp://localhost/printers/"); - if ((var = cgiGetVariable("PPD_MAKE")) != NULL) + if ((var = cgiGetVariable("CURRENT_MAKE")) == NULL) + var = cgiGetVariable("PPD_MAKE"); + if (var) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make", NULL, var); else @@ -815,32 +1071,36 @@ do_am_printer(http_t *http, /* I - HTTP connection */ * Got the list of PPDs, see if the user has selected a make... */ - cgiSetIPPVars(response, NULL, NULL, NULL, 0); - - if (var == NULL) + if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0) { /* - * Let the user choose a make... + * No PPD files with this make, try again with all makes... */ - for (element = 0, attr = response->attrs, last = NULL; - attr != NULL; - attr = attr->next) - if (attr->name && strcmp(attr->name, "ppd-make") == 0) - if (last == NULL || - strcasecmp(last->values[0].string.text, - attr->values[0].string.text) != 0) - { - cgiSetArray("PPD_MAKE", element, attr->values[0].string.text); - element ++; - last = attr; - } + ippDelete(response); + + request = ippNewRequest(CUPS_GET_PPDS); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers/"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "ppd-make"); + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + cgiSetIPPVars(response, NULL, NULL, NULL, 0); cgiStartHTML(title); cgiCopyTemplateLang("choose-make.tmpl"); cgiEndHTML(); } - else + else if (!var || cgiGetVariable("SELECT_MAKE")) + { + cgiStartHTML(title); + cgiCopyTemplateLang("choose-make.tmpl"); + cgiEndHTML(); + } + else { /* * Let the user choose a model... @@ -891,7 +1151,6 @@ do_am_printer(http_t *http, /* I - HTTP connection */ cgiEndHTML(); } - ippDelete(response); } else @@ -921,8 +1180,9 @@ do_am_printer(http_t *http, /* I - HTTP connection */ request = ippNewRequest(CUPS_ADD_PRINTER); - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/printers/%s", cgiGetVariable("PRINTER_NAME")); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, "/printers/%s", + cgiGetVariable("PRINTER_NAME")); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -977,16 +1237,21 @@ do_am_printer(http_t *http, /* I - HTTP connection */ else ippDelete(cupsDoRequest(http, request, "/admin/")); - if (cupsLastError() > IPP_OK_CONFLICT) + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) { cgiStartHTML(title); cgiShowIPPError(modify ? _("Unable to modify printer:") : _("Unable to add printer:")); } - else + else if (modify) { /* - * Redirect successful updates back to the printer or set-options pages... + * Redirect successful updates back to the printer page... */ char refresh[1024]; /* Refresh URL */ @@ -994,21 +1259,24 @@ do_am_printer(http_t *http, /* I - HTTP connection */ cgiFormEncode(uri, name, sizeof(uri)); - if (modify) - snprintf(refresh, sizeof(refresh), - "5;/admin/?OP=redirect&URL=/printers/%s", uri); - else - snprintf(refresh, sizeof(refresh), - "5;/admin/?OP=set-printer-options&PRINTER_NAME=%s", uri); + snprintf(refresh, sizeof(refresh), + "5;/admin/?OP=redirect&URL=/printers/%s", uri); cgiSetVariable("refresh_page", refresh); cgiStartHTML(title); - if (modify) - cgiCopyTemplateLang("printer-modified.tmpl"); - else - cgiCopyTemplateLang("printer-added.tmpl"); + cgiCopyTemplateLang("printer-modified.tmpl"); + } + else + { + /* + * Set the printer options... + */ + + cgiSetVariable("OP", "set-printer-options"); + do_set_options(http, 0); + return; } cgiEndHTML(); @@ -1020,1382 +1288,1152 @@ do_am_printer(http_t *http, /* I - HTTP connection */ /* - * 'do_config_printer()' - Configure the default options for a printer. + * 'do_cancel_subscription()' - Cancel a subscription. */ static void -do_config_printer(http_t *http) /* I - HTTP connection */ +do_cancel_subscription(http_t *http)/* I - HTTP connection */ { - int i, j, k, m; /* Looping vars */ - int have_options; /* Have options? */ - ipp_t *request, /* IPP request */ - *response; /* IPP response */ - ipp_attribute_t *attr; /* IPP attribute */ - char uri[HTTP_MAX_URI]; /* Job URI */ - const char *var; /* Variable value */ - const char *printer; /* Printer printer name */ - const char *filename; /* PPD filename */ - char tempfile[1024]; /* Temporary filename */ - cups_file_t *in, /* Input file */ - *out; /* Output file */ - char line[1024]; /* Line from PPD file */ - char keyword[1024], /* Keyword from Default line */ - *keyptr; /* Pointer into keyword... */ - ppd_file_t *ppd; /* PPD file */ - ppd_group_t *group; /* Option group */ - ppd_option_t *option; /* Option */ - ppd_attr_t *protocol; /* cupsProtocol attribute */ - const char *title; /* Page title */ + ipp_t *request; /* IPP request data */ + const char *var, /* Form variable */ + *user; /* Username */ + int id; /* Subscription ID */ - title = cgiText(_("Set Printer Options")); - /* - * Get the printer name... + * See if we have all of the required information... */ - if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/printers/%s", printer); + if ((var = cgiGetVariable("NOTIFY_SUBSCRIPTION_ID")) != NULL) + id = atoi(var); else + id = 0; + + if (id <= 0) { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); - cgiStartHTML(title); + cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!"))); + cgiStartHTML(_("Cancel RSS Subscription")); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); return; } /* - * Get the PPD file... + * Require a username... */ - if ((filename = cupsGetPPD(printer)) == NULL) + if ((user = getenv("REMOTE_USER")) == NULL) { - cgiStartHTML(title); - cgiShowIPPError(_("Unable to get PPD file!")); - cgiEndHTML(); - return; + puts("Status: 401\n"); + exit(0); } - if ((ppd = ppdOpenFile(filename)) == NULL) - { - cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:"))); - cgiStartHTML(title); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; - } + /* + * Cancel the subscription... + */ - if (cgiGetVariable("job_sheets_start") != NULL || - cgiGetVariable("job_sheets_end") != NULL) - have_options = 1; - else - have_options = 0; + request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION); - ppdMarkDefaults(ppd); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/"); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, + "notify-subscription-id", id); - DEBUG_printf(("

ppd->num_groups = %d\n" - "

    \n", ppd->num_groups)); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, user); - for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) - { - DEBUG_printf(("
  • %s
      \n", group->text)); + ippDelete(cupsDoRequest(http, request, "/")); - for (j = group->num_options, option = group->options; j > 0; j --, option ++) - if ((var = cgiGetVariable(option->keyword)) != NULL) - { - DEBUG_printf(("
    • %s = \"%s\"
    • \n", option->keyword, var)); - have_options = 1; - ppdMarkOption(ppd, option->keyword, var); - } -#ifdef DEBUG - else - printf("
    • %s not defined!
    • \n", option->keyword); -#endif /* DEBUG */ + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) + { + cgiStartHTML(_("Cancel RSS Subscription")); + cgiShowIPPError(_("Unable to cancel RSS subscription:")); + } + else + { + /* + * Redirect successful updates back to the admin page... + */ - DEBUG_puts("
  • "); + cgiSetVariable("refresh_page", "5;URL=/admin"); + cgiStartHTML(_("Cancel RSS Subscription")); + cgiCopyTemplateLang("subscription-canceled.tmpl"); } - DEBUG_printf(("
\n" - "

ppdConflicts(ppd) = %d\n", ppdConflicts(ppd))); + cgiEndHTML(); +} - if (!have_options || ppdConflicts(ppd)) + +/* + * 'do_config_server()' - Configure server settings. + */ + +static void +do_config_server(http_t *http) /* I - HTTP connection */ +{ + if (cgiGetVariable("CHANGESETTINGS")) { /* - * Show the options to the user... + * Save basic setting changes... */ - ppdLocalize(ppd); + int num_settings; /* Number of server settings */ + cups_option_t *settings; /* Server settings */ + const char *debug_logging, /* DEBUG_LOGGING value */ + *remote_admin, /* REMOTE_ADMIN value */ + *remote_any, /* REMOTE_ANY value */ + *remote_printers, + /* REMOTE_PRINTERS value */ + *share_printers,/* SHARE_PRINTERS value */ + *user_cancel_any; + /* USER_CANCEL_ANY value */ +#ifdef HAVE_GSSAPI + char default_auth_type[255]; + /* DefaultAuthType value */ +#endif /* HAVE_GSSAPI */ - cgiStartHTML("Set Printer Options"); - cgiCopyTemplateLang("set-printer-options-header.tmpl"); - if (ppdConflicts(ppd)) - { - for (i = ppd->num_groups, k = 0, group = ppd->groups; i > 0; i --, group ++) - for (j = group->num_options, option = group->options; j > 0; j --, option ++) - if (option->conflicted) - { - cgiSetArray("ckeyword", k, option->keyword); - cgiSetArray("ckeytext", k, option->text); - k ++; - } + /* + * Get the checkbox values from the form... + */ - cgiCopyTemplateLang("option-conflict.tmpl"); - } + debug_logging = cgiGetVariable("DEBUG_LOGGING") ? "1" : "0"; + remote_admin = cgiGetVariable("REMOTE_ADMIN") ? "1" : "0"; + remote_any = cgiGetVariable("REMOTE_ANY") ? "1" : "0"; + remote_printers = cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0"; + share_printers = cgiGetVariable("SHARE_PRINTERS") ? "1" : "0"; + user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0"; - for (i = ppd->num_groups, group = ppd->groups; - i > 0; - i --, group ++) - { - if (!strcmp(group->name, "InstallableOptions")) - cgiSetVariable("GROUP", cgiText(_("Options Installed"))); - else - cgiSetVariable("GROUP", group->text); + /* + * Get the current server settings... + */ - cgiCopyTemplateLang("option-header.tmpl"); - - for (j = group->num_options, option = group->options; - j > 0; - j --, option ++) - { - if (!strcmp(option->keyword, "PageRegion")) - continue; + if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) + { + cgiStartHTML(cgiText(_("Change Settings"))); + cgiSetVariable("MESSAGE", + cgiText(_("Unable to change server settings:"))); + cgiSetVariable("ERROR", cupsLastErrorString()); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } - cgiSetVariable("KEYWORD", option->keyword); - cgiSetVariable("KEYTEXT", option->text); - - if (option->conflicted) - cgiSetVariable("CONFLICTED", "1"); - else - cgiSetVariable("CONFLICTED", "0"); +#ifdef HAVE_GSSAPI + /* + * Get authentication settings... + */ - cgiSetSize("CHOICES", 0); - cgiSetSize("TEXT", 0); - for (k = 0, m = 0; k < option->num_choices; k ++) - { - /* - * Hide custom option values... - */ + if (cgiGetVariable("KERBEROS")) + strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type)); + else + { + const char *val = cupsGetOption("DefaultAuthType", num_settings, + settings); - if (!strcmp(option->choices[k].choice, "Custom")) - continue; + if (val && !strcasecmp(val, "Negotiate")) + strlcpy(default_auth_type, "Basic", sizeof(default_auth_type)); + else + strlcpy(default_auth_type, val, sizeof(default_auth_type)); + } - cgiSetArray("CHOICES", m, option->choices[k].choice); - cgiSetArray("TEXT", m, option->choices[k].text); + fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type); +#endif /* HAVE_GSSAPI */ - m ++; + /* + * See if the settings have changed... + */ - if (option->choices[k].marked) - cgiSetVariable("DEFCHOICE", option->choices[k].choice); - } + if (strcmp(debug_logging, cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, + num_settings, settings)) || + strcmp(remote_admin, cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, + num_settings, settings)) || + strcmp(remote_any, cupsGetOption(CUPS_SERVER_REMOTE_ANY, + num_settings, settings)) || + strcmp(remote_printers, cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, + num_settings, settings)) || + strcmp(share_printers, cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, + num_settings, settings)) || +#ifdef HAVE_GSSAPI + !cupsGetOption("DefaultAuthType", num_settings, settings) || + strcmp(default_auth_type, cupsGetOption("DefaultAuthType", + num_settings, settings)) || +#endif /* HAVE_GSSAPI */ + strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, + num_settings, settings))) + { + /* + * Settings *have* changed, so save the changes... + */ - switch (option->ui) + cupsFreeOptions(num_settings, settings); + + num_settings = 0; + num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, + debug_logging, num_settings, &settings); + num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, + remote_admin, num_settings, &settings); + num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ANY, + remote_any, num_settings, &settings); + num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS, + remote_printers, num_settings, &settings); + num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, + share_printers, num_settings, &settings); + num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, + user_cancel_any, num_settings, &settings); +#ifdef HAVE_GSSAPI + num_settings = cupsAddOption("DefaultAuthType", default_auth_type, + num_settings, &settings); +#endif /* HAVE_GSSAPI */ + + if (!cupsAdminSetServerSettings(http, num_settings, settings)) + { + if (cupsLastError() == IPP_NOT_AUTHORIZED) { - case PPD_UI_BOOLEAN : - cgiCopyTemplateLang("option-boolean.tmpl"); - break; - case PPD_UI_PICKONE : - cgiCopyTemplateLang("option-pickone.tmpl"); - break; - case PPD_UI_PICKMANY : - cgiCopyTemplateLang("option-pickmany.tmpl"); - break; + puts("Status: 401\n"); + exit(0); } + + cgiStartHTML(cgiText(_("Change Settings"))); + cgiSetVariable("MESSAGE", + cgiText(_("Unable to change server settings:"))); + cgiSetVariable("ERROR", cupsLastErrorString()); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); + cgiStartHTML(cgiText(_("Change Settings"))); + cgiCopyTemplateLang("restart.tmpl"); } + } + else + { + /* + * No changes... + */ - cgiCopyTemplateLang("option-trailer.tmpl"); + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); + cgiStartHTML(cgiText(_("Change Settings"))); + cgiCopyTemplateLang("norestart.tmpl"); } + cupsFreeOptions(num_settings, settings); + + cgiEndHTML(); + } + else if (cgiGetVariable("SAVECHANGES") && cgiGetVariable("CUPSDCONF")) + { /* - * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the - * following attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri + * Save hand-edited config file... */ - request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); + http_status_t status; /* PUT status */ + char tempfile[1024]; /* Temporary new cupsd.conf */ + int tempfd; /* Temporary file descriptor */ + cups_file_t *temp; /* Temporary file */ + const char *start, /* Start of line */ + *end; /* End of line */ - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/printers/%s", printer); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); /* - * Do the request and get back a response... + * Create a temporary file for the new cupsd.conf file... */ - if ((response = cupsDoRequest(http, request, "/")) != NULL) + if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) { - if ((attr = ippFindAttribute(response, "job-sheets-supported", - IPP_TAG_ZERO)) != NULL) - { - /* - * Add the job sheets options... - */ - - cgiSetVariable("GROUP", cgiText(_("Banners"))); - cgiCopyTemplateLang("option-header.tmpl"); + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:"))); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(tempfile); + return; + } - cgiSetSize("CHOICES", attr->num_values); - cgiSetSize("TEXT", attr->num_values); - for (k = 0; k < attr->num_values; k ++) - { - cgiSetArray("CHOICES", k, attr->values[k].string.text); - cgiSetArray("TEXT", k, attr->values[k].string.text); - } + if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL) + { + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:"))); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(tempfile); + close(tempfd); + unlink(tempfile); + return; + } - attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO); + /* + * Copy the cupsd.conf text from the form variable... + */ - cgiSetVariable("KEYWORD", "job_sheets_start"); - cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner"))); - cgiSetVariable("DEFCHOICE", attr == NULL ? - "" : attr->values[0].string.text); + start = cgiGetVariable("CUPSDCONF"); + while (start) + { + if ((end = strstr(start, "\r\n")) == NULL) + if ((end = strstr(start, "\n")) == NULL) + end = start + strlen(start); - cgiCopyTemplateLang("option-pickone.tmpl"); + cupsFileWrite(temp, start, end - start); + cupsFilePutChar(temp, '\n'); - cgiSetVariable("KEYWORD", "job_sheets_end"); - cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner"))); - cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ? - "" : attr->values[1].string.text); + if (*end == '\r') + start = end + 2; + else if (*end == '\n') + start = end + 1; + else + start = NULL; + } - cgiCopyTemplateLang("option-pickone.tmpl"); + cupsFileClose(temp); - cgiCopyTemplateLang("option-trailer.tmpl"); - } + /* + * Upload the configuration file to the server... + */ - if (ippFindAttribute(response, "printer-error-policy-supported", - IPP_TAG_ZERO) || - ippFindAttribute(response, "printer-op-policy-supported", - IPP_TAG_ZERO)) - { - /* - * Add the error and operation policy options... - */ + status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); - cgiSetVariable("GROUP", cgiText(_("Policies"))); - cgiCopyTemplateLang("option-header.tmpl"); + if (status == HTTP_UNAUTHORIZED) + { + puts("Status: 401\n"); + unlink(tempfile); + exit(0); + } + else if (status != HTTP_CREATED) + { + cgiSetVariable("MESSAGE", + cgiText(_("Unable to upload cupsd.conf file:"))); + cgiSetVariable("ERROR", httpStatus(status)); - /* - * Error policy... - */ + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); - attr = ippFindAttribute(response, "printer-error-policy-supported", - IPP_TAG_ZERO); - - if (attr) - { - cgiSetSize("CHOICES", attr->num_values); - cgiSetSize("TEXT", attr->num_values); - for (k = 0; k < attr->num_values; k ++) - { - cgiSetArray("CHOICES", k, attr->values[k].string.text); - cgiSetArray("TEXT", k, attr->values[k].string.text); - } - - attr = ippFindAttribute(response, "printer-error-policy", - IPP_TAG_ZERO); - - cgiSetVariable("KEYWORD", "printer_error_policy"); - cgiSetVariable("KEYTEXT", cgiText(_("Error Policy"))); - cgiSetVariable("DEFCHOICE", attr == NULL ? - "" : attr->values[0].string.text); - } - - cgiCopyTemplateLang("option-pickone.tmpl"); - - /* - * Operation policy... - */ - - attr = ippFindAttribute(response, "printer-op-policy-supported", - IPP_TAG_ZERO); - - if (attr) - { - cgiSetSize("CHOICES", attr->num_values); - cgiSetSize("TEXT", attr->num_values); - for (k = 0; k < attr->num_values; k ++) - { - cgiSetArray("CHOICES", k, attr->values[k].string.text); - cgiSetArray("TEXT", k, attr->values[k].string.text); - } - - attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO); - - cgiSetVariable("KEYWORD", "printer_op_policy"); - cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy"))); - cgiSetVariable("DEFCHOICE", attr == NULL ? - "" : attr->values[0].string.text); + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiCopyTemplateLang("restart.tmpl"); + } - cgiCopyTemplateLang("option-pickone.tmpl"); - } + cgiEndHTML(); - cgiCopyTemplateLang("option-trailer.tmpl"); - } + unlink(tempfile); + } + else + { + struct stat info; /* cupsd.conf information */ + cups_file_t *cupsd; /* cupsd.conf file */ + char *buffer, /* Buffer for entire file */ + *bufptr, /* Pointer into buffer */ + *bufend; /* End of buffer */ + int ch; /* Character from file */ + char filename[1024]; /* Filename */ + const char *server_root; /* Location of config files */ - ippDelete(response); - } /* - * Binary protocol support... + * Locate the cupsd.conf file... */ - if (ppd->protocols && strstr(ppd->protocols, "BCP")) - { - protocol = ppdFindAttr(ppd, "cupsProtocol", NULL); - - cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol"))); - cgiCopyTemplateLang("option-header.tmpl"); - - cgiSetSize("CHOICES", 2); - cgiSetSize("TEXT", 2); - cgiSetArray("CHOICES", 0, "None"); - cgiSetArray("TEXT", 0, cgiText(_("None"))); - - if (strstr(ppd->protocols, "TBCP")) - { - cgiSetArray("CHOICES", 1, "TBCP"); - cgiSetArray("TEXT", 1, "TBCP"); - } - else - { - cgiSetArray("CHOICES", 1, "BCP"); - cgiSetArray("TEXT", 1, "BCP"); - } - - cgiSetVariable("KEYWORD", "protocol"); - cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol"))); - cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None"); - - cgiCopyTemplateLang("option-pickone.tmpl"); + if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) + server_root = CUPS_SERVERROOT; - cgiCopyTemplateLang("option-trailer.tmpl"); - } + snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root); - cgiCopyTemplateLang("set-printer-options-trailer.tmpl"); - cgiEndHTML(); - } - else - { /* - * Set default options... + * Figure out the size... */ - out = cupsTempFile2(tempfile, sizeof(tempfile)); - in = cupsFileOpen(filename, "r"); - - if (!in || !out) + if (stat(filename, &info)) { + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiSetVariable("MESSAGE", + cgiText(_("Unable to access cupsd.conf file:"))); cgiSetVariable("ERROR", strerror(errno)); - cgiStartHTML("Set Printer Options"); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); - if (in) - cupsFileClose(in); - - if (out) - { - cupsFileClose(out); - unlink(tempfile); - } - - unlink(filename); + perror(filename); return; } - while (cupsFileGets(in, line, sizeof(line))) + if (info.st_size > (1024 * 1024)) { - if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol")) - continue; - else if (strncmp(line, "*Default", 8)) - cupsFilePrintf(out, "%s\n", line); - else - { - /* - * Get default option name... - */ + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiSetVariable("MESSAGE", + cgiText(_("Unable to access cupsd.conf file:"))); + cgiSetVariable("ERROR", + cgiText(_("Unable to edit cupsd.conf files larger than " + "1MB!"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); - strlcpy(keyword, line + 8, sizeof(keyword)); + fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename, + (long)info.st_size); + return; + } - for (keyptr = keyword; *keyptr; keyptr ++) - if (*keyptr == ':' || isspace(*keyptr & 255)) - break; + /* + * Open the cupsd.conf file... + */ - *keyptr = '\0'; + if ((cupsd = cupsFileOpen(filename, "r")) == NULL) + { + /* + * Unable to open - log an error... + */ - if (!strcmp(keyword, "PageRegion")) - var = cgiGetVariable("PageSize"); - else - var = cgiGetVariable(keyword); + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiSetVariable("MESSAGE", + cgiText(_("Unable to access cupsd.conf file:"))); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); - if (var != NULL) - cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); - else - cupsFilePrintf(out, "%s\n", line); - } + perror(filename); + return; } - if ((var = cgiGetVariable("protocol")) != NULL) - cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol")); - - cupsFileClose(in); - cupsFileClose(out); - /* - * Build a CUPS_ADD_PRINTER request, which requires the following - * attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri - * job-sheets-default - * [ppd file] + * Allocate memory and load the file into a string buffer... */ - request = ippNewRequest(CUPS_ADD_PRINTER); - - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/printers/%s", cgiGetVariable("PRINTER_NAME")); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); - - attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, - "job-sheets-default", 2, NULL, NULL); - attr->values[0].string.text = strdup(cgiGetVariable("job_sheets_start")); - attr->values[1].string.text = strdup(cgiGetVariable("job_sheets_end")); - - if ((var = cgiGetVariable("printer_error_policy")) != NULL) - attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, - "printer-error-policy", NULL, var); + if ((buffer = calloc(1, info.st_size + 1)) != NULL) + { + cupsFileRead(cupsd, buffer, info.st_size); + cgiSetVariable("CUPSDCONF", buffer); + free(buffer); + } - if ((var = cgiGetVariable("printer_op_policy")) != NULL) - attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, - "printer-op-policy", NULL, var); + cupsFileClose(cupsd); /* - * Do the request and get back a response... + * Then get the default cupsd.conf file and put that into a string as + * well... */ - ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile)); + strlcat(filename, ".default", sizeof(filename)); - if (cupsLastError() > IPP_OK_CONFLICT) - { - cgiStartHTML(title); - cgiShowIPPError(_("Unable to set options:")); - } - else + if (!stat(filename, &info) && info.st_size < (1024 * 1024) && + (cupsd = cupsFileOpen(filename, "r")) != NULL) { - /* - * Redirect successful updates back to the printer page... - */ - - char refresh[1024]; /* Refresh URL */ + if ((buffer = calloc(1, 2 * info.st_size + 1)) != NULL) + { + bufend = buffer + 2 * info.st_size - 1; + for (bufptr = buffer; + bufptr < bufend && (ch = cupsFileGetChar(cupsd)) != EOF;) + { + if (ch == '\\' || ch == '\"') + { + *bufptr++ = '\\'; + *bufptr++ = ch; + } + else if (ch == '\n') + { + *bufptr++ = '\\'; + *bufptr++ = 'n'; + } + else if (ch == '\t') + { + *bufptr++ = '\\'; + *bufptr++ = 't'; + } + else if (ch >= ' ') + *bufptr++ = ch; + } - cgiFormEncode(uri, printer, sizeof(uri)); - snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=/printers/%s", - uri); - cgiSetVariable("refresh_page", refresh); + *bufptr = '\0'; - cgiStartHTML(title); + cgiSetVariable("CUPSDCONF_DEFAULT", buffer); + free(buffer); + } - cgiCopyTemplateLang("printer-configured.tmpl"); + cupsFileClose(cupsd); } - cgiEndHTML(); + /* + * Show the current config file... + */ - unlink(tempfile); - } + cgiStartHTML(cgiText(_("Edit Configuration File"))); + + cgiCopyTemplateLang("edit-config.tmpl"); - unlink(filename); + cgiEndHTML(); + } } /* - * 'do_config_server()' - Configure server settings. + * 'do_delete_class()' - Delete a class. */ static void -do_config_server(http_t *http) /* I - HTTP connection */ +do_delete_class(http_t *http) /* I - HTTP connection */ { - if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF")) - { - /* - * Save basic setting changes... - */ + ipp_t *request; /* IPP request */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *pclass; /* Printer class name */ - http_status_t status; /* PUT status */ - cups_file_t *cupsd; /* cupsd.conf file */ - char tempfile[1024]; /* Temporary new cupsd.conf */ - int tempfd; /* Temporary file descriptor */ - cups_file_t *temp; /* Temporary file */ - char line[1024], /* Line from cupsd.conf file */ - *value; /* Value on line */ - const char *server_root; /* Location of config files */ - int linenum, /* Line number in file */ - in_policy, /* In a policy section? */ - in_cancel_job, /* In a cancel-job section? */ - in_admin_location, /* In the /admin location? */ - in_conf_location, /* In the /admin/conf location? */ - in_root_location; /* In the / location? */ - int remote_printers, /* Show remote printers */ - share_printers, /* Share local printers */ - remote_admin, /* Remote administration allowed? */ - user_cancel_any, /* Cancel-job policy set? */ - debug_logging; /* LogLevel debug set? */ - int wrote_port_listen, /* Wrote the port/listen lines? */ - wrote_browsing, /* Wrote the browsing lines? */ - wrote_policy, /* Wrote the policy? */ - wrote_loglevel, /* Wrote the LogLevel line? */ - wrote_admin_location, /* Wrote the /admin location? */ - wrote_conf_location, /* Wrote the /admin/conf location? */ - wrote_root_location; /* Wrote the / location? */ - int indent; /* Indentation */ + /* + * Get form variables... + */ - /* - * Get form variables... - */ + if (cgiGetVariable("CONFIRM") == NULL) + { + cgiStartHTML(cgiText(_("Delete Class"))); + cgiCopyTemplateLang("class-confirm.tmpl"); + cgiEndHTML(); + return; + } - remote_printers = cgiGetVariable("REMOTE_PRINTERS") != NULL; - share_printers = cgiGetVariable("SHARE_PRINTERS") != NULL; - remote_admin = cgiGetVariable("REMOTE_ADMIN") != NULL; - user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") != NULL; - debug_logging = cgiGetVariable("DEBUG_LOGGING") != NULL; + if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, "/classes/%s", pclass); + else + { + cgiStartHTML(cgiText(_("Delete Class"))); + cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } - /* - * Locate the cupsd.conf file... - */ + /* + * Build a CUPS_DELETE_CLASS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ - if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) - server_root = CUPS_SERVERROOT; + request = ippNewRequest(CUPS_DELETE_CLASS); - snprintf(line, sizeof(line), "%s/cupsd.conf", server_root); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); - /* - * Open the cupsd.conf file... - */ + /* + * Do the request and get back a response... + */ - if ((cupsd = cupsFileOpen(line, "r")) == NULL) - { - /* - * Unable to open - log an error... - */ + ippDelete(cupsDoRequest(http, request, "/admin/")); - cgiStartHTML(cgiText(_("Change Settings"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to change server settings:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - - perror(line); - return; - } + /* + * Show the results... + */ + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() <= IPP_OK_CONFLICT) + { /* - * Create a temporary file for the new cupsd.conf file... + * Redirect successful updates back to the classes page... */ - if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) - { - cgiStartHTML(cgiText(_("Change Settings"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to change server settings:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - - perror(tempfile); - cupsFileClose(cupsd); - return; - } - - if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL) - { - cgiStartHTML(cgiText(_("Change Settings"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to change server settings:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - - perror(tempfile); - close(tempfd); - unlink(tempfile); - cupsFileClose(cupsd); - return; - } - - /* - * Copy the old file to the new, making changes along the way... - */ + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes"); + } - in_admin_location = 0; - in_cancel_job = 0; - in_conf_location = 0; - in_policy = 0; - in_root_location = 0; - linenum = 0; - wrote_admin_location = 0; - wrote_browsing = 0; - wrote_conf_location = 0; - wrote_loglevel = 0; - wrote_policy = 0; - wrote_port_listen = 0; - wrote_root_location = 0; - indent = 0; - - while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) - { - if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen")) - { - if (!wrote_port_listen) - { - wrote_port_listen = 1; + cgiStartHTML(cgiText(_("Delete Class"))); - if (share_printers || remote_admin) - { - cupsFilePuts(temp, "# Allow remote access\n"); - cupsFilePrintf(temp, "Listen *:%d\n", ippPort()); - } - else - { - cupsFilePuts(temp, "# Only listen for connections from the local machine.\n"); - cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort()); - } + if (cupsLastError() > IPP_OK_CONFLICT) + cgiShowIPPError(_("Unable to delete class:")); + else + cgiCopyTemplateLang("class-deleted.tmpl"); -#ifdef CUPS_DEFAULT_DOMAINSOCKET - cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); -#endif /* CUPS_DEFAULT_DOMAINSOCKET */ - } - } - else if (!strcasecmp(line, "Browsing") || - !strcasecmp(line, "BrowseAddress") || - !strcasecmp(line, "BrowseAllow") || - !strcasecmp(line, "BrowseDeny") || - !strcasecmp(line, "BrowseOrder")) - { - if (!wrote_browsing) - { - wrote_browsing = 1; + cgiEndHTML(); +} - if (remote_printers || share_printers) - { - if (remote_printers && share_printers) - cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n"); - else if (remote_printers) - cupsFilePuts(temp, "# Show shared printers on the local network.\n"); - else - cupsFilePuts(temp, "# Share local printers on the local network.\n"); - cupsFilePuts(temp, "Browsing On\n"); - cupsFilePuts(temp, "BrowseOrder allow,deny\n"); +/* + * 'do_delete_printer()' - Delete a printer. + */ - if (remote_printers) - cupsFilePuts(temp, "BrowseAllow @LOCAL\n"); +static void +do_delete_printer(http_t *http) /* I - HTTP connection */ +{ + ipp_t *request; /* IPP request */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *printer; /* Printer printer name */ - if (share_printers) - cupsFilePuts(temp, "BrowseAddress @LOCAL\n"); - } - else - { - cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n"); - cupsFilePuts(temp, "Browsing Off\n"); - } - } - } - else if (!strcasecmp(line, "LogLevel")) - { - wrote_loglevel = 1; - if (debug_logging) - { - cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); - cupsFilePuts(temp, "LogLevel debug\n"); - } - else - { - cupsFilePuts(temp, "# Show general information in error_log.\n"); - cupsFilePuts(temp, "LogLevel info\n"); - } - } - else if (!strcasecmp(line, "\n", line, value); - indent += 2; - } - else if (!strcasecmp(line, "")) - { - indent -= 2; - if (!wrote_policy) - { - wrote_policy = 1; - - if (!user_cancel_any) - cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n" - " \n" - " Order deny,allow\n" - " Allow @SYSTEM\n" - " Allow @OWNER\n" - " \n"); - } + if (cgiGetVariable("CONFIRM") == NULL) + { + cgiStartHTML(cgiText(_("Delete Printer"))); + cgiCopyTemplateLang("printer-confirm.tmpl"); + cgiEndHTML(); + return; + } - in_policy = 0; + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, "/printers/%s", printer); + else + { + cgiStartHTML(cgiText(_("Delete Printer"))); + cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } - cupsFilePuts(temp, "\n"); - } - else if (!strcasecmp(line, "\n", line, value); - } - else if (!strcasecmp(line, "")) - { - indent -= 2; - if (in_admin_location) - { - wrote_admin_location = 1; + /* + * Build a CUPS_DELETE_PRINTER request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ - if (remote_admin) - cupsFilePuts(temp, " # Allow remote administration...\n"); - else - cupsFilePuts(temp, " # Restrict access to the admin pages...\n"); + request = ippNewRequest(CUPS_DELETE_PRINTER); - cupsFilePuts(temp, " Order allow,deny\n"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); - if (remote_admin) - cupsFilePuts(temp, " Allow @LOCAL\n"); - else - cupsFilePuts(temp, " Allow localhost\n"); - } - else if (in_conf_location) - { - wrote_conf_location = 1; + /* + * Do the request and get back a response... + */ - if (remote_admin) - cupsFilePuts(temp, " # Allow remote access to the configuration files...\n"); - else - cupsFilePuts(temp, " # Restrict access to the configuration files...\n"); + ippDelete(cupsDoRequest(http, request, "/admin/")); - cupsFilePuts(temp, " Order allow,deny\n"); + /* + * Show the results... + */ - if (remote_admin) - cupsFilePuts(temp, " Allow @LOCAL\n"); - else - cupsFilePuts(temp, " Allow localhost\n"); - } - else if (in_root_location) - { - wrote_root_location = 1; - - if (remote_admin && share_printers) - cupsFilePuts(temp, " # Allow shared printing and remote administration...\n"); - else if (remote_admin) - cupsFilePuts(temp, " # Allow remote administration...\n"); - else if (share_printers) - cupsFilePuts(temp, " # Allow shared printing...\n"); - else - cupsFilePuts(temp, " # Restrict access to the server...\n"); + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() <= IPP_OK_CONFLICT) + { + /* + * Redirect successful updates back to the printers page... + */ - cupsFilePuts(temp, " Order allow,deny\n"); + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers"); + } - if (remote_admin || share_printers) - cupsFilePuts(temp, " Allow @LOCAL\n"); - else - cupsFilePuts(temp, " Allow localhost\n"); - } + cgiStartHTML(cgiText(_("Delete Printer"))); - in_admin_location = 0; - in_conf_location = 0; - in_root_location = 0; + if (cupsLastError() > IPP_OK_CONFLICT) + cgiShowIPPError(_("Unable to delete printer:")); + else + cgiCopyTemplateLang("printer-deleted.tmpl"); - cupsFilePuts(temp, "\n"); - } - else if (!strcasecmp(line, "\n"); - } - } - else if (!strcasecmp(line, "") && in_cancel_job) - { - indent -= 2; + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, + "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE | + CUPS_PRINTER_IMPLICIT); - if (in_cancel_job == 1) - cupsFilePuts(temp, " \n"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "printer-name"); - wrote_policy = 1; + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + ippDelete(response); - if (!user_cancel_any) - cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n" - " \n" - " Order deny,allow\n" - " Require user @OWNER @SYSTEM\n" - " \n"); + if (!export_all) + { + printer_count = cgiGetSize("PRINTER_NAME"); - in_cancel_job = 0; - } - else if ((in_admin_location || in_conf_location || in_root_location) && - (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny") || - !strcasecmp(line, "Order"))) - continue; - else if (in_cancel_job == 2) - continue; - else if (!strcasecmp(line, "\n", line, value); - else if (line[0] == '<') + for (i = 0; i < printer_count; i ++) { - if (value) - { - cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); - indent += 2; - } - else - { - if (line[1] == '/') - indent -= 2; + dest = cgiGetArray("PRINTER_NAME", i); - cupsFilePrintf(temp, "%*s%s\n", indent, "", line); - } + for (j = 0; j < export_count; j ++) + if (!strcasecmp(dest, cgiGetArray("EXPORT_NAME", j))) + break; + + cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : ""); } - else if (value) - cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value); - else - cupsFilePrintf(temp, "%*s%s\n", indent, "", line); } + } + /* + * Export or get the printers to export... + */ + + if (username && *username && password && *password && + (export_all || export_count > 0)) + { /* - * Write any missing info... + * Do export... */ - if (!wrote_browsing) + fputs("DEBUG: Export printers...\n", stderr); + + if (export_all) { - if (remote_printers || share_printers) - { - if (remote_printers && share_printers) - cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n"); - else if (remote_printers) - cupsFilePuts(temp, "# Show shared printers on the local network.\n"); - else - cupsFilePuts(temp, "# Share local printers on the local network.\n"); + name = "PRINTER_NAME"; + export_count = cgiGetSize("PRINTER_NAME"); + } + else + name = "EXPORT_NAME"; - cupsFilePuts(temp, "Browsing On\n"); - cupsFilePuts(temp, "BrowseOrder allow,deny\n"); + for (i = 0; i < export_count; i ++) + { + dest = cgiGetArray(name, i); - if (remote_printers) - cupsFilePuts(temp, "BrowseAllow @LOCAL\n"); + if (!cupsAdminCreateWindowsPPD(http, dest, ppd, sizeof(ppd))) + break; - if (share_printers) - cupsFilePuts(temp, "BrowseAddress @LOCAL\n"); - } - else - { - cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n"); - cupsFilePuts(temp, "Browsing Off\n"); - } - } + j = cupsAdminExportSamba(dest, ppd, "localhost", username, password, + stderr); - if (!wrote_loglevel) - { - if (debug_logging) - { - cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); - cupsFilePuts(temp, "LogLevel debug\n"); - } - else - { - cupsFilePuts(temp, "# Show general information in error_log.\n"); - cupsFilePuts(temp, "LogLevel info\n"); - } - } - - if (!wrote_port_listen) - { - if (share_printers || remote_admin) - { - cupsFilePuts(temp, "# Allow remote access\n"); - cupsFilePrintf(temp, "Listen *:%d\n", ippPort()); - } - else - { - cupsFilePuts(temp, "# Only listen for connections from the local machine.\n"); - cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort()); - } - -#ifdef CUPS_DEFAULT_DOMAINSOCKET - cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); -#endif /* CUPS_DEFAULT_DOMAINSOCKET */ - } - - if (!wrote_root_location) - { - if (remote_admin && share_printers) - cupsFilePuts(temp, "# Allow shared printing and remote administration...\n"); - else if (remote_admin) - cupsFilePuts(temp, "# Allow remote administration...\n"); - else if (share_printers) - cupsFilePuts(temp, "# Allow shared printing...\n"); - else - cupsFilePuts(temp, "# Restrict access to the server...\n"); - - cupsFilePuts(temp, "\n" - " Order allow,deny\n"); - - if (remote_admin || share_printers) - cupsFilePuts(temp, " Allow @LOCAL\n"); - else - cupsFilePuts(temp, " Allow localhost\n"); + unlink(ppd); - cupsFilePuts(temp, "\n"); + if (!j) + break; } - if (!wrote_admin_location) + if (i < export_count) + cgiSetVariable("ERROR", cupsLastErrorString()); + else { - if (remote_admin) - cupsFilePuts(temp, "# Allow remote administration...\n"); - else - cupsFilePuts(temp, "# Restrict access to the admin pages...\n"); - - cupsFilePuts(temp, "\n" - " Order allow,deny\n"); - - if (remote_admin) - cupsFilePuts(temp, " Allow @LOCAL\n"); - else - cupsFilePuts(temp, " Allow localhost\n"); - - cupsFilePuts(temp, "\n"); + cgiStartHTML(cgiText(_("Export Printers to Samba"))); + cgiCopyTemplateLang("samba-exported.tmpl"); + cgiEndHTML(); + return; } + } + else if (username && !*username) + cgiSetVariable("ERROR", + cgiText(_("A Samba username is required to export " + "printer drivers!"))); + else if (username && (!password || !*password)) + cgiSetVariable("ERROR", + cgiText(_("A Samba password is required to export " + "printer drivers!"))); - if (!wrote_conf_location) - { - if (remote_admin) - cupsFilePuts(temp, "# Allow remote access to the configuration files...\n"); - else - cupsFilePuts(temp, "# Restrict access to the configuration files...\n"); + /* + * Show form... + */ - cupsFilePuts(temp, "\n" - " AuthType Basic\n" - " Require user @SYSTEM\n" - " Order allow,deny\n"); + cgiStartHTML(cgiText(_("Export Printers to Samba"))); + cgiCopyTemplateLang("samba-export.tmpl"); + cgiEndHTML(); +} - if (remote_admin) - cupsFilePuts(temp, " Allow @LOCAL\n"); - else - cupsFilePuts(temp, " Allow localhost\n"); - cupsFilePuts(temp, "\n"); - } +/* + * 'do_list_printers()' - List available printers. + */ - if (!wrote_policy) - { - cupsFilePuts(temp, "\n" - " # Job-related operations must be done by the owner or an adminstrator...\n" - " \n" - " Require user @OWNER @SYSTEM\n" - " Order deny,allow\n" - " \n" - " # All administration operations require an adminstrator to authenticate...\n" - " \n" - " AuthType Basic\n" - " Require user @SYSTEM\n" - " Order deny,allow\n" - "\n"); - - if (!user_cancel_any) - cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n" - " \n" - " Require user @OWNER @SYSTEM\n" - " Order deny,allow\n" - " \n"); - - cupsFilePuts(temp, " \n" - " Order deny,allow\n" - " \n" - "\n"); - } +static void +do_list_printers(http_t *http) /* I - HTTP connection */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ - cupsFileClose(cupsd); - cupsFileClose(temp); - /* - * Upload the configuration file to the server... - */ + cgiStartHTML(cgiText(_("List Available Printers"))); + fflush(stdout); - status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); + /* + * Get the list of printers and their devices... + */ - if (status != HTTP_CREATED) - { - cgiSetVariable("MESSAGE", cgiText(_("Unable to upload cupsd.conf file:"))); - cgiSetVariable("ERROR", httpStatus(status)); - cgiStartHTML(cgiText(_("Change Settings"))); - cgiCopyTemplateLang("error.tmpl"); - } - else - { - cgiSetVariable("refresh_page", "5;/admin/?OP=redirect"); + request = ippNewRequest(CUPS_GET_PRINTERS); - cgiStartHTML(cgiText(_("Change Settings"))); - cgiCopyTemplateLang("restart.tmpl"); - } + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "device-uri"); - cgiEndHTML(); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", + CUPS_PRINTER_LOCAL); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", + CUPS_PRINTER_LOCAL); - unlink(tempfile); - } - else if (cgiIsPOST()) + if ((response = cupsDoRequest(http, request, "/")) != NULL) { /* - * Save hand-edited config file... + * Got the printer list, now load the devices... */ - http_status_t status; /* PUT status */ - char tempfile[1024]; /* Temporary new cupsd.conf */ - int tempfd; /* Temporary file descriptor */ - cups_file_t *temp; /* Temporary file */ - const char *start, /* Start of line */ - *end; /* End of line */ + int i; /* Looping var */ + cups_array_t *printer_devices; /* Printer devices for local printers */ + char *printer_device; /* Current printer device */ /* - * Create a temporary file for the new cupsd.conf file... + * Allocate an array and copy the device strings... */ - if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) - { - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - - perror(tempfile); - return; - } + printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL); - if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL) + for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI); + attr; + attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI)) { - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - - perror(tempfile); - close(tempfd); - unlink(tempfile); - return; + cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text)); } /* - * Copy the cupsd.conf text from the form variable... + * Free the printer list and get the device list... */ - start = cgiGetVariable("CUPSDCONF"); - while (start) - { - if ((end = strstr(start, "\r\n")) == NULL) - if ((end = strstr(start, "\n")) == NULL) - end = start + strlen(start); - - cupsFileWrite(temp, start, end - start); - cupsFilePutChar(temp, '\n'); + ippDelete(response); - if (*end == '\r') - start = end + 2; - else if (*end == '\n') - start = end + 1; - else - start = NULL; - } + request = ippNewRequest(CUPS_GET_DEVICES); - cupsFileClose(temp); + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Got the device list, let's parse it... + */ - /* - * Upload the configuration file to the server... - */ + const char *device_uri, /* device-uri attribute value */ + *device_make_and_model, /* device-make-and-model value */ + *device_info; /* device-info value */ - status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); - if (status != HTTP_CREATED) - { - cgiSetVariable("MESSAGE", cgiText(_("Unable to upload cupsd.conf file:"))); - cgiSetVariable("ERROR", httpStatus(status)); + for (i = 0, attr = response->attrs; attr; attr = attr->next) + { + /* + * Skip leading attributes until we hit a device... + */ - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiCopyTemplateLang("error.tmpl"); - } - else - { - cgiSetVariable("refresh_page", "5;/admin/?OP=redirect"); + while (attr && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiCopyTemplateLang("restart.tmpl"); - } + if (!attr) + break; - cgiEndHTML(); + /* + * Pull the needed attributes from this device... + */ - unlink(tempfile); - } - else - { - struct stat info; /* cupsd.conf information */ - cups_file_t *cupsd; /* cupsd.conf file */ - char *buffer; /* Buffer for entire file */ - char filename[1024]; /* Filename */ - const char *server_root; /* Location of config files */ + device_info = NULL; + device_make_and_model = NULL; + device_uri = NULL; + while (attr && attr->group_tag == IPP_TAG_PRINTER) + { + if (!strcmp(attr->name, "device-info") && + attr->value_tag == IPP_TAG_TEXT) + device_info = attr->values[0].string.text; - /* - * Locate the cupsd.conf file... - */ + if (!strcmp(attr->name, "device-make-and-model") && + attr->value_tag == IPP_TAG_TEXT) + device_make_and_model = attr->values[0].string.text; - if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) - server_root = CUPS_SERVERROOT; + if (!strcmp(attr->name, "device-uri") && + attr->value_tag == IPP_TAG_URI) + device_uri = attr->values[0].string.text; - snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root); + attr = attr->next; + } - /* - * Figure out the size... - */ + /* + * See if we have everything needed... + */ - if (stat(filename, &info)) - { - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); + if (device_info && device_make_and_model && device_uri && + strcasecmp(device_make_and_model, "unknown") && + strchr(device_uri, ':')) + { + /* + * Yes, now see if there is already a printer for this + * device... + */ - perror(filename); - return; - } + if (!cupsArrayFind(printer_devices, (void *)device_uri)) + { + /* + * Not found, so it must be a new printer... + */ - if (info.st_size > (1024 * 1024)) - { - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:"))); - cgiSetVariable("ERROR", - cgiText(_("Unable to edit cupsd.conf files larger than " - "1MB!"))); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); + char option[1024], /* Form variables for this device */ + *option_ptr; /* Pointer into string */ + const char *ptr; /* Pointer into device string */ - fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename, - (long)info.st_size); - return; - } - /* - * Open the cupsd.conf file... - */ - - if ((cupsd = cupsFileOpen(filename, "r")) == NULL) - { - /* - * Unable to open - log an error... - */ + /* + * Format the printer name variable for this device... + * + * We use the device-info string first, then device-uri, + * and finally device-make-and-model to come up with a + * suitable name. + */ - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to access cupsd.conf file:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); + if (strncasecmp(device_info, "unknown", 7)) + ptr = device_info; + else if ((ptr = strstr(device_uri, "://")) != NULL) + ptr += 3; + else + ptr = device_make_and_model; - perror(filename); - return; - } + for (option_ptr = option; + option_ptr < (option + sizeof(option) - 1) && *ptr; + ptr ++) + if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || + *ptr == '.') + *option_ptr++ = *ptr; + else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_') + *option_ptr++ = '_'; + else if (*ptr == '?' || *ptr == '(') + break; - /* - * Allocate memory and load the file into a string buffer... - */ + *option_ptr = '\0'; - buffer = calloc(1, info.st_size + 1); + cgiSetArray("TEMPLATE_NAME", i, option); - cupsFileRead(cupsd, buffer, info.st_size); - cupsFileClose(cupsd); + /* + * Finally, set the form variables for this printer... + */ - cgiSetVariable("CUPSDCONF", buffer); - free(buffer); + cgiSetArray("device_info", i, device_info); + cgiSetArray("device_make_and_model", i, device_make_and_model); + cgiSetArray("device_uri", i, device_uri); + i ++; + } + } - /* - * Show the current config file... - */ + if (!attr) + break; + } - cgiStartHTML("Edit Configuration File"); + ippDelete(response); - printf("\n", filename); + /* + * Free the device list... + */ - cgiCopyTemplateLang("edit-config.tmpl"); + for (printer_device = (char *)cupsArrayFirst(printer_devices); + printer_device; + printer_device = (char *)cupsArrayNext(printer_devices)) + free(printer_device); - cgiEndHTML(); + cupsArrayDelete(printer_devices); + } } + + /* + * Finally, show the printer list... + */ + + cgiCopyTemplateLang("list-available-printers.tmpl"); + + cgiEndHTML(); } /* - * 'do_delete_class()' - Delete a class... + * 'do_menu()' - Show the main menu. */ static void -do_delete_class(http_t *http) /* I - HTTP connection */ +do_menu(http_t *http) /* I - HTTP connection */ { - ipp_t *request; /* IPP request */ - char uri[HTTP_MAX_URI]; /* Job URI */ - const char *pclass; /* Printer class name */ + int num_settings; /* Number of server settings */ + cups_option_t *settings; /* Server settings */ + const char *val; /* Setting value */ + char filename[1024]; /* Temporary filename */ + const char *datadir; /* Location of data files */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ - cgiStartHTML(cgiText(_("Delete Class"))); + /* + * Get the current server settings... + */ - if (cgiGetVariable("CONFIRM") == NULL) + if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) { - cgiCopyTemplateLang("class-confirm.tmpl"); - cgiEndHTML(); - return; + cgiSetVariable("SETTINGS_MESSAGE", + cgiText(_("Unable to open cupsd.conf file:"))); + cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString()); } - if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL) - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/classes/%s", pclass); - else + if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings, + settings)) != NULL && atoi(val)) + cgiSetVariable("DEBUG_LOGGING", "CHECKED"); + + if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings, + settings)) != NULL && atoi(val)) + cgiSetVariable("REMOTE_ADMIN", "CHECKED"); + + if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ANY, num_settings, + settings)) != NULL && atoi(val)) + cgiSetVariable("REMOTE_ANY", "CHECKED"); + + if ((val = cupsGetOption(CUPS_SERVER_REMOTE_PRINTERS, num_settings, + settings)) != NULL && atoi(val)) + cgiSetVariable("REMOTE_PRINTERS", "CHECKED"); + + if ((val = cupsGetOption(CUPS_SERVER_SHARE_PRINTERS, num_settings, + settings)) != NULL && atoi(val)) + cgiSetVariable("SHARE_PRINTERS", "CHECKED"); + + if ((val = cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, num_settings, + settings)) != NULL && atoi(val)) + cgiSetVariable("USER_CANCEL_ANY", "CHECKED"); + +#ifdef HAVE_GSSAPI + cgiSetVariable("HAVE_GSSAPI", "1"); + + if ((val = cupsGetOption("DefaultAuthType", num_settings, + settings)) != NULL && !strcasecmp(val, "Negotiate")) + cgiSetVariable("KERBEROS", "CHECKED"); +#endif /* HAVE_GSSAPI */ + + cupsFreeOptions(num_settings, settings); + + /* + * See if Samba and the Windows drivers are installed... + */ + + if ((datadir = getenv("CUPS_DATADIR")) == NULL) + datadir = CUPS_DATADIR; + + snprintf(filename, sizeof(filename), "%s/drivers/pscript5.dll", datadir); + if (!access(filename, R_OK)) { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; + /* + * Found Windows 2000 driver file, see if we have smbclient and + * rpcclient... + */ + + if (cupsFileFind("smbclient", getenv("PATH"), 1, filename, + sizeof(filename)) && + cupsFileFind("rpcclient", getenv("PATH"), 1, filename, + sizeof(filename))) + cgiSetVariable("HAVE_SAMBA", "Y"); + else + { + if (!cupsFileFind("smbclient", getenv("PATH"), 1, filename, + sizeof(filename))) + fputs("ERROR: smbclient not found!\n", stderr); + + if (!cupsFileFind("rpcclient", getenv("PATH"), 1, filename, + sizeof(filename))) + fputs("ERROR: rpcclient not found!\n", stderr); + } } + else + perror(filename); /* - * Build a CUPS_DELETE_CLASS request, which requires the following - * attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri + * Subscriptions... */ - request = ippNewRequest(CUPS_DELETE_CLASS); + request = ippNewRequest(IPP_GET_SUBSCRIPTIONS); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + NULL, "ipp://localhost/"); + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + ippDelete(response); + } /* - * Do the request and get back a response... + * Finally, show the main menu template... */ - ippDelete(cupsDoRequest(http, request, "/admin/")); + cgiStartHTML(cgiText(_("Administration"))); - if (cupsLastError() > IPP_OK_CONFLICT) - cgiShowIPPError(_("Unable to delete class:")); - else - cgiCopyTemplateLang("class-deleted.tmpl"); + cgiCopyTemplateLang("admin.tmpl"); cgiEndHTML(); } /* - * 'do_delete_printer()' - Delete a printer... + * 'do_printer_op()' - Do a printer operation. */ static void -do_delete_printer(http_t *http) /* I - HTTP connection */ +do_printer_op(http_t *http, /* I - HTTP connection */ + ipp_op_t op, /* I - Operation to perform */ + const char *title) /* I - Title of page */ { ipp_t *request; /* IPP request */ - char uri[HTTP_MAX_URI]; /* Job URI */ - const char *printer; /* Printer printer name */ - + char uri[HTTP_MAX_URI]; /* Printer URI */ + const char *printer, /* Printer name (purge-jobs) */ + *is_class; /* Is a class? */ - cgiStartHTML(cgiText(_("Delete Printer"))); - if (cgiGetVariable("CONFIRM") == NULL) - { - cgiCopyTemplateLang("printer-confirm.tmpl"); - cgiEndHTML(); - return; - } + is_class = cgiGetVariable("IS_CLASS"); + printer = cgiGetVariable("PRINTER_NAME"); - if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - "/printers/%s", printer); - else + if (!printer) { cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiStartHTML(title); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); return; } /* - * Build a CUPS_DELETE_PRINTER request, which requires the following + * Build a printer request, which requires the following * attributes: * * attributes-charset @@ -2403,8 +2441,11 @@ do_delete_printer(http_t *http) /* I - HTTP connection */ * printer-uri */ - request = ippNewRequest(CUPS_DELETE_PRINTER); + request = ippNewRequest(op); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", + printer); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -2414,990 +2455,926 @@ do_delete_printer(http_t *http) /* I - HTTP connection */ ippDelete(cupsDoRequest(http, request, "/admin/")); - if (cupsLastError() > IPP_OK_CONFLICT) - cgiShowIPPError(_("Unable to delete printer:")); + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) + { + cgiStartHTML(title); + cgiShowIPPError(_("Unable to change printer:")); + } else - cgiCopyTemplateLang("printer-deleted.tmpl"); + { + /* + * Redirect successful updates back to the printer page... + */ + + char url[1024], /* Printer/class URL */ + refresh[1024]; /* Refresh URL */ + + + cgiRewriteURL(uri, url, sizeof(url), NULL); + cgiFormEncode(uri, url, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri); + cgiSetVariable("refresh_page", refresh); + + cgiStartHTML(title); + + if (op == IPP_PAUSE_PRINTER) + cgiCopyTemplateLang("printer-stop.tmpl"); + else if (op == IPP_RESUME_PRINTER) + cgiCopyTemplateLang("printer-start.tmpl"); + else if (op == CUPS_ACCEPT_JOBS) + cgiCopyTemplateLang("printer-accept.tmpl"); + else if (op == CUPS_REJECT_JOBS) + cgiCopyTemplateLang("printer-reject.tmpl"); + else if (op == IPP_PURGE_JOBS) + cgiCopyTemplateLang("printer-purge.tmpl"); + else if (op == CUPS_SET_DEFAULT) + cgiCopyTemplateLang("printer-default.tmpl"); + } cgiEndHTML(); } /* - * 'do_export()' - Export printers to Samba... + * 'do_set_allowed_users()' - Set the allowed/denied users for a queue. */ static void -do_export(http_t *http) /* I - HTTP connection */ +do_set_allowed_users(http_t *http) /* I - HTTP connection */ { - int i, j; /* Looping vars */ + int i; /* Looping var */ ipp_t *request, /* IPP request */ *response; /* IPP response */ - const char *username, /* Samba username */ - *password, /* Samba password */ - *export_all; /* Export all printers? */ - int export_count, /* Number of printers to export */ - printer_count; /* Number of available printers */ - + char uri[HTTP_MAX_URI]; /* Printer URI */ + const char *printer, /* Printer name (purge-jobs) */ + *is_class, /* Is a class? */ + *users, /* List of users or groups */ + *type; /* Allow/deny type */ + int num_users; /* Number of users */ + char *ptr, /* Pointer into users string */ + *end, /* Pointer to end of users string */ + quote; /* Quote character */ + ipp_attribute_t *attr; /* Attribute */ + static const char * const attrs[] = /* Requested attributes */ + { + "requesting-user-name-allowed", + "requesting-user-name-denied" + }; - /* - * Show header... - */ - cgiStartHTML(cgiText(_("Export Printers to Samba"))); + is_class = cgiGetVariable("IS_CLASS"); + printer = cgiGetVariable("PRINTER_NAME"); - /* - * Get form data... - */ + if (!printer) + { + cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiStartHTML(cgiText(_("Set Allowed Users"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } - username = cgiGetVariable("USERNAME"); - password = cgiGetVariable("PASSWORD"); - export_all = cgiGetVariable("EXPORT_ALL"); - export_count = cgiGetSize("EXPORT_NAME"); + users = cgiGetVariable("users"); + type = cgiGetVariable("type"); - if (username && *username && password && *password && export_count <= 1000) - { + if (!users || !type || + (strcmp(type, "requesting-user-name-allowed") && + strcmp(type, "requesting-user-name-denied"))) + { /* - * Do export... + * Build a Get-Printer-Attributes request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requested-attributes */ - char userpass[1024], /* Username%password */ - *argv[1005]; /* Arguments */ - int argc; /* Number of arguments */ - int pid; /* Process ID of child */ - int status; /* Status of command */ + request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", + printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); - fputs("DEBUG: Export printers...\n", stderr); + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); /* - * Create the command-line for cupsaddsmb... + * Do the request and get back a response... */ - snprintf(userpass, sizeof(userpass), "%s%%%s", username, password); + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + } - argv[0] = "cupsaddsmb"; - argv[1] = "-v"; - argv[2] = "-U"; - argv[3] = userpass; - argc = 4; + cgiStartHTML(cgiText(_("Set Allowed Users"))); - if (export_all) - argv[argc ++] = "-a"; - else + if (cupsLastError() == IPP_NOT_AUTHORIZED) { - for (i = 0; i < export_count; i ++) - argv[argc ++] = (char *)cgiGetArray("EXPORT_NAME", i); + puts("Status: 401\n"); + exit(0); } + else if (cupsLastError() > IPP_OK_CONFLICT) + cgiShowIPPError(_("Unable to get printer attributes:")); + else + cgiCopyTemplateLang("users.tmpl"); - argv[argc] = NULL; - + cgiEndHTML(); + } + else + { /* - * Run the command... + * Save the changes... */ - if ((pid = fork()) == 0) + for (num_users = 0, ptr = (char *)users; *ptr; num_users ++) { /* - * Child goes here... + * Skip whitespace and commas... */ - close(0); - open("/dev/null", O_RDONLY); - close(1); - dup(2); + while (*ptr == ',' || isspace(*ptr & 255)) + ptr ++; + + if (*ptr == '\'' || *ptr == '\"') + { + /* + * Scan quoted name... + */ + + quote = *ptr++; + + for (end = ptr; *end; end ++) + if (*end == quote) + break; + } + else + { + /* + * Scan space or comma-delimited name... + */ + + for (end = ptr; *end; end ++) + if (isspace(*end & 255) || *end == ',') + break; + } - execvp("cupsaddsmb", argv); - perror("ERROR: Unable to execute cupsaddsmb"); - exit(20); - } - else if (pid < 0) - cgiSetVariable("ERROR", cgiText(_("Unable to fork process!"))); - else - { /* - * Parent goes here, wait for child to finish... + * Advance to the next name... */ - while (wait(&status) < 0); + ptr = end; + } + + /* + * Build a CUPS-Add-Printer/Class request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name-{allowed,denied} + */ + + request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER); + + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", + printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + if (num_users == 0) + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "requesting-user-name-allowed", NULL, "all"); + else + { + attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + type, num_users, NULL, NULL); - if (status) + for (i = 0, ptr = (char *)users; *ptr; i ++) { - char message[1024]; /* Error message */ + /* + * Skip whitespace and commas... + */ + while (*ptr == ',' || isspace(*ptr & 255)) + ptr ++; - if (WIFEXITED(status)) + if (*ptr == '\'' || *ptr == '\"') { - switch (WEXITSTATUS(status)) - { - case 1 : - cgiSetVariable("ERROR", cgiText(_("Unable to connect to server!"))); - break; - - case 2 : - cgiSetVariable("ERROR", cgiText(_("Unable to get printer " - "attributes!"))); - break; - - case 3 : - cgiSetVariable("ERROR", cgiText(_("Unable to convert PPD file!"))); - break; - - case 4 : - cgiSetVariable("ERROR", cgiText(_("Unable to copy Windows 2000 " - "printer driver files!"))); - break; - - case 5 : - cgiSetVariable("ERROR", cgiText(_("Unable to install Windows " - "2000 printer driver files!"))); - break; - - case 6 : - cgiSetVariable("ERROR", cgiText(_("Unable to copy Windows 9x " - "printer driver files!"))); - break; - - case 7 : - cgiSetVariable("ERROR", cgiText(_("Unable to install Windows " - "9x printer driver files!"))); - break; - - case 8 : - cgiSetVariable("ERROR", cgiText(_("Unable to set Windows " - "printer driver!"))); - break; - - case 9 : - cgiSetVariable("ERROR", cgiText(_("No printer drivers found!"))); - break; - - case 20 : - cgiSetVariable("ERROR", cgiText(_("Unable to execute " - "cupsaddsmb command!"))); - break; - - default : - snprintf(message, sizeof(message), - cgiText(_("cupsaddsmb failed with status %d")), - WEXITSTATUS(status)); - - cgiSetVariable("ERROR", message); - break; - } + /* + * Scan quoted name... + */ + + quote = *ptr++; + + for (end = ptr; *end; end ++) + if (*end == quote) + break; } - else + else { - snprintf(message, sizeof(message), - cgiText(_("cupsaddsmb crashed on signal %d")), - WTERMSIG(status)); + /* + * Scan space or comma-delimited name... + */ - cgiSetVariable("ERROR", message); - } - } - else - { - cgiCopyTemplateLang("samba-exported"); - cgiEndHTML(); - return; - } - } - } - else if (username && !*username) - cgiSetVariable("ERROR", - cgiText(_("A Samba username is required to export " - "printer drivers!"))); - else if (username && (!password || !*password)) - cgiSetVariable("ERROR", - cgiText(_("A Samba password is required to export " - "printer drivers!"))); + for (end = ptr; *end; end ++) + if (isspace(*end & 255) || *end == ',') + break; + } - /* - * Get list of available printers... - */ + /* + * Terminate the name... + */ - cgiSetSize("PRINTER_NAME", 0); - cgiSetSize("PRINTER_EXPORT", 0); + if (*end) + *end++ = '\0'; - request = ippNewRequest(CUPS_GET_PRINTERS); + /* + * Add the name... + */ - ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, - "printer-type", 0); + attr->values[i].string.text = strdup(ptr); - ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, - "printer-type-mask", CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE | - CUPS_PRINTER_IMPLICIT); + /* + * Advance to the next name... + */ - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", NULL, "printer-name"); + ptr = end; + } + } - if ((response = cupsDoRequest(http, request, "/")) != NULL) - { - cgiSetIPPVars(response, NULL, NULL, NULL, 0); - ippDelete(response); + /* + * Do the request and get back a response... + */ - if (!export_all) + ippDelete(cupsDoRequest(http, request, "/admin/")); + + if (cupsLastError() == IPP_NOT_AUTHORIZED) { - printer_count = cgiGetSize("PRINTER_NAME"); + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) + { + cgiStartHTML(cgiText(_("Set Allowed Users"))); + cgiShowIPPError(_("Unable to change printer:")); + } + else + { + /* + * Redirect successful updates back to the printer page... + */ - for (i = 0; i < printer_count; i ++) - { - for (j = 0; j < export_count; j ++) - if (!strcasecmp(cgiGetArray("PRINTER_NAME", i), - cgiGetArray("EXPORT_NAME", j))) - break; + char url[1024], /* Printer/class URL */ + refresh[1024]; /* Refresh URL */ - cgiSetArray("PRINTER_EXPORT", i, j < export_count ? "Y" : ""); - } - } - } - /* - * Show form... - */ + cgiRewriteURL(uri, url, sizeof(url), NULL); + cgiFormEncode(uri, url, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", + uri); + cgiSetVariable("refresh_page", refresh); - cgiCopyTemplateLang("samba-export.tmpl"); - cgiEndHTML(); + cgiStartHTML(cgiText(_("Set Allowed Users"))); + + cgiCopyTemplateLang(is_class ? "class-modified.tmpl" : + "printer-modified.tmpl"); + } + + cgiEndHTML(); + } } /* - * 'do_menu()' - Show the main menu... + * 'do_set_options()' - Configure the default options for a queue. */ static void -do_menu(http_t *http) /* I - HTTP connection */ +do_set_options(http_t *http, /* I - HTTP connection */ + int is_class) /* I - Set options for class? */ { - cups_file_t *cupsd; /* cupsd.conf file */ - char line[1024], /* Line from cupsd.conf file */ - *value; /* Value on line */ - const char *server_root; /* Location of config files */ - const char *datadir; /* Location of data files */ + int i, j, k, m; /* Looping vars */ + int have_options; /* Have options? */ ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* IPP attribute */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *var; /* Variable value */ + const char *printer; /* Printer printer name */ + const char *filename; /* PPD filename */ + char tempfile[1024]; /* Temporary filename */ + cups_file_t *in, /* Input file */ + *out; /* Output file */ + char line[1024], /* Line from PPD file */ + value[1024], /* Option value */ + keyword[1024], /* Keyword from Default line */ + *keyptr; /* Pointer into keyword... */ + ppd_file_t *ppd; /* PPD file */ + ppd_group_t *group; /* Option group */ + ppd_option_t *option; /* Option */ + ppd_coption_t *coption; /* Custom option */ + ppd_cparam_t *cparam; /* Custom parameter */ + ppd_attr_t *protocol; /* cupsProtocol attribute */ + const char *title; /* Page title */ - /* - * Locate the cupsd.conf file... - */ - - if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) - server_root = CUPS_SERVERROOT; - - snprintf(line, sizeof(line), "%s/cupsd.conf", server_root); - - cgiStartHTML(cgiText(_("Administration"))); + title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options")); - printf("\n", line); + fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http, + is_class); /* - * Open the cupsd.conf file... + * Get the printer name... */ - if ((cupsd = cupsFileOpen(line, "r")) == NULL) + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", + printer); + else { - /* - * Unable to open - log an error... - */ - - cgiSetVariable("MESSAGE", cgiText(_("Unable to open cupsd.conf file:"))); - cgiSetVariable("ERROR", strerror(errno)); + cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiStartHTML(title); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); - - perror(line); + return; } - else - { - /* - * Read the file, keeping track of what settings are enabled... - */ - int remote_access = 0, /* Remote access allowed? */ - remote_admin = 0, /* Remote administration allowed? */ - browsing = 1, /* Browsing enabled? */ - browse_allow = 1, /* Browse address set? */ - browse_address = 0, /* Browse address set? */ - cancel_policy = 1, /* Cancel-job policy set? */ - debug_logging = 0; /* LogLevel debug set? */ - int linenum = 0, /* Line number in file */ - in_policy = 0, /* In a policy section? */ - in_cancel_job = 0, /* In a cancel-job section? */ - in_admin_location = 0; /* In the /admin location? */ + fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri); + + /* + * Get the PPD file... + */ + + if (is_class) + filename = NULL; + else + filename = cupsGetPPD2(http, printer); + if (filename) + { + fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename); - while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) + if ((ppd = ppdOpenFile(filename)) == NULL) { - if (!strcasecmp(line, "Port")) - { - remote_access = 1; - } - else if (!strcasecmp(line, "Listen")) - { - char *port; /* Pointer to port number, if any */ - - - if ((port = strrchr(value, ':')) != NULL) - *port = '\0'; - - if (strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1")) - remote_access = 1; - } - else if (!strcasecmp(line, "Browsing")) - { - browsing = !strcasecmp(value, "yes") || !strcasecmp(value, "on") || - !strcasecmp(value, "true"); - } - else if (!strcasecmp(line, "BrowseAddress")) - { - browse_address = 1; - } - else if (!strcasecmp(line, "BrowseAllow")) - { - browse_allow = 1; - } - else if (!strcasecmp(line, "BrowseOrder")) - { - browse_allow = !strncasecmp(value, "deny,", 5); - } - else if (!strcasecmp(line, "LogLevel")) - { - debug_logging = !strncasecmp(value, "debug", 5); - } - else if (!strcasecmp(line, "")) - { - in_policy = 0; - } - else if (!strcasecmp(line, "")) - { - in_cancel_job = 0; - } - else if (!strcasecmp(line, "Require") && in_cancel_job) - { - cancel_policy = 0; - } - else if (!strcasecmp(line, "")) - { - in_admin_location = 0; - } - else if (!strcasecmp(line, "Allow") && in_admin_location && - strcasecmp(value, "localhost") && strcasecmp(value, "127.0.0.1")) + for (option = ppdFirstOption(ppd); + option; + option = ppdNextOption(ppd)) + if ((var = cgiGetVariable(option->keyword)) != NULL) { - remote_admin = 1; + have_options = 1; + ppdMarkOption(ppd, option->keyword, var); } - } - - cupsFileClose(cupsd); - - if (browsing && browse_allow) - cgiSetVariable("REMOTE_PRINTERS", "CHECKED"); - - if (remote_access && browsing && browse_address) - cgiSetVariable("SHARE_PRINTERS", "CHECKED"); - - if (remote_access && remote_admin) - cgiSetVariable("REMOTE_ADMIN", "CHECKED"); - - if (cancel_policy) - cgiSetVariable("USER_CANCEL_ANY", "CHECKED"); - - if (debug_logging) - cgiSetVariable("DEBUG_LOGGING", "CHECKED"); } - /* - * Get the list of printers and their devices... - */ - - request = ippNewRequest(CUPS_GET_PRINTERS); - - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", NULL, "device-uri"); - - ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", - CUPS_PRINTER_LOCAL); - ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", - CUPS_PRINTER_LOCAL); - - if ((response = cupsDoRequest(http, request, "/")) != NULL) + if (!have_options || ppdConflicts(ppd)) { /* - * Got the printer list, now load the devices... - */ - - int i; /* Looping var */ - cups_array_t *printer_devices; /* Printer devices for local printers */ - char *printer_device; /* Current printer device */ - - - /* - * Allocate an array and copy the device strings... - */ - - printer_devices = cupsArrayNew((cups_array_func_t)strcmp, NULL); - - for (attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI); - attr; - attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI)) - { - cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text)); - } - - /* - * Free the printer list and get the device list... + * Show the options to the user... */ - ippDelete(response); + fputs("DEBUG: Showing options...\n", stderr); - request = ippNewRequest(CUPS_GET_DEVICES); + cgiStartHTML(cgiText(_("Set Printer Options"))); + cgiCopyTemplateLang("set-printer-options-header.tmpl"); - if ((response = cupsDoRequest(http, request, "/")) != NULL) + if (ppd) { - /* - * Got the device list, let's parse it... - */ - - const char *device_uri, /* device-uri attribute value */ - *device_make_and_model, /* device-make-and-model value */ - *device_info; /* device-info value */ - + ppdLocalize(ppd); - for (i = 0, attr = response->attrs; attr; attr = attr->next) + if (ppdConflicts(ppd)) { - /* - * Skip leading attributes until we hit a device... - */ - - while (attr && attr->group_tag != IPP_TAG_PRINTER) - attr = attr->next; - - if (!attr) - break; - - /* - * Pull the needed attributes from this device... - */ - - device_info = NULL; - device_make_and_model = NULL; - device_uri = NULL; - - while (attr && attr->group_tag == IPP_TAG_PRINTER) - { - if (!strcmp(attr->name, "device-info") && - attr->value_tag == IPP_TAG_TEXT) - device_info = attr->values[0].string.text; - - if (!strcmp(attr->name, "device-make-and-model") && - attr->value_tag == IPP_TAG_TEXT) - device_make_and_model = attr->values[0].string.text; - - if (!strcmp(attr->name, "device-uri") && - attr->value_tag == IPP_TAG_URI) - device_uri = attr->values[0].string.text; + for (i = ppd->num_groups, k = 0, group = ppd->groups; + i > 0; + i --, group ++) + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + if (option->conflicted) + { + cgiSetArray("ckeyword", k, option->keyword); + cgiSetArray("ckeytext", k, option->text); + k ++; + } - attr = attr->next; - } + cgiCopyTemplateLang("option-conflict.tmpl"); + } - /* - * See if we have everything needed... - */ + for (i = ppd->num_groups, group = ppd->groups; + i > 0; + i --, group ++) + { + if (!strcmp(group->name, "InstallableOptions")) + cgiSetVariable("GROUP", cgiText(_("Options Installed"))); + else + cgiSetVariable("GROUP", group->text); - if (device_info && device_make_and_model && device_uri && - strcasecmp(device_make_and_model, "unknown") && - strchr(device_uri, ':')) + cgiCopyTemplateLang("option-header.tmpl"); + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) { - /* - * Yes, now see if there is already a printer for this - * device... - */ - - if (!cupsArrayFind(printer_devices, (void *)device_uri)) - { - /* - * Not found, so it must be a new printer... - */ - - char options[1024], /* Form variables for this device */ - *options_ptr; /* Pointer into string */ - const char *ptr; /* Pointer into device string */ - - - /* - * Format the printer name variable for this device... - * - * We use the device-info string first, then device-uri, - * and finally device-make-and-model to come up with a - * suitable name. - */ + if (!strcmp(option->keyword, "PageRegion")) + continue; - strcpy(options, "PRINTER_NAME="); - options_ptr = options + strlen(options); + cgiSetVariable("KEYWORD", option->keyword); + cgiSetVariable("KEYTEXT", option->text); - if (strncasecmp(device_info, "unknown", 7)) - ptr = device_info; - else if ((ptr = strstr(device_uri, "://")) != NULL) - ptr += 3; - else - ptr = device_make_and_model; + if (option->conflicted) + cgiSetVariable("CONFLICTED", "1"); + else + cgiSetVariable("CONFLICTED", "0"); - for (; - options_ptr < (options + sizeof(options) - 1) && *ptr; - ptr ++) - if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || *ptr == '.') - *options_ptr++ = *ptr; - else if ((*ptr == ' ' || *ptr == '/') && options_ptr[-1] != '_') - *options_ptr++ = '_'; - else if (*ptr == '?' || *ptr == '(') - break; + cgiSetSize("CHOICES", 0); + cgiSetSize("TEXT", 0); + for (k = 0, m = 0; k < option->num_choices; k ++) + { + cgiSetArray("CHOICES", m, option->choices[k].choice); + cgiSetArray("TEXT", m, option->choices[k].text); - /* - * Then add the make and model in the printer info, so - * that MacOS clients see something reasonable... - */ + m ++; - strlcpy(options_ptr, "&PRINTER_LOCATION=Local+Printer" - "&PRINTER_INFO=", - sizeof(options) - (options_ptr - options)); - options_ptr += strlen(options_ptr); + if (option->choices[k].marked) + cgiSetVariable("DEFCHOICE", option->choices[k].choice); + } - cgiFormEncode(options_ptr, device_make_and_model, - sizeof(options) - (options_ptr - options)); - options_ptr += strlen(options_ptr); + cgiSetSize("PARAMS", 0); + cgiSetSize("PARAMTEXT", 0); + cgiSetSize("PARAMVALUE", 0); + cgiSetSize("INPUTTYPE", 0); - /* - * Then copy the device URI... - */ + if ((coption = ppdFindCustomOption(ppd, option->keyword))) + { + const char *units = NULL; /* Units value, if any */ - strlcpy(options_ptr, "&DEVICE_URI=", - sizeof(options) - (options_ptr - options)); - options_ptr += strlen(options_ptr); - cgiFormEncode(options_ptr, device_uri, - sizeof(options) - (options_ptr - options)); - options_ptr += strlen(options_ptr); + cgiSetVariable("ISCUSTOM", "1"); - if (options_ptr < (options + sizeof(options) - 1)) + for (cparam = ppdFirstCustomParam(coption), m = 0; + cparam; + cparam = ppdNextCustomParam(coption), m ++) { - *options_ptr++ = '|'; - cgiFormEncode(options_ptr, device_make_and_model, - sizeof(options) - (options_ptr - options)); + if (!strcasecmp(option->keyword, "PageSize") && + strcasecmp(cparam->name, "Width") && + strcasecmp(cparam->name, "Height")) + { + m --; + continue; + } + + cgiSetArray("PARAMS", m, cparam->name); + cgiSetArray("PARAMTEXT", m, cparam->text); + cgiSetArray("INPUTTYPE", m, "text"); + + switch (cparam->type) + { + case PPD_CUSTOM_POINTS : + if (!strncasecmp(option->defchoice, "Custom.", 7)) + { + units = option->defchoice + strlen(option->defchoice) - 2; + + if (strcmp(units, "mm") && strcmp(units, "cm") && + strcmp(units, "in") && strcmp(units, "ft")) + { + if (units[1] == 'm') + units ++; + else + units = "pt"; + } + } + else + units = "pt"; + + if (!strcmp(units, "mm")) + snprintf(value, sizeof(value), "%g", + cparam->current.custom_points / 72.0 * 25.4); + else if (!strcmp(units, "cm")) + snprintf(value, sizeof(value), "%g", + cparam->current.custom_points / 72.0 * 2.54); + else if (!strcmp(units, "in")) + snprintf(value, sizeof(value), "%g", + cparam->current.custom_points / 72.0); + else if (!strcmp(units, "ft")) + snprintf(value, sizeof(value), "%g", + cparam->current.custom_points / 72.0 / 12.0); + else if (!strcmp(units, "m")) + snprintf(value, sizeof(value), "%g", + cparam->current.custom_points / 72.0 * 0.0254); + else + snprintf(value, sizeof(value), "%g", + cparam->current.custom_points); + cgiSetArray("PARAMVALUE", m, value); + break; + + case PPD_CUSTOM_CURVE : + case PPD_CUSTOM_INVCURVE : + case PPD_CUSTOM_REAL : + snprintf(value, sizeof(value), "%g", + cparam->current.custom_real); + cgiSetArray("PARAMVALUE", m, value); + break; + + case PPD_CUSTOM_INT: + snprintf(value, sizeof(value), "%d", + cparam->current.custom_int); + cgiSetArray("PARAMVALUE", m, value); + break; + + case PPD_CUSTOM_PASSCODE: + case PPD_CUSTOM_PASSWORD: + if (cparam->current.custom_password) + cgiSetArray("PARAMVALUE", m, + cparam->current.custom_password); + else + cgiSetArray("PARAMVALUE", m, ""); + cgiSetArray("INPUTTYPE", m, "password"); + break; + + case PPD_CUSTOM_STRING: + if (cparam->current.custom_string) + cgiSetArray("PARAMVALUE", m, + cparam->current.custom_string); + else + cgiSetArray("PARAMVALUE", m, ""); + break; + } } - /* - * Finally, set the form variables for this printer... - */ + if (units) + { + cgiSetArray("PARAMS", m, "Units"); + cgiSetArray("PARAMTEXT", m, cgiText(_("Units"))); + cgiSetArray("PARAMVALUE", m, units); + } + } + else + cgiSetVariable("ISCUSTOM", "0"); - cgiSetArray("device_info", i, device_info); - cgiSetArray("device_make_and_model", i, device_make_and_model); - cgiSetArray("device_options", i, options); - cgiSetArray("device_uri", i, device_uri); - i ++; + switch (option->ui) + { + case PPD_UI_BOOLEAN : + cgiCopyTemplateLang("option-boolean.tmpl"); + break; + case PPD_UI_PICKONE : + cgiCopyTemplateLang("option-pickone.tmpl"); + break; + case PPD_UI_PICKMANY : + cgiCopyTemplateLang("option-pickmany.tmpl"); + break; } } - if (!attr) - break; + cgiCopyTemplateLang("option-trailer.tmpl"); } - - ippDelete(response); - - /* - * Free the device list... - */ - - for (printer_device = (char *)cupsArrayFirst(printer_devices); - printer_device; - printer_device = (char *)cupsArrayNext(printer_devices)) - free(printer_device); - - cupsArrayDelete(printer_devices); } - } - /* - * See if Samba and the Windows drivers are installed... - */ - - if ((datadir = getenv("CUPS_DATADIR")) == NULL) - datadir = CUPS_DATADIR; - - snprintf(line, sizeof(line), "%s/drivers/pscript5.dll", datadir); - if (!access(line, 0)) - { /* - * Found Windows 2000 driver file, see if we have smbclient and - * rpcclient... + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri */ - if (cupsFileFind("smbclient", getenv("PATH"), line, sizeof(line)) && - cupsFileFind("rpcclient", getenv("PATH"), line, sizeof(line))) - cgiSetVariable("HAVE_SAMBA", "Y"); - else - { - if (!cupsFileFind("smbclient", getenv("PATH"), line, sizeof(line))) - fputs("ERROR: smbclient not found!\n", stderr); - - if (!cupsFileFind("rpcclient", getenv("PATH"), line, sizeof(line))) - fputs("ERROR: rpcclient not found!\n", stderr); - } - } - else - perror(line); - - /* - * Finally, show the main menu template... - */ + request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); - cgiCopyTemplateLang("admin.tmpl"); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, "/printers/%s", printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); - cgiEndHTML(); -} + /* + * Do the request and get back a response... + */ + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((attr = ippFindAttribute(response, "job-sheets-supported", + IPP_TAG_ZERO)) != NULL) + { + /* + * Add the job sheets options... + */ -/* - * 'do_printer_op()' - Do a printer operation. - */ + cgiSetVariable("GROUP", cgiText(_("Banners"))); + cgiCopyTemplateLang("option-header.tmpl"); -static void -do_printer_op(http_t *http, /* I - HTTP connection */ - ipp_op_t op, /* I - Operation to perform */ - const char *title) /* I - Title of page */ -{ - ipp_t *request; /* IPP request */ - char uri[HTTP_MAX_URI]; /* Printer URI */ - const char *printer, /* Printer name (purge-jobs) */ - *is_class; /* Is a class? */ + cgiSetSize("CHOICES", attr->num_values); + cgiSetSize("TEXT", attr->num_values); + for (k = 0; k < attr->num_values; k ++) + { + cgiSetArray("CHOICES", k, attr->values[k].string.text); + cgiSetArray("TEXT", k, attr->values[k].string.text); + } + attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO); - is_class = cgiGetVariable("IS_CLASS"); - printer = cgiGetVariable("PRINTER_NAME"); + cgiSetVariable("KEYWORD", "job_sheets_start"); + cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner"))); + cgiSetVariable("DEFCHOICE", attr != NULL ? + attr->values[0].string.text : ""); - if (!printer) - { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); - cgiStartHTML(title); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; - } + cgiCopyTemplateLang("option-pickone.tmpl"); - /* - * Build a printer request, which requires the following - * attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri - */ + cgiSetVariable("KEYWORD", "job_sheets_end"); + cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner"))); + cgiSetVariable("DEFCHOICE", attr != NULL && attr->num_values > 1 ? + attr->values[1].string.text : ""); - request = ippNewRequest(op); + cgiCopyTemplateLang("option-pickone.tmpl"); - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - is_class ? "/classes/%s" : "/printers/%s", printer); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + cgiCopyTemplateLang("option-trailer.tmpl"); + } - /* - * Do the request and get back a response... - */ + if (ippFindAttribute(response, "printer-error-policy-supported", + IPP_TAG_ZERO) || + ippFindAttribute(response, "printer-op-policy-supported", + IPP_TAG_ZERO)) + { + /* + * Add the error and operation policy options... + */ - ippDelete(cupsDoRequest(http, request, "/admin/")); + cgiSetVariable("GROUP", cgiText(_("Policies"))); + cgiCopyTemplateLang("option-header.tmpl"); - if (cupsLastError() > IPP_OK_CONFLICT) - { - cgiStartHTML(title); - cgiShowIPPError(_("Unable to change printer:")); - } - else - { - /* - * Redirect successful updates back to the printer page... - */ + /* + * Error policy... + */ - char url[1024], /* Printer/class URL */ - refresh[1024]; /* Refresh URL */ + attr = ippFindAttribute(response, "printer-error-policy-supported", + IPP_TAG_ZERO); + if (attr) + { + cgiSetSize("CHOICES", attr->num_values); + cgiSetSize("TEXT", attr->num_values); + for (k = 0; k < attr->num_values; k ++) + { + cgiSetArray("CHOICES", k, attr->values[k].string.text); + cgiSetArray("TEXT", k, attr->values[k].string.text); + } - cgiRewriteURL(uri, url, sizeof(url), NULL); - cgiFormEncode(uri, url, sizeof(uri)); - snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=%s", uri); - cgiSetVariable("refresh_page", refresh); + attr = ippFindAttribute(response, "printer-error-policy", + IPP_TAG_ZERO); - cgiStartHTML(title); + cgiSetVariable("KEYWORD", "printer_error_policy"); + cgiSetVariable("KEYTEXT", cgiText(_("Error Policy"))); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); + } - if (op == IPP_PAUSE_PRINTER) - cgiCopyTemplateLang("printer-stop.tmpl"); - else if (op == IPP_RESUME_PRINTER) - cgiCopyTemplateLang("printer-start.tmpl"); - else if (op == CUPS_ACCEPT_JOBS) - cgiCopyTemplateLang("printer-accept.tmpl"); - else if (op == CUPS_REJECT_JOBS) - cgiCopyTemplateLang("printer-reject.tmpl"); - else if (op == IPP_PURGE_JOBS) - cgiCopyTemplateLang("printer-purge.tmpl"); - else if (op == CUPS_SET_DEFAULT) - cgiCopyTemplateLang("printer-default.tmpl"); - } + cgiCopyTemplateLang("option-pickone.tmpl"); - cgiEndHTML(); -} + /* + * Operation policy... + */ + attr = ippFindAttribute(response, "printer-op-policy-supported", + IPP_TAG_ZERO); -/* - * 'do_set_allowed_users()' - Set the allowed/denied users for a queue. - */ + if (attr) + { + cgiSetSize("CHOICES", attr->num_values); + cgiSetSize("TEXT", attr->num_values); + for (k = 0; k < attr->num_values; k ++) + { + cgiSetArray("CHOICES", k, attr->values[k].string.text); + cgiSetArray("TEXT", k, attr->values[k].string.text); + } -static void -do_set_allowed_users(http_t *http) /* I - HTTP connection */ -{ - int i; /* Looping var */ - ipp_t *request, /* IPP request */ - *response; /* IPP response */ - char uri[HTTP_MAX_URI]; /* Printer URI */ - const char *printer, /* Printer name (purge-jobs) */ - *is_class, /* Is a class? */ - *users, /* List of users or groups */ - *type; /* Allow/deny type */ - int num_users; /* Number of users */ - char *ptr, /* Pointer into users string */ - *end, /* Pointer to end of users string */ - quote; /* Quote character */ - ipp_attribute_t *attr; /* Attribute */ - static const char * const attrs[] = /* Requested attributes */ - { - "requesting-user-name-allowed", - "requesting-user-name-denied" - }; + attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO); + cgiSetVariable("KEYWORD", "printer_op_policy"); + cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy"))); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); - is_class = cgiGetVariable("IS_CLASS"); - printer = cgiGetVariable("PRINTER_NAME"); + cgiCopyTemplateLang("option-pickone.tmpl"); + } - if (!printer) - { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); - cgiStartHTML(cgiText(_("Set Allowed Users"))); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; - } + cgiCopyTemplateLang("option-trailer.tmpl"); + } - users = cgiGetVariable("users"); - type = cgiGetVariable("type"); + ippDelete(response); + } - if (!users || !type || - (strcmp(type, "requesting-user-name-allowed") && - strcmp(type, "requesting-user-name-denied"))) - { /* - * Build a Get-Printer-Attributes request, which requires the following - * attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri - * requested-attributes + * Binary protocol support... */ - request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); - - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - is_class ? "/classes/%s" : "/printers/%s", printer); - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + if (ppd && ppd->protocols && strstr(ppd->protocols, "BCP")) + { + protocol = ppdFindAttr(ppd, "cupsProtocol", NULL); - ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", - (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); + cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol"))); + cgiCopyTemplateLang("option-header.tmpl"); - /* - * Do the request and get back a response... - */ + cgiSetSize("CHOICES", 2); + cgiSetSize("TEXT", 2); + cgiSetArray("CHOICES", 0, "None"); + cgiSetArray("TEXT", 0, cgiText(_("None"))); - if ((response = cupsDoRequest(http, request, "/")) != NULL) - { - cgiSetIPPVars(response, NULL, NULL, NULL, 0); + if (strstr(ppd->protocols, "TBCP")) + { + cgiSetArray("CHOICES", 1, "TBCP"); + cgiSetArray("TEXT", 1, "TBCP"); + } + else + { + cgiSetArray("CHOICES", 1, "BCP"); + cgiSetArray("TEXT", 1, "BCP"); + } - ippDelete(response); - } + cgiSetVariable("KEYWORD", "protocol"); + cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol"))); + cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None"); - cgiStartHTML(cgiText(_("Set Allowed Users"))); + cgiCopyTemplateLang("option-pickone.tmpl"); - if (cupsLastError() > IPP_OK_CONFLICT) - cgiShowIPPError(_("Unable to get printer attributes:")); - else - cgiCopyTemplateLang("users.tmpl"); + cgiCopyTemplateLang("option-trailer.tmpl"); + } + cgiCopyTemplateLang("set-printer-options-trailer.tmpl"); cgiEndHTML(); } else { /* - * Save the changes... + * Set default options... */ - for (num_users = 0, ptr = (char *)users; *ptr; num_users ++) - { - /* - * Skip whitespace and commas... - */ + fputs("DEBUG: Setting options...\n", stderr); - while (*ptr == ',' || isspace(*ptr & 255)) - ptr ++; + if (filename) + { + out = cupsTempFile2(tempfile, sizeof(tempfile)); + in = cupsFileOpen(filename, "r"); - if (*ptr == '\'' || *ptr == '\"') + if (!in || !out) { - /* - * Scan quoted name... - */ + cgiSetVariable("ERROR", strerror(errno)); + cgiStartHTML(cgiText(_("Set Printer Options"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); - quote = *ptr++; + if (in) + cupsFileClose(in); - for (end = ptr; *end; end ++) - if (*end == quote) - break; + if (out) + { + cupsFileClose(out); + unlink(tempfile); + } + + unlink(filename); + return; } - else + + while (cupsFileGets(in, line, sizeof(line))) { - /* - * Scan space or comma-delimited name... - */ + if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol")) + continue; + else if (strncmp(line, "*Default", 8)) + cupsFilePrintf(out, "%s\n", line); + else + { + /* + * Get default option name... + */ - for (end = ptr; *end; end ++) - if (isspace(*end & 255) || *end == ',') - break; + strlcpy(keyword, line + 8, sizeof(keyword)); + + for (keyptr = keyword; *keyptr; keyptr ++) + if (*keyptr == ':' || isspace(*keyptr & 255)) + break; + + *keyptr = '\0'; + + if (!strcmp(keyword, "PageRegion") || + !strcmp(keyword, "PaperDimension") || + !strcmp(keyword, "ImageableArea")) + var = get_option_value(ppd, "PageSize", value, sizeof(value)); + else + var = get_option_value(ppd, keyword, value, sizeof(value)); + + if (!var) + cupsFilePrintf(out, "%s\n", line); + else + cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); + } } /* - * Advance to the next name... + * TODO: We need to set the port-monitor attribute! */ - ptr = end; + if ((var = cgiGetVariable("protocol")) != NULL) + cupsFilePrintf(out, "*cupsProtocol: %s\n", var); + + cupsFileClose(in); + cupsFileClose(out); + } + else + { + /* + * Make sure temporary filename is cleared when there is no PPD... + */ + + tempfile[0] = '\0'; } /* - * Build a CUPS-Add-Printer/Class request, which requires the following - * attributes: + * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the + * following attributes: * * attributes-charset * attributes-natural-language * printer-uri - * requesting-user-name-{allowed,denied} + * job-sheets-default + * printer-error-policy + * printer-op-policy + * [ppd file] */ - request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER); + request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS : + CUPS_ADD_MODIFY_PRINTER); - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - is_class ? "/classes/%s" : "/printers/%s", printer); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); - - if (num_users == 0) - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - "requesting-user-name-allowed", NULL, "all"); - else - { - attr = ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - type, num_users, NULL, NULL); - - for (i = 0, ptr = (char *)users; *ptr; i ++) - { - /* - * Skip whitespace and commas... - */ - - while (*ptr == ',' || isspace(*ptr & 255)) - ptr ++; - - if (*ptr == '\'' || *ptr == '\"') - { - /* - * Scan quoted name... - */ - - quote = *ptr++; - - for (end = ptr; *end; end ++) - if (*end == quote) - break; - } - else - { - /* - * Scan space or comma-delimited name... - */ - - for (end = ptr; *end; end ++) - if (isspace(*end & 255) || *end == ',') - break; - } - - /* - * Terminate the name... - */ - - if (*end) - *end++ = '\0'; - - /* - * Add the name... - */ + NULL, uri); - attr->values[i].string.text = strdup(ptr); + attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "job-sheets-default", 2, NULL, NULL); + attr->values[0].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_start")); + attr->values[1].string.text = _cupsStrAlloc(cgiGetVariable("job_sheets_end")); - /* - * Advance to the next name... - */ + if ((var = cgiGetVariable("printer_error_policy")) != NULL) + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-error-policy", NULL, var); - ptr = end; - } - } + if ((var = cgiGetVariable("printer_op_policy")) != NULL) + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-op-policy", NULL, var); /* * Do the request and get back a response... */ - ippDelete(cupsDoRequest(http, request, "/admin/")); + if (filename) + ippDelete(cupsDoFileRequest(http, request, "/admin/", tempfile)); + else + ippDelete(cupsDoRequest(http, request, "/admin/")); - if (cupsLastError() > IPP_OK_CONFLICT) + if (cupsLastError() == IPP_NOT_AUTHORIZED) { - cgiStartHTML(cgiText(_("Set Allowed Users"))); - cgiShowIPPError(_("Unable to change printer:")); + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) + { + cgiStartHTML(title); + cgiShowIPPError(_("Unable to set options:")); } else { @@ -3405,28 +3382,32 @@ do_set_allowed_users(http_t *http) /* I - HTTP connection */ * Redirect successful updates back to the printer page... */ - char url[1024], /* Printer/class URL */ - refresh[1024]; /* Refresh URL */ + char refresh[1024]; /* Refresh URL */ - cgiRewriteURL(uri, url, sizeof(url), NULL); - cgiFormEncode(uri, url, sizeof(uri)); - snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=%s", uri); + cgiFormEncode(uri, printer, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s", + is_class ? "classes" : "printers", uri); cgiSetVariable("refresh_page", refresh); - cgiStartHTML(cgiText(_("Set Allowed Users"))); + cgiStartHTML(title); - cgiCopyTemplateLang(is_class ? "class-modified.tmpl" : - "printer-modified.tmpl"); + cgiCopyTemplateLang("printer-configured.tmpl"); } cgiEndHTML(); + + if (filename) + unlink(tempfile); } + + if (filename) + unlink(filename); } /* - * 'do_set_sharing()' - Set printer-is-shared value... + * 'do_set_sharing()' - Set printer-is-shared value. */ static void @@ -3465,8 +3446,9 @@ do_set_sharing(http_t *http) /* I - HTTP connection */ request = ippNewRequest(is_class ? CUPS_ADD_CLASS : CUPS_ADD_PRINTER); - httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, - is_class ? "/classes/%s" : "/printers/%s", printer); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, + "localhost", 0, is_class ? "/classes/%s" : "/printers/%s", + printer); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -3483,7 +3465,12 @@ do_set_sharing(http_t *http) /* I - HTTP connection */ ippDelete(response); } - if (cupsLastError() > IPP_OK_CONFLICT) + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) { cgiStartHTML(cgiText(_("Set Publishing"))); cgiShowIPPError(_("Unable to change printer-is-shared attribute:")); @@ -3500,7 +3487,7 @@ do_set_sharing(http_t *http) /* I - HTTP connection */ cgiRewriteURL(uri, url, sizeof(url), NULL); cgiFormEncode(uri, url, sizeof(uri)); - snprintf(refresh, sizeof(refresh), "5;/admin/?OP=redirect&URL=%s", uri); + snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=%s", uri); cgiSetVariable("refresh_page", refresh); cgiStartHTML(cgiText(_("Set Publishing"))); @@ -3512,6 +3499,294 @@ do_set_sharing(http_t *http) /* I - HTTP connection */ } +/* + * 'get_option_value()' - Return the value of an option. + * + * This function also handles generation of custom option values. + */ + +static char * /* O - Value string or NULL on error */ +get_option_value( + ppd_file_t *ppd, /* I - PPD file */ + const char *name, /* I - Option name */ + char *buffer, /* I - String buffer */ + size_t bufsize) /* I - Size of buffer */ +{ + char *bufptr, /* Pointer into buffer */ + *bufend; /* End of buffer */ + ppd_coption_t *coption; /* Custom option */ + ppd_cparam_t *cparam; /* Current custom parameter */ + char keyword[256]; /* Parameter name */ + const char *val, /* Parameter value */ + *uval; /* Units value */ + long integer; /* Integer value */ + double number, /* Number value */ + number_points; /* Number in points */ + + + /* + * See if we have a custom option choice... + */ + + if ((val = cgiGetVariable(name)) == NULL) + { + /* + * Option not found! + */ + + return (NULL); + } + else if (strcasecmp(val, "Custom") || + (coption = ppdFindCustomOption(ppd, name)) == NULL) + { + /* + * Not a custom choice... + */ + + strlcpy(buffer, val, bufsize); + return (buffer); + } + + /* + * OK, we have a custom option choice, format it... + */ + + *buffer = '\0'; + + if (!strcmp(coption->keyword, "PageSize")) + { + const char *lval; /* Length string value */ + double width, /* Width value */ + width_points, /* Width in points */ + length, /* Length value */ + length_points; /* Length in points */ + + + val = cgiGetVariable("PageSize.Width"); + lval = cgiGetVariable("PageSize.Height"); + uval = cgiGetVariable("PageSize.Units"); + + if (!val || !lval || !uval || + (width = strtod(val, NULL)) == 0.0 || + (length = strtod(lval, NULL)) == 0.0 || + (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && + strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) + return (NULL); + + width_points = get_points(width, uval); + length_points = get_points(length, uval); + + if (width_points < ppd->custom_min[0] || + width_points > ppd->custom_max[0] || + length_points < ppd->custom_min[1] || + length_points > ppd->custom_max[1]) + return (NULL); + + snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval); + } + else if (cupsArrayCount(coption->params) == 1) + { + cparam = ppdFirstCustomParam(coption); + snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name); + + if ((val = cgiGetVariable(keyword)) == NULL) + return (NULL); + + switch (cparam->type) + { + case PPD_CUSTOM_CURVE : + case PPD_CUSTOM_INVCURVE : + case PPD_CUSTOM_REAL : + if ((number = strtod(val, NULL)) == 0.0 || + number < cparam->minimum.custom_real || + number > cparam->maximum.custom_real) + return (NULL); + + snprintf(buffer, bufsize, "Custom.%g", number); + break; + + case PPD_CUSTOM_INT : + if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || + integer == LONG_MAX || + integer < cparam->minimum.custom_int || + integer > cparam->maximum.custom_int) + return (NULL); + + snprintf(buffer, bufsize, "Custom.%ld", integer); + break; + + case PPD_CUSTOM_POINTS : + snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); + + if ((number = strtod(val, NULL)) == 0.0 || + (uval = cgiGetVariable(keyword)) == NULL || + (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && + strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) + return (NULL); + + number_points = get_points(number, uval); + if (number_points < cparam->minimum.custom_points || + number_points > cparam->maximum.custom_points) + return (NULL); + + snprintf(buffer, bufsize, "Custom.%g%s", number, uval); + break; + + case PPD_CUSTOM_PASSCODE : + for (uval = val; *uval; uval ++) + if (!isdigit(*uval & 255)) + return (NULL); + + case PPD_CUSTOM_PASSWORD : + case PPD_CUSTOM_STRING : + integer = (long)strlen(val); + if (integer < cparam->minimum.custom_string || + integer > cparam->maximum.custom_string) + return (NULL); + + snprintf(buffer, bufsize, "Custom.%s", val); + break; + } + } + else + { + const char *prefix = "{"; /* Prefix string */ + + + bufptr = buffer; + bufend = buffer + bufsize; + + for (cparam = ppdFirstCustomParam(coption); + cparam; + cparam = ppdNextCustomParam(coption)) + { + snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, + cparam->name); + + if ((val = cgiGetVariable(keyword)) == NULL) + return (NULL); + + snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name); + bufptr += strlen(bufptr); + prefix = " "; + + switch (cparam->type) + { + case PPD_CUSTOM_CURVE : + case PPD_CUSTOM_INVCURVE : + case PPD_CUSTOM_REAL : + if ((number = strtod(val, NULL)) == 0.0 || + number < cparam->minimum.custom_real || + number > cparam->maximum.custom_real) + return (NULL); + + snprintf(bufptr, bufend - bufptr, "%g", number); + break; + + case PPD_CUSTOM_INT : + if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || + integer == LONG_MAX || + integer < cparam->minimum.custom_int || + integer > cparam->maximum.custom_int) + return (NULL); + + snprintf(bufptr, bufend - bufptr, "%ld", integer); + break; + + case PPD_CUSTOM_POINTS : + snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); + + if ((number = strtod(val, NULL)) == 0.0 || + (uval = cgiGetVariable(keyword)) == NULL || + (strcmp(uval, "pt") && strcmp(uval, "in") && + strcmp(uval, "ft") && strcmp(uval, "cm") && + strcmp(uval, "mm") && strcmp(uval, "m"))) + return (NULL); + + number_points = get_points(number, uval); + if (number_points < cparam->minimum.custom_points || + number_points > cparam->maximum.custom_points) + return (NULL); + + snprintf(bufptr, bufend - bufptr, "%g%s", number, uval); + break; + + case PPD_CUSTOM_PASSCODE : + for (uval = val; *uval; uval ++) + if (!isdigit(*uval & 255)) + return (NULL); + + case PPD_CUSTOM_PASSWORD : + case PPD_CUSTOM_STRING : + integer = (long)strlen(val); + if (integer < cparam->minimum.custom_string || + integer > cparam->maximum.custom_string) + return (NULL); + + if ((bufptr + 2) > bufend) + return (NULL); + + bufend --; + *bufptr++ = '\"'; + + while (*val && bufptr < bufend) + { + if (*val == '\\' || *val == '\"') + { + if ((bufptr + 1) >= bufend) + return (NULL); + + *bufptr++ = '\\'; + } + + *bufptr++ = *val++; + } + + if (bufptr >= bufend) + return (NULL); + + *bufptr++ = '\"'; + *bufptr = '\0'; + bufend ++; + break; + } + + bufptr += strlen(bufptr); + } + + if (bufptr == buffer || (bufend - bufptr) < 2) + return (NULL); + + strcpy(bufptr, "}"); + } + + return (buffer); +} + + +/* + * 'get_points()' - Get a value in points. + */ + +static double /* O - Number in points */ +get_points(double number, /* I - Original number */ + const char *uval) /* I - Units */ +{ + if (!strcmp(uval, "mm")) /* Millimeters */ + return (number * 72.0 / 25.4); + else if (!strcmp(uval, "cm")) /* Centimeters */ + return (number * 72.0 / 2.54); + else if (!strcmp(uval, "in")) /* Inches */ + return (number * 72.0); + else if (!strcmp(uval, "ft")) /* Feet */ + return (number * 72.0 * 12.0); + else if (!strcmp(uval, "m")) /* Meters */ + return (number * 72.0 / 0.0254); + else /* Points */ + return (number); +} + + /* * 'match_string()' - Return the number of matching characters. */ @@ -3562,5 +3837,5 @@ match_string(const char *a, /* I - First string */ /* - * End of "$Id: admin.c 4943 2006-01-18 20:30:42Z mike $". + * End of "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $". */