X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=cgi-bin%2Fadmin.c;h=0a981d231841b671a155c0784ed66e4d24753618;hp=0fae095082a7f2bf3259148ccfe551905c7dd8b4;hb=91c84a3551145559de2956179661e111e373db95;hpb=ed4869111296da3b8514751fab9dffaa3146cb87 diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index 0fae09508..0a981d231 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -1,39 +1,33 @@ /* - * "$Id$" + * "$Id: admin.c 7012 2007-10-10 21:22:45Z 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_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_options() - Configure the default options for a queue. * do_set_sharing() - Set printer-is-shared value... * match_string() - Return the number of matching characters. */ @@ -55,13 +49,16 @@ * 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); @@ -122,7 +119,7 @@ main(int argc, /* I - Number of command-line arguments */ do_menu(http); } - else if ((op = cgiGetVariable("OP")) != NULL) + else if ((op = cgiGetVariable("OP")) != NULL && cgiIsPOST()) { /* * Do the operation... @@ -130,25 +127,7 @@ main(int argc, /* I - Number of command-line arguments */ fprintf(stderr, "DEBUG: op=\"%s\"...\n", op); - if (!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 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"))); @@ -168,6 +147,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")) @@ -180,12 +162,18 @@ 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 { /* @@ -197,6 +185,24 @@ 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 { /* @@ -222,6 +228,170 @@ 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; + } + + /* + * 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); + + if ((user = getenv("REMOTE_USER")) == NULL) + user = "guest"; + + 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. */ @@ -259,14 +429,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... */ @@ -467,7 +633,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:") : @@ -569,67 +740,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 @@ -726,6 +931,37 @@ do_am_printer(http_t *http, /* I - HTTP connection */ cgiCopyTemplateLang("choose-serial.tmpl"); cgiEndHTML(); } + 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 && (var = cgiGetVariable("PPD_NAME")) == NULL) { if (modify) @@ -788,39 +1024,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 @@ -836,7 +1039,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 @@ -876,7 +1081,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ cgiCopyTemplateLang("choose-make.tmpl"); cgiEndHTML(); } - else if (!var) + else if (!var || cgiGetVariable("SELECT_MAKE")) { cgiStartHTML(title); cgiCopyTemplateLang("choose-make.tmpl"); @@ -1019,16 +1224,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 */ @@ -1036,21 +1246,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;URL=/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(); @@ -1062,787 +1275,497 @@ 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")); - - fprintf(stderr, "DEBUG: do_config_printer(http=%p)\n", http); /* - * Get the printer name... + * See if we have all of the required information... */ - if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) - httpAssembleURIf(HTTP_URI_CODING_ALL, 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; } - fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri); - /* - * Get the PPD file... + * Cancel the subscription... */ - if ((filename = cupsGetPPD2(http, printer)) == NULL) - { - fputs("DEBUG: No PPD file!?!\n", stderr); + request = ippNewRequest(IPP_CANCEL_SUBSCRIPTION); - cgiStartHTML(title); - cgiShowIPPError(_("Unable to get PPD file!")); - cgiEndHTML(); - return; - } + 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); + + if ((user = getenv("REMOTE_USER")) == NULL) + user = "guest"; - fprintf(stderr, "DEBUG: Got PPD file: \"%s\"\n", filename); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, user); - if ((ppd = ppdOpenFile(filename)) == NULL) + ippDelete(cupsDoRequest(http, request, "/")); + + if (cupsLastError() == IPP_NOT_AUTHORIZED) { - cgiSetVariable("ERROR", ppdErrorString(ppdLastError(&i))); - cgiSetVariable("MESSAGE", cgiText(_("Unable to open PPD file:"))); - cgiStartHTML(title); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) + { + cgiStartHTML(_("Cancel RSS Subscription")); + cgiShowIPPError(_("Unable to cancel RSS subscription:")); } - - if (cgiGetVariable("job_sheets_start") != NULL || - cgiGetVariable("job_sheets_end") != NULL) - have_options = 1; else - have_options = 0; - - ppdMarkDefaults(ppd); - - DEBUG_printf(("

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

\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... */ - fputs("DEBUG: Showing options...\n", stderr); + 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 */ +#ifdef HAVE_GSSAPI + *default_auth_type, + /* DefaultAuthType value */ +#endif /* HAVE_GSSAPI */ + *user_cancel_any; + /* USER_CANCEL_ANY value */ - ppdLocalize(ppd); - cgiStartHTML(cgiText(_("Set Printer Options"))); - cgiCopyTemplateLang("set-printer-options-header.tmpl"); + /* + * Get the checkbox values from the form... + */ - 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 ++; - } + 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"; - cgiCopyTemplateLang("option-conflict.tmpl"); - } + /* + * Get the current server settings... + */ - for (i = ppd->num_groups, group = ppd->groups; - i > 0; - i --, group ++) + if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) { - if (!strcmp(group->name, "InstallableOptions")) - cgiSetVariable("GROUP", cgiText(_("Options Installed"))); - else - cgiSetVariable("GROUP", group->text); - - cgiCopyTemplateLang("option-header.tmpl"); - - for (j = group->num_options, option = group->options; - j > 0; - j --, option ++) - { - if (!strcmp(option->keyword, "PageRegion")) - continue; - - cgiSetVariable("KEYWORD", option->keyword); - cgiSetVariable("KEYTEXT", option->text); - - if (option->conflicted) - cgiSetVariable("CONFLICTED", "1"); - else - cgiSetVariable("CONFLICTED", "0"); + cgiStartHTML(cgiText(_("Change Settings"))); + cgiSetVariable("MESSAGE", + cgiText(_("Unable to change server settings:"))); + cgiSetVariable("ERROR", cupsLastErrorString()); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } - cgiSetSize("CHOICES", 0); - cgiSetSize("TEXT", 0); - for (k = 0, m = 0; k < option->num_choices; k ++) - { - /* - * Hide custom option values... - */ +#ifdef HAVE_GSSAPI + /* + * Get authentication settings... + */ - if (!strcmp(option->choices[k].choice, "Custom")) - continue; + if (cgiGetVariable("KERBEROS")) + default_auth_type = "Negotiate"; + else + { + default_auth_type = cupsGetOption("DefaultAuthType", num_settings, + settings); + if (!strcasecmp(default_auth_type, "Negotiate")) + default_auth_type = "Basic"; + } - 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(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); /* - * 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... - */ + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiSetVariable("MESSAGE", cgiText(_("Unable to create temporary file:"))); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(tempfile); + return; + } - cgiSetVariable("GROUP", cgiText(_("Banners"))); - cgiCopyTemplateLang("option-header.tmpl"); + 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; + } - 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); - } + /* + * Copy the cupsd.conf text from the form variable... + */ - attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO); + start = cgiGetVariable("CUPSDCONF"); + while (start) + { + if ((end = strstr(start, "\r\n")) == NULL) + if ((end = strstr(start, "\n")) == NULL) + end = start + strlen(start); - cgiSetVariable("KEYWORD", "job_sheets_start"); - cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner"))); - cgiSetVariable("DEFCHOICE", attr == NULL ? - "" : attr->values[0].string.text); + cupsFileWrite(temp, start, end - start); + cupsFilePutChar(temp, '\n'); - cgiCopyTemplateLang("option-pickone.tmpl"); + if (*end == '\r') + start = end + 2; + else if (*end == '\n') + start = end + 1; + else + start = NULL; + } - cgiSetVariable("KEYWORD", "job_sheets_end"); - cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner"))); - cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ? - "" : attr->values[1].string.text); + cupsFileClose(temp); - cgiCopyTemplateLang("option-pickone.tmpl"); + /* + * Upload the configuration file to the server... + */ - cgiCopyTemplateLang("option-trailer.tmpl"); - } + status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); - 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... - */ + 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)); - cgiSetVariable("GROUP", cgiText(_("Policies"))); - cgiCopyTemplateLang("option-header.tmpl"); + cgiStartHTML(cgiText(_("Edit Configuration File"))); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); - /* - * Error policy... - */ - - 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... */ - fputs("DEBUG: Setting options...\n", stderr); - - 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(cgiText(_("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") || - !strcmp(keyword, "PaperDimension") || - !strcmp(keyword, "ImageableArea")) - 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(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); - - 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;URL=/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... - */ - - int num_settings; /* Number of server settings */ - cups_option_t *settings; /* Server settings */ + ipp_t *request; /* IPP request */ + char uri[HTTP_MAX_URI]; /* Job URI */ + const char *pclass; /* Printer class name */ - num_settings = 0; - num_settings = cupsAddOption(CUPS_SERVER_DEBUG_LOGGING, - cgiGetVariable("DEBUG_LOGGING") ? "1" : "0", - num_settings, &settings); - num_settings = cupsAddOption(CUPS_SERVER_REMOTE_ADMIN, - cgiGetVariable("REMOTE_ADMIN") ? "1" : "0", - num_settings, &settings); - num_settings = cupsAddOption(CUPS_SERVER_REMOTE_PRINTERS, - cgiGetVariable("REMOTE_PRINTERS") ? "1" : "0", - num_settings, &settings); - num_settings = cupsAddOption(CUPS_SERVER_SHARE_PRINTERS, - cgiGetVariable("SHARE_PRINTERS") ? "1" : "0", - num_settings, &settings); - num_settings = cupsAddOption(CUPS_SERVER_USER_CANCEL_ANY, - cgiGetVariable("USER_CANCEL_ANY") ? "1" : "0", - num_settings, &settings); - - - if (!_cupsAdminSetServerSettings(http, num_settings, settings)) - { - 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"); - } - - cupsFreeOptions(num_settings, settings); - - cgiEndHTML(); - } - else if (cgiIsPOST()) - { - /* - * Save hand-edited config file... - */ - - 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 */ - - - /* - * Create a temporary file for the new cupsd.conf file... - */ - - 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; - } - - 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; - } - - /* - * Copy the cupsd.conf text from the form variable... - */ - - 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'); - - if (*end == '\r') - start = end + 2; - else if (*end == '\n') - start = end + 1; - else - start = NULL; - } - - cupsFileClose(temp); - - /* - * Upload the configuration file to the server... - */ - - 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)); - - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiCopyTemplateLang("error.tmpl"); - } - else - { - cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); - - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiCopyTemplateLang("restart.tmpl"); - } - - cgiEndHTML(); - - 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 */ - - - /* - * Locate the cupsd.conf file... - */ - - if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) - server_root = CUPS_SERVERROOT; - - snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root); - - /* - * Figure out the size... - */ - - 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(); - - perror(filename); - return; - } - - 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(); - - 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... - */ - - cgiStartHTML(cgiText(_("Edit Configuration File"))); - cgiSetVariable("MESSAGE", - cgiText(_("Unable to access cupsd.conf file:"))); - cgiSetVariable("ERROR", strerror(errno)); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - - perror(filename); - return; - } - - /* - * Allocate memory and load the file into a string buffer... - */ - - buffer = calloc(1, info.st_size + 1); - - cupsFileRead(cupsd, buffer, info.st_size); - cupsFileClose(cupsd); - - cgiSetVariable("CUPSDCONF", buffer); - free(buffer); - - /* - * Show the current config file... - */ - - cgiStartHTML(cgiText(_("Edit Configuration File"))); - - printf("\n", filename); - - cgiCopyTemplateLang("edit-config.tmpl"); - - cgiEndHTML(); - } -} - - -/* - * 'do_delete_class()' - Delete a class... - */ - -static void -do_delete_class(http_t *http) /* I - HTTP connection */ -{ - ipp_t *request; /* IPP request */ - char uri[HTTP_MAX_URI]; /* Job URI */ - const char *pclass; /* Printer class name */ - - - /* - * Get form variables... - */ + /* + * Get form variables... + */ if (cgiGetVariable("CONFIRM") == NULL) { @@ -1888,6 +1811,20 @@ do_delete_class(http_t *http) /* I - HTTP connection */ * Show the results... */ + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() <= IPP_OK_CONFLICT) + { + /* + * Redirect successful updates back to the classes page... + */ + + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/classes"); + } + cgiStartHTML(cgiText(_("Delete Class"))); if (cupsLastError() > IPP_OK_CONFLICT) @@ -1959,6 +1896,20 @@ do_delete_printer(http_t *http) /* I - HTTP connection */ * Show the results... */ + 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... + */ + + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/printers"); + } + cgiStartHTML(cgiText(_("Delete Printer"))); if (cupsLastError() > IPP_OK_CONFLICT) @@ -2107,68 +2058,33 @@ do_export(http_t *http) /* I - HTTP connection */ /* - * 'do_menu()' - Show the main menu... + * 'do_list_printers()' - List available printers... */ static void -do_menu(http_t *http) /* I - HTTP connection */ +do_list_printers(http_t *http) /* I - HTTP connection */ { - 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 */ ipp_attribute_t *attr; /* IPP attribute */ + cgiStartHTML(cgiText(_("List Available Printers"))); + fflush(stdout); + /* - * Get the current server settings... + * Get the list of printers and their devices... */ - if (!_cupsAdminGetServerSettings(http, &num_settings, &settings)) - { - cgiSetVariable("SETTINGS_MESSAGE", - cgiText(_("Unable to open cupsd.conf file:"))); - cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString()); - } - - if ((val = cupsGetOption(CUPS_SERVER_DEBUG_LOGGING, num_settings, - settings)) != NULL && atoi(val)) - cgiSetVariable("DEBUG_LOGGING", "CHECKED"); + request = ippNewRequest(CUPS_GET_PRINTERS); - if ((val = cupsGetOption(CUPS_SERVER_REMOTE_ADMIN, num_settings, - settings)) != NULL && atoi(val)) - cgiSetVariable("REMOTE_ADMIN", "CHECKED"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "device-uri"); - 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"); - - cupsFreeOptions(num_settings, settings); - - /* - * 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); + 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) { @@ -2269,8 +2185,8 @@ do_menu(http_t *http) /* I - HTTP connection */ * Not found, so it must be a new printer... */ - char options[1024], /* Form variables for this device */ - *options_ptr; /* Pointer into string */ + char option[1024], /* Form variables for this device */ + *option_ptr; /* Pointer into string */ const char *ptr; /* Pointer into device string */ @@ -2282,9 +2198,6 @@ do_menu(http_t *http) /* I - HTTP connection */ * suitable name. */ - strcpy(options, "PRINTER_NAME="); - options_ptr = options + strlen(options); - if (strncasecmp(device_info, "unknown", 7)) ptr = device_info; else if ((ptr = strstr(device_uri, "://")) != NULL) @@ -2292,49 +2205,20 @@ do_menu(http_t *http) /* I - HTTP connection */ else ptr = device_make_and_model; - for (; - options_ptr < (options + sizeof(options) - 1) && *ptr; + for (option_ptr = option; + option_ptr < (option + sizeof(option) - 1) && *ptr; ptr ++) if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || *ptr == '.') - *options_ptr++ = *ptr; - else if ((*ptr == ' ' || *ptr == '/') && options_ptr[-1] != '_') - *options_ptr++ = '_'; + *option_ptr++ = *ptr; + else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_') + *option_ptr++ = '_'; else if (*ptr == '?' || *ptr == '(') break; - /* - * Then add the make and model in the printer info, so - * that MacOS clients see something reasonable... - */ - - strlcpy(options_ptr, "&PRINTER_LOCATION=Local+Printer" - "&PRINTER_INFO=", - sizeof(options) - (options_ptr - options)); - options_ptr += strlen(options_ptr); - - cgiFormEncode(options_ptr, device_make_and_model, - sizeof(options) - (options_ptr - options)); - options_ptr += strlen(options_ptr); - - /* - * Then copy the device URI... - */ - - 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); + *option_ptr = '\0'; - if (options_ptr < (options + sizeof(options) - 1)) - { - *options_ptr++ = '|'; - cgiFormEncode(options_ptr, device_make_and_model, - sizeof(options) - (options_ptr - options)); - } + cgiSetArray("TEMPLATE_NAME", i, option); /* * Finally, set the form variables for this printer... @@ -2342,7 +2226,6 @@ do_menu(http_t *http) /* I - HTTP connection */ 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 ++; } @@ -2367,6 +2250,77 @@ do_menu(http_t *http) /* I - HTTP connection */ } } + /* + * Finally, show the printer list... + */ + + cgiCopyTemplateLang("list-available-printers.tmpl"); + + cgiEndHTML(); +} + + +/* + * 'do_menu()' - Show the main menu... + */ + +static void +do_menu(http_t *http) /* I - HTTP connection */ +{ + 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 */ + + + /* + * Get the current server settings... + */ + + if (!cupsAdminGetServerSettings(http, &num_settings, &settings)) + { + cgiSetVariable("SETTINGS_MESSAGE", + cgiText(_("Unable to open cupsd.conf file:"))); + cgiSetVariable("SETTINGS_ERROR", cupsLastErrorString()); + } + + 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... */ @@ -2401,6 +2355,21 @@ do_menu(http_t *http) /* I - HTTP connection */ else perror(filename); + /* + * Subscriptions... + */ + + request = ippNewRequest(IPP_GET_SUBSCRIPTIONS); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/"); + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + ippDelete(response); + } + /* * Finally, show the main menu template... */ @@ -2463,7 +2432,12 @@ do_printer_op(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(_("Unable to change printer:")); @@ -2530,201 +2504,760 @@ do_set_allowed_users(http_t *http) /* I - HTTP connection */ }; - is_class = cgiGetVariable("IS_CLASS"); - printer = cgiGetVariable("PRINTER_NAME"); + is_class = cgiGetVariable("IS_CLASS"); + printer = cgiGetVariable("PRINTER_NAME"); + + if (!printer) + { + cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiStartHTML(cgiText(_("Set Allowed Users"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + users = cgiGetVariable("users"); + type = cgiGetVariable("type"); + + 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 + */ + + 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); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + } + + cgiStartHTML(cgiText(_("Set Allowed Users"))); + + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else if (cupsLastError() > IPP_OK_CONFLICT) + cgiShowIPPError(_("Unable to get printer attributes:")); + else + cgiCopyTemplateLang("users.tmpl"); + + cgiEndHTML(); + } + else + { + /* + * Save the changes... + */ + + for (num_users = 0, ptr = (char *)users; *ptr; num_users ++) + { + /* + * 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; + } + + /* + * Advance to the next name... + */ + + 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); + + 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... + */ + + attr->values[i].string.text = strdup(ptr); + + /* + * Advance to the next name... + */ + + ptr = end; + } + } + + /* + * Do the request and get back a response... + */ + + ippDelete(cupsDoRequest(http, request, "/admin/")); + + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + 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... + */ + + 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(cgiText(_("Set Allowed Users"))); + + cgiCopyTemplateLang(is_class ? "class-modified.tmpl" : + "printer-modified.tmpl"); + } + + cgiEndHTML(); + } +} + + +/* + * 'do_set_options()' - Configure the default options for a queue. + */ + +static void +do_set_options(http_t *http, /* I - HTTP connection */ + int is_class) /* I - Set options for class? */ +{ + 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 */ + + + title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options")); + + fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http, + is_class); + + /* + * Get the printer name... + */ + + 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 + { + cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiStartHTML(title); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + 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); + + 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; + } + } + else + { + fputs("DEBUG: No PPD file\n", stderr); + ppd = NULL; + } + + if (cgiGetVariable("job_sheets_start") != NULL || + cgiGetVariable("job_sheets_end") != NULL) + have_options = 1; + else + have_options = 0; + + if (ppd) + { + ppdMarkDefaults(ppd); + + DEBUG_printf(("

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

\n" + "

ppdConflicts(ppd) = %d\n", ppdConflicts(ppd))); + } + + if (!have_options || ppdConflicts(ppd)) + { + /* + * Show the options to the user... + */ + + fputs("DEBUG: Showing options...\n", stderr); + + cgiStartHTML(cgiText(_("Set Printer Options"))); + cgiCopyTemplateLang("set-printer-options-header.tmpl"); + + if (ppd) + { + ppdLocalize(ppd); + + 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 ++; + } + + cgiCopyTemplateLang("option-conflict.tmpl"); + } + + 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); + + cgiCopyTemplateLang("option-header.tmpl"); + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + if (!strcmp(option->keyword, "PageRegion")) + continue; + + cgiSetVariable("KEYWORD", option->keyword); + cgiSetVariable("KEYTEXT", option->text); + + if (option->conflicted) + cgiSetVariable("CONFLICTED", "1"); + else + cgiSetVariable("CONFLICTED", "0"); + + cgiSetSize("CHOICES", 0); + cgiSetSize("TEXT", 0); + for (k = 0, m = 0; k < option->num_choices; k ++) + { + /* + * Hide custom option values... + */ + + if (!strcmp(option->choices[k].choice, "Custom")) + continue; + + cgiSetArray("CHOICES", m, option->choices[k].choice); + cgiSetArray("TEXT", m, option->choices[k].text); + + m ++; + + if (option->choices[k].marked) + cgiSetVariable("DEFCHOICE", option->choices[k].choice); + } + + 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; + } + } + + cgiCopyTemplateLang("option-trailer.tmpl"); + } + } + + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); + + 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); + + /* + * 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... + */ + + cgiSetVariable("GROUP", cgiText(_("Banners"))); + cgiCopyTemplateLang("option-header.tmpl"); + + 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); + + cgiSetVariable("KEYWORD", "job_sheets_start"); + cgiSetVariable("KEYTEXT", cgiText(_("Starting Banner"))); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); + + cgiCopyTemplateLang("option-pickone.tmpl"); + + cgiSetVariable("KEYWORD", "job_sheets_end"); + cgiSetVariable("KEYTEXT", cgiText(_("Ending Banner"))); + cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ? + "" : attr->values[1].string.text); + + cgiCopyTemplateLang("option-pickone.tmpl"); + + cgiCopyTemplateLang("option-trailer.tmpl"); + } + + 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... + */ + + cgiSetVariable("GROUP", cgiText(_("Policies"))); + cgiCopyTemplateLang("option-header.tmpl"); + + /* + * Error policy... + */ + + 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); + } - if (!printer) - { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); - cgiStartHTML(cgiText(_("Set Allowed Users"))); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; - } + cgiCopyTemplateLang("option-pickone.tmpl"); - users = cgiGetVariable("users"); - type = cgiGetVariable("type"); + /* + * Operation policy... + */ - 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 - */ + attr = ippFindAttribute(response, "printer-op-policy-supported", + IPP_TAG_ZERO); - request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); + 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); + } - 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); + attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO); - ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "requested-attributes", - (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); + cgiSetVariable("KEYWORD", "printer_op_policy"); + cgiSetVariable("KEYTEXT", cgiText(_("Operation Policy"))); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); - /* - * Do the request and get back a response... - */ + cgiCopyTemplateLang("option-pickone.tmpl"); + } - if ((response = cupsDoRequest(http, request, "/")) != NULL) - { - cgiSetIPPVars(response, NULL, NULL, NULL, 0); + cgiCopyTemplateLang("option-trailer.tmpl"); + } ippDelete(response); } - cgiStartHTML(cgiText(_("Set Allowed Users"))); - - if (cupsLastError() > IPP_OK_CONFLICT) - cgiShowIPPError(_("Unable to get printer attributes:")); - else - cgiCopyTemplateLang("users.tmpl"); - - cgiEndHTML(); - } - else - { /* - * Save the changes... + * Binary protocol support... */ - for (num_users = 0, ptr = (char *)users; *ptr; num_users ++) + if (ppd && ppd->protocols && strstr(ppd->protocols, "BCP")) { - /* - * Skip whitespace and commas... - */ - - while (*ptr == ',' || isspace(*ptr & 255)) - ptr ++; + protocol = ppdFindAttr(ppd, "cupsProtocol", NULL); - if (*ptr == '\'' || *ptr == '\"') - { - /* - * Scan quoted name... - */ + cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol"))); + cgiCopyTemplateLang("option-header.tmpl"); - quote = *ptr++; + cgiSetSize("CHOICES", 2); + cgiSetSize("TEXT", 2); + cgiSetArray("CHOICES", 0, "None"); + cgiSetArray("TEXT", 0, cgiText(_("None"))); - for (end = ptr; *end; end ++) - if (*end == quote) - break; + if (strstr(ppd->protocols, "TBCP")) + { + cgiSetArray("CHOICES", 1, "TBCP"); + cgiSetArray("TEXT", 1, "TBCP"); } else { - /* - * Scan space or comma-delimited name... - */ - - for (end = ptr; *end; end ++) - if (isspace(*end & 255) || *end == ',') - break; + cgiSetArray("CHOICES", 1, "BCP"); + cgiSetArray("TEXT", 1, "BCP"); } - /* - * Advance to the next name... - */ + cgiSetVariable("KEYWORD", "protocol"); + cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol"))); + cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None"); - ptr = end; + cgiCopyTemplateLang("option-pickone.tmpl"); + + cgiCopyTemplateLang("option-trailer.tmpl"); } + cgiCopyTemplateLang("set-printer-options-trailer.tmpl"); + cgiEndHTML(); + } + else + { /* - * Build a CUPS-Add-Printer/Class request, which requires the following - * attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri - * requesting-user-name-{allowed,denied} + * Set default options... */ - 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); + fputs("DEBUG: Setting options...\n", stderr); - if (num_users == 0) - ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, - "requesting-user-name-allowed", NULL, "all"); - else + if (filename) { - attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_NAME, - type, num_users, NULL, NULL); + out = cupsTempFile2(tempfile, sizeof(tempfile)); + in = cupsFileOpen(filename, "r"); - for (i = 0, ptr = (char *)users; *ptr; i ++) + if (!in || !out) { - /* - * Skip whitespace and commas... - */ + cgiSetVariable("ERROR", strerror(errno)); + cgiStartHTML(cgiText(_("Set Printer Options"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); - while (*ptr == ',' || isspace(*ptr & 255)) - ptr ++; + if (in) + cupsFileClose(in); - if (*ptr == '\'' || *ptr == '\"') + if (out) { - /* - * Scan quoted name... - */ + cupsFileClose(out); + unlink(tempfile); + } - quote = *ptr++; + unlink(filename); + return; + } - for (end = ptr; *end; end ++) - if (*end == quote) - break; - } + while (cupsFileGets(in, line, sizeof(line))) + { + if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol")) + continue; + else if (strncmp(line, "*Default", 8)) + cupsFilePrintf(out, "%s\n", line); else { /* - * Scan space or comma-delimited name... + * Get default option name... */ - for (end = ptr; *end; end ++) - if (isspace(*end & 255) || *end == ',') + strlcpy(keyword, line + 8, sizeof(keyword)); + + for (keyptr = keyword; *keyptr; keyptr ++) + if (*keyptr == ':' || isspace(*keyptr & 255)) break; - } - /* - * Terminate the name... - */ + *keyptr = '\0'; - if (*end) - *end++ = '\0'; + if (!strcmp(keyword, "PageRegion") || + !strcmp(keyword, "PaperDimension") || + !strcmp(keyword, "ImageableArea")) + var = cgiGetVariable("PageSize"); + else + var = cgiGetVariable(keyword); - /* - * Add the name... - */ + if (var != NULL) + cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); + else + cupsFilePrintf(out, "%s\n", line); + } + } - attr->values[i].string.text = strdup(ptr); + if ((var = cgiGetVariable("protocol")) != NULL) + cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol")); - /* - * Advance to the next name... - */ + cupsFileClose(in); + cupsFileClose(out); + } + else + { + /* + * Make sure temporary filename is cleared when there is no PPD... + */ - ptr = end; - } + tempfile[0] = '\0'; } + /* + * Build a CUPS_ADD_MODIFY_CLASS/PRINTER request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * job-sheets-default + * printer-error-policy + * printer-op-policy + * [ppd file] + */ + + request = ippNewRequest(is_class ? CUPS_ADD_MODIFY_CLASS : + CUPS_ADD_MODIFY_PRINTER); + + 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 = _cupsStrAlloc(cgiGetVariable("job_sheets_start")); + attr->values[1].string.text = _cupsStrAlloc(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 ((var = cgiGetVariable("printer_op_policy")) != NULL) + attr = 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 { @@ -2732,24 +3265,27 @@ 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;URL=/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); } @@ -2812,7 +3348,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:")); @@ -2891,5 +3432,5 @@ match_string(const char *a, /* I - First string */ /* - * End of "$Id$". + * End of "$Id: admin.c 7012 2007-10-10 21:22:45Z mike $". */