X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=cgi-bin%2Fadmin.c;h=fdd1c47acabeaf1f14156ec1951444b3a532873d;hb=321d8d57dacf00e4ae19558dc9444519f4d9ade1;hp=3f94b8826973231aa86ba2a0718d18f7f7529ce3;hpb=75bd9771f6e44fdd887ee90faac46f403aefc0fc;p=thirdparty%2Fcups.git diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c index 3f94b8826..fdd1c47ac 100644 --- a/cgi-bin/admin.c +++ b/cgi-bin/admin.c @@ -1,9 +1,9 @@ /* - * "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $" + * "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $" * - * Administration CGI for the Common UNIX Printing System (CUPS). + * Administration CGI for CUPS. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2011 by Apple Inc. * Copyright 1997-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the @@ -15,21 +15,23 @@ * Contents: * * main() - Main entry for CGI. + * choose_device_cb() - Add a device to the device selection page. * 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_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_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_set_allowed_users() - Set the allowed/denied users for a queue. + * do_set_default() - Set the server default printer/class. * 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. + * do_set_sharing() - Set printer-is-shared value. + * get_option_value() - Return the value of an option. + * get_points() - Get a value in points. */ /* @@ -38,33 +40,48 @@ #include "cgi-private.h" #include -#include +#include #include #include #include #include +#include + + +/* + * Local globals... + */ + +static int current_device = 0; /* Current device shown */ /* * Local functions... */ +static void choose_device_cb(const char *device_class, + const char *device_id, const char *device_info, + const char *device_make_and_model, + const char *device_uri, + const char *device_location, + const char *title); 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_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_default(http_t *http); +static void do_set_options(http_t *http, int is_class); static void do_set_sharing(http_t *http); -static int match_string(const char *a, const char *b); +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); /* @@ -104,12 +121,13 @@ main(int argc, /* I - Number of command-line arguments */ */ cgiSetVariable("SECTION", "admin"); + cgiSetVariable("REFRESH_PAGE", ""); /* * See if we have form data... */ - if (!cgiInitialize()) + if (!cgiInitialize() || !cgiGetVariable("OP")) { /* * Nope, send the administration menu... @@ -127,24 +145,33 @@ main(int argc, /* I - Number of command-line arguments */ fprintf(stderr, "DEBUG: op=\"%s\"...\n", op); - 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"))); - else if (!strcmp(op, "start-class")) - do_printer_op(http, IPP_RESUME_PRINTER, cgiText(_("Start Class"))); - else if (!strcmp(op, "stop-class")) - do_printer_op(http, IPP_PAUSE_PRINTER, cgiText(_("Stop Class"))); - else if (!strcmp(op, "accept-jobs")) - do_printer_op(http, CUPS_ACCEPT_JOBS, cgiText(_("Accept Jobs"))); - else if (!strcmp(op, "reject-jobs")) - do_printer_op(http, CUPS_REJECT_JOBS, cgiText(_("Reject Jobs"))); - else if (!strcmp(op, "purge-jobs")) - do_printer_op(http, IPP_PURGE_JOBS, cgiText(_("Purge Jobs"))); + if (!*op) + { + const char *printer = getenv("PRINTER_NAME"), + /* Printer or class name */ + *server_port = getenv("SERVER_PORT"); + /* Port number string */ + int port = atoi(server_port ? server_port : "0"); + /* Port number */ + char uri[1024]; /* URL */ + + if (printer) + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), + getenv("HTTPS") ? "https" : "http", NULL, + getenv("SERVER_NAME"), port, "/%s/%s", + cgiGetVariable("IS_CLASS") ? "classes" : "printers", + printer); + else + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), + getenv("HTTPS") ? "https" : "http", NULL, + getenv("SERVER_NAME"), port, "/admin"); + + printf("Location: %s\n\n", uri); + } else if (!strcmp(op, "set-allowed-users")) do_set_allowed_users(http); else if (!strcmp(op, "set-as-default")) - do_printer_op(http, CUPS_SET_DEFAULT, cgiText(_("Set As Default"))); + do_set_default(http); else if (!strcmp(op, "set-sharing")) do_set_sharing(http); else if (!strcmp(op, "find-new-printers") || @@ -177,7 +204,7 @@ main(int argc, /* I - Number of command-line arguments */ else { /* - * Bad operation code... Display an error... + * Bad operation code - display an error... */ cgiStartHTML(cgiText(_("Administration"))); @@ -187,7 +214,7 @@ main(int argc, /* I - Number of command-line arguments */ } else if (op && !strcmp(op, "redirect")) { - const char *url; /* Redirection URL... */ + const char *url; /* Redirection URL... */ char prefix[1024]; /* URL prefix */ @@ -198,15 +225,60 @@ main(int argc, /* I - Number of command-line arguments */ snprintf(prefix, sizeof(prefix), "http://%s:%s", getenv("SERVER_NAME"), getenv("SERVER_PORT")); + fprintf(stderr, "DEBUG: redirecting with prefix %s!\n", prefix); + if ((url = cgiGetVariable("URL")) != NULL) - printf("Location: %s%s\n\n", prefix, url); + { + char encoded[1024], /* Encoded URL string */ + *ptr; /* Pointer into encoded string */ + + + ptr = encoded; + if (*url != '/') + *ptr++ = '/'; + + for (; *url && ptr < (encoded + sizeof(encoded) - 4); url ++) + { + if (strchr("%@&+ <>#=", *url) || *url < ' ' || *url & 128) + { + /* + * Percent-encode this character; safe because we have at least 4 + * bytes left in the array... + */ + + sprintf(ptr, "%%%02X", *url & 255); + ptr += 3; + } + else + *ptr++ = *url; + } + + *ptr = '\0'; + + if (*url) + { + /* + * URL was too long, just redirect to the admin page... + */ + + printf("Location: %s/admin\n\n", prefix); + } + else + { + /* + * URL is OK, redirect there... + */ + + printf("Location: %s%s\n\n", prefix, encoded); + } + } 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"))); @@ -228,6 +300,50 @@ main(int argc, /* I - Number of command-line arguments */ } +/* + * 'choose_device_cb()' - Add a device to the device selection page. + */ + +static void +choose_device_cb( + const char *device_class, /* I - Class */ + const char *device_id, /* I - 1284 device ID */ + const char *device_info, /* I - Description */ + const char *device_make_and_model, /* I - Make and model */ + const char *device_uri, /* I - Device URI */ + const char *device_location, /* I - Location */ + const char *title) /* I - Page title */ +{ + /* + * For modern browsers, start a multi-part page so we can show that something + * is happening. Non-modern browsers just get everything at the end... + */ + + if (current_device == 0 && cgiSupportsMultipart()) + { + cgiStartMultipart(); + cgiStartHTML(title); + cgiCopyTemplateLang("choose-device.tmpl"); + cgiEndHTML(); + fflush(stdout); + } + + + /* + * Add the device to the array... + */ + + cgiSetArray("device_class", current_device, device_class); + cgiSetArray("device_id", current_device, device_id); + cgiSetArray("device_info", current_device, device_info); + cgiSetArray("device_make_and_model", current_device, device_make_and_model); + cgiSetArray("device_uri", current_device, device_uri); + cgiSetArray("device_location", current_device, device_location); + + current_device ++; +} + + /* * 'do_add_rss_subscription()' - Add a RSS subscription. */ @@ -293,6 +409,31 @@ do_add_rss_subscription(http_t *http) /* I - HTTP connection */ * and classes and (re)show the add page... */ + if (cgiGetVariable("EVENT_JOB_CREATED")) + cgiSetVariable("EVENT_JOB_CREATED", "CHECKED"); + if (cgiGetVariable("EVENT_JOB_COMPLETED")) + cgiSetVariable("EVENT_JOB_COMPLETED", "CHECKED"); + if (cgiGetVariable("EVENT_JOB_STOPPED")) + cgiSetVariable("EVENT_JOB_STOPPED", "CHECKED"); + if (cgiGetVariable("EVENT_JOB_CONFIG_CHANGED")) + cgiSetVariable("EVENT_JOB_CONFIG_CHANGED", "CHECKED"); + if (cgiGetVariable("EVENT_PRINTER_STOPPED")) + cgiSetVariable("EVENT_PRINTER_STOPPED", "CHECKED"); + if (cgiGetVariable("EVENT_PRINTER_ADDED")) + cgiSetVariable("EVENT_PRINTER_ADDED", "CHECKED"); + if (cgiGetVariable("EVENT_PRINTER_MODIFIED")) + cgiSetVariable("EVENT_PRINTER_MODIFIED", "CHECKED"); + if (cgiGetVariable("EVENT_PRINTER_DELETED")) + cgiSetVariable("EVENT_PRINTER_DELETED", "CHECKED"); + if (cgiGetVariable("EVENT_SERVER_STARTED")) + cgiSetVariable("EVENT_SERVER_STARTED", "CHECKED"); + if (cgiGetVariable("EVENT_SERVER_STOPPED")) + cgiSetVariable("EVENT_SERVER_STOPPED", "CHECKED"); + if (cgiGetVariable("EVENT_SERVER_RESTARTED")) + cgiSetVariable("EVENT_SERVER_RESTARTED", "CHECKED"); + if (cgiGetVariable("EVENT_SERVER_AUDIT")) + cgiSetVariable("EVENT_SERVER_AUDIT", "CHECKED"); + request = ippNewRequest(CUPS_GET_PRINTERS); response = cupsDoRequest(http, request, "/"); @@ -415,6 +556,7 @@ do_am_class(http_t *http, /* I - HTTP connection */ ipp_attribute_t *attr; /* member-uris attribute */ char uri[HTTP_MAX_URI]; /* Device or printer URI */ const char *name, /* Pointer to class name */ + *op, /* Operation name */ *ptr; /* Pointer to CGI variable */ const char *title; /* Title of page */ static const char * const pattrs[] = /* Requested printer attributes */ @@ -426,6 +568,7 @@ do_am_class(http_t *http, /* I - HTTP connection */ title = cgiText(modify ? _("Modify Class") : _("Add Class")); + op = cgiGetVariable("OP"); name = cgiGetVariable("PRINTER_NAME"); if (cgiGetVariable("PRINTER_LOCATION") == NULL) @@ -440,10 +583,22 @@ do_am_class(http_t *http, /* I - HTTP connection */ request = ippNewRequest(CUPS_GET_PRINTERS); + 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_CLASS | CUPS_PRINTER_REMOTE | + CUPS_PRINTER_IMPLICIT); + /* * Do the request and get back a response... */ + cgiClearVariables(); + if (op) + cgiSetVariable("OP", op); + if (name) + cgiSetVariable("PRINTER_NAME", name); + if ((response = cupsDoRequest(http, request, "/")) != NULL) { /* @@ -576,6 +731,15 @@ do_am_class(http_t *http, /* I - HTTP connection */ return; } + if (!name) + { + cgiStartHTML(title); + cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + for (ptr = name; *ptr; ptr ++) if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') break; @@ -610,8 +774,7 @@ do_am_class(http_t *http, /* I - HTTP connection */ request = ippNewRequest(CUPS_ADD_CLASS); httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL, - "localhost", 0, "/classes/%s", - cgiGetVariable("PRINTER_NAME")); + "localhost", 0, "/classes/%s", name); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -631,7 +794,7 @@ do_am_class(http_t *http, /* I - HTTP connection */ attr = ippAddStrings(request, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", num_printers, NULL, NULL); for (i = 0; i < num_printers; i ++) - attr->values[i].string.text = strdup(cgiGetArray("MEMBER_URIS", i)); + attr->values[i].string.text = _cupsStrAlloc(cgiGetArray("MEMBER_URIS", i)); } /* @@ -811,8 +974,6 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if (!cgiGetVariable("CURRENT_MAKE")) cgiSetVariable("CURRENT_MAKE", make); - cgiSetVariable("PPD_MAKE", make); - if (!cgiGetVariable("CURRENT_MAKE_AND_MODEL")) cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr); @@ -829,7 +990,8 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if (isalnum(*uriptr & 255) || *uriptr == '_' || *uriptr == '-' || *uriptr == '.') *tptr++ = *uriptr; - else if ((*uriptr == ' ' || *uriptr == '/') && tptr[-1] != '_') + else if ((*uriptr == ' ' || *uriptr == '/') && tptr > template && + tptr[-1] != '_') *tptr++ = '_'; else if (*uriptr == '?' || *uriptr == '(') break; @@ -844,56 +1006,65 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if (!var) { /* - * Build a CUPS_GET_DEVICES request, which requires the following - * attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri + * Look for devices so the user can pick something... */ - fputs("DEBUG: Getting list of devices...\n", stderr); - - request = ippNewRequest(CUPS_GET_DEVICES); + if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) + { + strlcpy(uri, attr->values[0].string.text, sizeof(uri)); + if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0) + *uriptr = '\0'; - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, "ipp://localhost/printers/"); + cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); + cgiSetVariable("CURRENT_DEVICE_SCHEME", uri); + } /* - * Do the request and get back a response... + * Scan for devices for up to 30 seconds... */ - if ((response = cupsDoRequest(http, request, "/")) != NULL) + fputs("DEBUG: Getting list of devices...\n", stderr); + + current_device = 0; + if (cupsGetDevices(http, 5, CUPS_INCLUDE_ALL, CUPS_EXCLUDE_NONE, + (cups_device_cb_t)choose_device_cb, + (void *)title) == IPP_OK) { fputs("DEBUG: Got device list!\n", stderr); - cgiSetIPPVars(response, NULL, NULL, NULL, 0); - ippDelete(response); + if (cgiSupportsMultipart()) + cgiStartMultipart(); + + cgiSetVariable("CUPS_GET_DEVICES_DONE", "1"); + cgiStartHTML(title); + cgiCopyTemplateLang("choose-device.tmpl"); + cgiEndHTML(); + + if (cgiSupportsMultipart()) + cgiEndMultipart(); } else + { fprintf(stderr, "ERROR: CUPS-Get-Devices request failed with status %x: %s\n", cupsLastError(), cupsLastErrorString()); - - /* - * Let the user choose... - */ - - if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) - { - strlcpy(uri, attr->values[0].string.text, sizeof(uri)); - if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0) - *uriptr = '\0'; - - cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); - cgiSetVariable("CURRENT_DEVICE_SCHEME", uri); + if (cupsLastError() == IPP_NOT_AUTHORIZED) + { + puts("Status: 401\n"); + exit(0); + } + else + { + cgiStartHTML(title); + cgiShowIPPError(modify ? _("Unable to modify printer:") : + _("Unable to add printer:")); + cgiEndHTML(); + return; + } } - - cgiStartHTML(title); - cgiCopyTemplateLang("choose-device.tmpl"); - cgiEndHTML(); } - else if (strchr(var, '/') == NULL) + else if (!strchr(var, '/') || + (!strncmp(var, "lpd://", 6) && !strchr(var + 6, '/'))) { if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) { @@ -902,7 +1073,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ */ if (strncmp(attr->values[0].string.text, var, strlen(var)) == 0) - cgiSetVariable("DEVICE_URI", attr->values[0].string.text); + cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); } /* @@ -949,7 +1120,20 @@ do_am_printer(http_t *http, /* I - HTTP connection */ */ if (oldinfo) - cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0); + { + if ((attr = ippFindAttribute(oldinfo, "printer-info", + IPP_TAG_TEXT)) != NULL) + cgiSetVariable("PRINTER_INFO", attr->values[0].string.text); + + if ((attr = ippFindAttribute(oldinfo, "printer-location", + IPP_TAG_TEXT)) != NULL) + cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text); + + if ((attr = ippFindAttribute(oldinfo, "printer-is-shared", + IPP_TAG_BOOLEAN)) != NULL) + cgiSetVariable("PRINTER_IS_SHARED", + attr->values[0].boolean ? "1" : "0"); + } cgiCopyTemplateLang("modify-printer.tmpl"); } @@ -959,6 +1143,13 @@ do_am_printer(http_t *http, /* I - HTTP connection */ * Get the name, location, and description for a new printer... */ +#ifdef __APPLE__ + if (!strncmp(var, "usb:", 4)) + cgiSetVariable("printer_is_shared", "1"); + else +#endif /* __APPLE__ */ + cgiSetVariable("printer_is_shared", "0"); + cgiCopyTemplateLang("add-printer.tmpl"); } @@ -969,9 +1160,10 @@ do_am_printer(http_t *http, /* I - HTTP connection */ return; } - else if (!file && (var = cgiGetVariable("PPD_NAME")) == NULL) + else if (!file && + (!cgiGetVariable("PPD_NAME") || cgiGetVariable("SELECT_MAKE"))) { - if (modify) + if (modify && !cgiGetVariable("SELECT_MAKE")) { /* * Get the PPD file... @@ -995,6 +1187,8 @@ do_am_printer(http_t *http, /* I - HTTP connection */ if (get_status != HTTP_OK) { + httpFlush(http); + fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n", uri, get_status, httpStatus(get_status)); } @@ -1046,11 +1240,20 @@ 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("CURRENT_MAKE")) == NULL) - var = cgiGetVariable("PPD_MAKE"); - if (var) + if ((var = cgiGetVariable("PPD_MAKE")) == NULL) + var = cgiGetVariable("CURRENT_MAKE"); + if (var && !cgiGetVariable("SELECT_MAKE")) + { + const char *make_model; /* Make and model */ + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make", NULL, var); + + if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, + "ppd-make-and-model", NULL, make_model); + } else ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "ppd-make"); @@ -1065,7 +1268,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ * Got the list of PPDs, see if the user has selected a make... */ - if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0) + if (cgiSetIPPVars(response, NULL, NULL, NULL, 0) == 0 && !modify) { /* * No PPD files with this make, try again with all makes... @@ -1100,47 +1303,12 @@ do_am_printer(http_t *http, /* I - HTTP connection */ * Let the user choose a model... */ - const char *make_model; /* Current make/model string */ - - - if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL) - { - /* - * Scan for "close" matches... - */ - - int match, /* Current match */ - best_match, /* Best match so far */ - count; /* Number of drivers */ - const char *best, /* Best matching string */ - *current; /* Current string */ - - - count = cgiGetSize("PPD_MAKE_AND_MODEL"); - - for (i = 0, best_match = 0, best = NULL; i < count; i ++) - { - current = cgiGetArray("PPD_MAKE_AND_MODEL", i); - match = match_string(make_model, current); - - if (match > best_match) - { - best_match = match; - best = current; - } - } - - if (best_match > strlen(var)) - { - /* - * Found a match longer than the make... - */ - - cgiSetVariable("CURRENT_MAKE_AND_MODEL", best); - } - } - cgiStartHTML(title); + if (!cgiGetVariable("PPD_MAKE")) + cgiSetVariable("PPD_MAKE", cgiGetVariable("CURRENT_MAKE")); + if (!modify) + cgiSetVariable("CURRENT_MAKE_AND_MODEL", + cgiGetArray("PPD_MAKE_AND_MODEL", 0)); cgiCopyTemplateLang("choose-model.tmpl"); cgiEndHTML(); } @@ -1169,6 +1337,7 @@ do_am_printer(http_t *http, /* I - HTTP connection */ * ppd-name * device-uri * printer-is-accepting-jobs + * printer-is-shared * printer-state */ @@ -1187,8 +1356,12 @@ do_am_printer(http_t *http, /* I - HTTP connection */ NULL, cgiGetVariable("PRINTER_INFO")); if (!file) - ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", - NULL, cgiGetVariable("PPD_NAME")); + { + var = cgiGetVariable("PPD_NAME"); + if (strcmp(var, "__no_change__")) + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", + NULL, var); + } strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri)); @@ -1219,6 +1392,10 @@ do_am_printer(http_t *http, /* I - HTTP connection */ ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-accepting-jobs", 1); + var = cgiGetVariable("printer_is_shared"); + ippAddBoolean(request, IPP_TAG_PRINTER, "printer-is-shared", + var && (!strcmp(var, "1") || !strcmp(var, "on"))); + ippAddInteger(request, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", IPP_PRINTER_IDLE); @@ -1305,7 +1482,7 @@ do_cancel_subscription(http_t *http)/* I - HTTP connection */ if (id <= 0) { - cgiSetVariable("ERROR", cgiText(_("Bad subscription ID!"))); + cgiSetVariable("ERROR", cgiText(_("Bad subscription ID"))); cgiStartHTML(_("Cancel RSS Subscription")); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); @@ -1378,17 +1555,52 @@ do_config_server(http_t *http) /* I - HTTP connection */ int num_settings; /* Number of server settings */ cups_option_t *settings; /* Server settings */ + int advanced, /* Advanced settings shown? */ + changed; /* Have settings changed? */ 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, /* USER_CANCEL_ANY value */ + *browse_web_if = NULL, + /* BrowseWebIF value */ + *preserve_job_history = NULL, + /* PreserveJobHistory value */ + *preserve_job_files = NULL, + /* PreserveJobFiles value */ + *max_clients = NULL, + /* MaxClients value */ + *max_jobs = NULL, + /* MaxJobs value */ + *max_log_size = NULL; + /* MaxLogSize value */ + char local_protocols[255], + /* BrowseLocalProtocols */ + remote_protocols[255]; + /* BrowseRemoteProtocols */ + const char *current_browse_web_if, + /* BrowseWebIF value */ + *current_preserve_job_history, + /* PreserveJobHistory value */ + *current_preserve_job_files, + /* PreserveJobFiles value */ + *current_max_clients, + /* MaxClients value */ + *current_max_jobs, + /* MaxJobs value */ + *current_max_log_size, + /* MaxLogSize value */ + *current_local_protocols, + /* BrowseLocalProtocols */ + *current_remote_protocols; + /* BrowseRemoteProtocols */ #ifdef HAVE_GSSAPI char default_auth_type[255]; /* DefaultAuthType value */ + const char *val; /* Setting value */ #endif /* HAVE_GSSAPI */ @@ -1396,12 +1608,96 @@ do_config_server(http_t *http) /* I - HTTP connection */ * Get the checkbox values from the form... */ - 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"; + 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"; + + advanced = cgiGetVariable("ADVANCEDSETTINGS") != NULL; + if (advanced) + { + /* + * Get advanced settings... + */ + + browse_web_if = cgiGetVariable("BROWSE_WEB_IF") ? "Yes" : "No"; + preserve_job_history = cgiGetVariable("PRESERVE_JOB_HISTORY") ? "Yes" : "No"; + preserve_job_files = cgiGetVariable("PRESERVE_JOB_FILES") ? "Yes" : "No"; + max_clients = cgiGetVariable("MAX_CLIENTS"); + max_jobs = cgiGetVariable("MAX_JOBS"); + max_log_size = cgiGetVariable("MAX_LOG_SIZE"); + + if (!max_clients || atoi(max_clients) <= 0) + max_clients = "100"; + + if (!max_jobs || atoi(max_jobs) <= 0) + max_jobs = "500"; + + if (!max_log_size || atof(max_log_size) <= 0.0) + max_log_size = "1m"; + + if (cgiGetVariable("BROWSE_LOCAL_CUPS")) + strcpy(local_protocols, "cups"); + else + local_protocols[0] = '\0'; + +#ifdef HAVE_DNSSD + if (cgiGetVariable("BROWSE_LOCAL_DNSSD")) + { + if (local_protocols[0]) + strcat(local_protocols, " dnssd"); + else + strcat(local_protocols, "dnssd"); + } +#endif /* HAVE_DNSSD */ + +#ifdef HAVE_LDAP + if (cgiGetVariable("BROWSE_LOCAL_LDAP")) + { + if (local_protocols[0]) + strcat(local_protocols, " ldap"); + else + strcat(local_protocols, "ldap"); + } +#endif /* HAVE_LDAP */ + +#ifdef HAVE_LIBSLP + if (cgiGetVariable("BROWSE_LOCAL_SLP")) + { + if (local_protocols[0]) + strcat(local_protocols, " slp"); + else + strcat(local_protocols, "slp"); + } +#endif /* HAVE_SLP */ + + if (cgiGetVariable("BROWSE_REMOTE_CUPS")) + strcpy(remote_protocols, "cups"); + else + remote_protocols[0] = '\0'; + +#ifdef HAVE_LDAP + if (cgiGetVariable("BROWSE_REMOTE_LDAP")) + { + if (remote_protocols[0]) + strcat(remote_protocols, " ldap"); + else + strcat(remote_protocols, "ldap"); + } +#endif /* HAVE_LDAP */ + +#ifdef HAVE_LIBSLP + if (cgiGetVariable("BROWSE_REMOTE_SLP")) + { + if (remote_protocols[0]) + strcat(remote_protocols, " slp"); + else + strcat(remote_protocols, "slp"); + } +#endif /* HAVE_SLP */ + } /* * Get the current server settings... @@ -1427,10 +1723,9 @@ do_config_server(http_t *http) /* I - HTTP connection */ strlcpy(default_auth_type, "Negotiate", sizeof(default_auth_type)); else { - const char *val = cupsGetOption("DefaultAuthType", num_settings, - settings); + val = cupsGetOption("DefaultAuthType", num_settings, settings); - if (val && !strcasecmp(val, "Negotiate")) + if (!val || !strcasecmp(val, "Negotiate")) strlcpy(default_auth_type, "Basic", sizeof(default_auth_type)); else strlcpy(default_auth_type, val, sizeof(default_auth_type)); @@ -1439,27 +1734,75 @@ do_config_server(http_t *http) /* I - HTTP connection */ fprintf(stderr, "DEBUG: DefaultAuthType %s\n", default_auth_type); #endif /* HAVE_GSSAPI */ + if ((current_browse_web_if = cupsGetOption("BrowseWebIF", num_settings, + settings)) == NULL) + current_browse_web_if = "No"; + + if ((current_preserve_job_history = cupsGetOption("PreserveJobHistory", + num_settings, + settings)) == NULL) + current_preserve_job_history = "Yes"; + + if ((current_preserve_job_files = cupsGetOption("PreserveJobFiles", + num_settings, + settings)) == NULL) + current_preserve_job_files = "No"; + + if ((current_max_clients = cupsGetOption("MaxClients", num_settings, + settings)) == NULL) + current_max_clients = "100"; + + if ((current_max_jobs = cupsGetOption("MaxJobs", num_settings, + settings)) == NULL) + current_max_jobs = "500"; + + if ((current_max_log_size = cupsGetOption("MaxLogSize", num_settings, + settings)) == NULL) + current_max_log_size = "1m"; + + if ((current_local_protocols = cupsGetOption("BrowseLocalProtocols", + num_settings, + settings)) == NULL) + current_local_protocols = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS; + + if ((current_remote_protocols = cupsGetOption("BrowseRemoteProtocols", + num_settings, + settings)) == NULL) + current_remote_protocols = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS; + /* * See if the settings have changed... */ - 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)) || + changed = 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)) || + !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))) + strcmp(user_cancel_any, cupsGetOption(CUPS_SERVER_USER_CANCEL_ANY, + num_settings, settings)); + + if (advanced && !changed) + changed = strcasecmp(local_protocols, current_local_protocols) || + strcasecmp(remote_protocols, current_remote_protocols) || + strcasecmp(browse_web_if, current_browse_web_if) || + strcasecmp(preserve_job_history, current_preserve_job_history) || + strcasecmp(preserve_job_files, current_preserve_job_files) || + strcasecmp(max_clients, current_max_clients) || + strcasecmp(max_jobs, current_max_jobs) || + strcasecmp(max_log_size, current_max_log_size); + + if (changed) { /* * Settings *have* changed, so save the changes... @@ -1485,6 +1828,39 @@ do_config_server(http_t *http) /* I - HTTP connection */ num_settings, &settings); #endif /* HAVE_GSSAPI */ + if (advanced) + { + /* + * Add advanced settings... + */ + + if (strcasecmp(local_protocols, current_local_protocols)) + num_settings = cupsAddOption("BrowseLocalProtocols", local_protocols, + num_settings, &settings); + if (strcasecmp(remote_protocols, current_remote_protocols)) + num_settings = cupsAddOption("BrowseRemoteProtocols", remote_protocols, + num_settings, &settings); + if (strcasecmp(browse_web_if, current_browse_web_if)) + num_settings = cupsAddOption("BrowseWebIF", browse_web_if, + num_settings, &settings); + if (strcasecmp(preserve_job_history, current_preserve_job_history)) + num_settings = cupsAddOption("PreserveJobHistory", + preserve_job_history, num_settings, + &settings); + if (strcasecmp(preserve_job_files, current_preserve_job_files)) + num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files, + num_settings, &settings); + if (strcasecmp(max_clients, current_max_clients)) + num_settings = cupsAddOption("MaxClients", max_clients, num_settings, + &settings); + if (strcasecmp(max_jobs, current_max_jobs)) + num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings, + &settings); + if (strcasecmp(max_log_size, current_max_log_size)) + num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings, + &settings); + } + if (!cupsAdminSetServerSettings(http, num_settings, settings)) { if (cupsLastError() == IPP_NOT_AUTHORIZED) @@ -1501,7 +1877,10 @@ do_config_server(http_t *http) /* I - HTTP connection */ } else { - cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); + if (advanced) + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect&URL=/admin/?ADVANCEDSETTINGS=YES"); + else + cgiSetVariable("refresh_page", "5;URL=/admin/?OP=redirect"); cgiStartHTML(cgiText(_("Change Settings"))); cgiCopyTemplateLang("restart.tmpl"); } @@ -1546,7 +1925,7 @@ do_config_server(http_t *http) /* I - HTTP connection */ cgiSetVariable("ERROR", strerror(errno)); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); - + perror(tempfile); return; } @@ -1558,7 +1937,7 @@ do_config_server(http_t *http) /* I - HTTP connection */ cgiSetVariable("ERROR", strerror(errno)); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); - + perror(tempfile); close(tempfd); unlink(tempfile); @@ -1667,7 +2046,7 @@ do_config_server(http_t *http) /* I - HTTP connection */ cgiText(_("Unable to access cupsd.conf file:"))); cgiSetVariable("ERROR", cgiText(_("Unable to edit cupsd.conf files larger than " - "1MB!"))); + "1MB"))); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); @@ -1769,7 +2148,7 @@ do_config_server(http_t *http) /* I - HTTP connection */ /* - * 'do_delete_class()' - Delete a class... + * 'do_delete_class()' - Delete a class. */ static void @@ -1798,7 +2177,7 @@ do_delete_class(http_t *http) /* I - HTTP connection */ else { cgiStartHTML(cgiText(_("Delete Class"))); - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); return; @@ -1854,7 +2233,7 @@ do_delete_class(http_t *http) /* I - HTTP connection */ /* - * 'do_delete_printer()' - Delete a printer... + * 'do_delete_printer()' - Delete a printer. */ static void @@ -1883,7 +2262,7 @@ do_delete_printer(http_t *http) /* I - HTTP connection */ else { cgiStartHTML(cgiText(_("Delete Printer"))); - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); return; @@ -1939,7 +2318,7 @@ do_delete_printer(http_t *http) /* I - HTTP connection */ /* - * 'do_export()' - Export printers to Samba... + * 'do_export()' - Export printers to Samba. */ static void @@ -2058,11 +2437,11 @@ do_export(http_t *http) /* I - HTTP connection */ else if (username && !*username) cgiSetVariable("ERROR", cgiText(_("A Samba username is required to export " - "printer drivers!"))); + "printer drivers"))); else if (username && (!password || !*password)) cgiSetVariable("ERROR", cgiText(_("A Samba password is required to export " - "printer drivers!"))); + "printer drivers"))); /* * Show form... @@ -2075,7 +2454,7 @@ do_export(http_t *http) /* I - HTTP connection */ /* - * 'do_list_printers()' - List available printers... + * 'do_list_printers()' - List available printers. */ static void @@ -2124,7 +2503,7 @@ do_list_printers(http_t *http) /* I - HTTP connection */ attr; attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI)) { - cupsArrayAdd(printer_devices, strdup(attr->values[0].string.text)); + cupsArrayAdd(printer_devices, _cupsStrAlloc(attr->values[0].string.text)); } /* @@ -2228,7 +2607,8 @@ do_list_printers(http_t *http) /* I - HTTP connection */ if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || *ptr == '.') *option_ptr++ = *ptr; - else if ((*ptr == ' ' || *ptr == '/') && option_ptr[-1] != '_') + else if ((*ptr == ' ' || *ptr == '/') && option_ptr > option && + option_ptr[-1] != '_') *option_ptr++ = '_'; else if (*ptr == '?' || *ptr == '(') break; @@ -2261,7 +2641,7 @@ do_list_printers(http_t *http) /* I - HTTP connection */ for (printer_device = (char *)cupsArrayFirst(printer_devices); printer_device; printer_device = (char *)cupsArrayNext(printer_devices)) - free(printer_device); + _cupsStrFree(printer_device); cupsArrayDelete(printer_devices); } @@ -2278,7 +2658,7 @@ do_list_printers(http_t *http) /* I - HTTP connection */ /* - * 'do_menu()' - Show the main menu... + * 'do_menu()' - Show the main menu. */ static void @@ -2334,7 +2714,97 @@ do_menu(http_t *http) /* I - HTTP connection */ if ((val = cupsGetOption("DefaultAuthType", num_settings, settings)) != NULL && !strcasecmp(val, "Negotiate")) cgiSetVariable("KERBEROS", "CHECKED"); + else #endif /* HAVE_GSSAPI */ + cgiSetVariable("KERBEROS", ""); + +#ifdef HAVE_DNSSD + cgiSetVariable("HAVE_DNSSD", "1"); +#endif /* HAVE_DNSSD */ + +#ifdef HAVE_LDAP + cgiSetVariable("HAVE_LDAP", "1"); +#endif /* HAVE_LDAP */ + +#ifdef HAVE_LIBSLP + cgiSetVariable("HAVE_LIBSLP", "1"); +#endif /* HAVE_LIBSLP */ + + if ((val = cupsGetOption("BrowseRemoteProtocols", num_settings, + settings)) == NULL) + if ((val = cupsGetOption("BrowseProtocols", num_settings, + settings)) == NULL) + val = CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS; + + if (strstr(val, "cups") || strstr(val, "CUPS")) + cgiSetVariable("BROWSE_REMOTE_CUPS", "CHECKED"); + + if (strstr(val, "ldap") || strstr(val, "LDAP")) + cgiSetVariable("BROWSE_REMOTE_LDAP", "CHECKED"); + + if (strstr(val, "slp") || strstr(val, "SLP")) + cgiSetVariable("BROWSE_REMOTE_SLP", "CHECKED"); + + if ((val = cupsGetOption("BrowseLocalProtocols", num_settings, + settings)) == NULL) + if ((val = cupsGetOption("BrowseProtocols", num_settings, + settings)) == NULL) + val = CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS; + + if (strstr(val, "cups") || strstr(val, "CUPS")) + cgiSetVariable("BROWSE_LOCAL_CUPS", "CHECKED"); + + if (strstr(val, "dnssd") || strstr(val, "DNSSD") || + strstr(val, "dns-sd") || strstr(val, "DNS-SD") || + strstr(val, "bonjour") || strstr(val, "BONJOUR")) + cgiSetVariable("BROWSE_LOCAL_DNSSD", "CHECKED"); + + if (strstr(val, "ldap") || strstr(val, "LDAP")) + cgiSetVariable("BROWSE_LOCAL_LDAP", "CHECKED"); + + if (strstr(val, "slp") || strstr(val, "SLP")) + cgiSetVariable("BROWSE_LOCAL_SLP", "CHECKED"); + + if ((val = cupsGetOption("BrowseWebIF", num_settings, + settings)) == NULL) + val = "No"; + + if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") || + !strcasecmp(val, "true")) + cgiSetVariable("BROWSE_WEB_IF", "CHECKED"); + + if ((val = cupsGetOption("PreserveJobHistory", num_settings, + settings)) == NULL) + val = "Yes"; + + if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") || + !strcasecmp(val, "true")) + { + cgiSetVariable("PRESERVE_JOB_HISTORY", "CHECKED"); + + if ((val = cupsGetOption("PreserveJobFiles", num_settings, + settings)) == NULL) + val = "No"; + + if (!strcasecmp(val, "yes") || !strcasecmp(val, "on") || + !strcasecmp(val, "true")) + cgiSetVariable("PRESERVE_JOB_FILES", "CHECKED"); + } + + if ((val = cupsGetOption("MaxClients", num_settings, settings)) == NULL) + val = "100"; + + cgiSetVariable("MAX_CLIENTS", val); + + if ((val = cupsGetOption("MaxJobs", num_settings, settings)) == NULL) + val = "500"; + + cgiSetVariable("MAX_JOBS", val); + + if ((val = cupsGetOption("MaxLogSize", num_settings, settings)) == NULL) + val = "1m"; + + cgiSetVariable("MAX_LOG_SIZE", val); cupsFreeOptions(num_settings, settings); @@ -2400,110 +2870,15 @@ do_menu(http_t *http) /* I - HTTP connection */ /* - * 'do_printer_op()' - Do a printer operation. + * 'do_set_allowed_users()' - Set the allowed/denied users for a queue. */ 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 */ +do_set_allowed_users(http_t *http) /* I - HTTP connection */ { - ipp_t *request; /* IPP request */ - char uri[HTTP_MAX_URI]; /* Printer URI */ - const char *printer, /* Printer name (purge-jobs) */ - *is_class; /* Is a class? */ - - - is_class = cgiGetVariable("IS_CLASS"); - printer = cgiGetVariable("PRINTER_NAME"); - - if (!printer) - { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); - cgiStartHTML(title); - cgiCopyTemplateLang("error.tmpl"); - cgiEndHTML(); - return; - } - - /* - * Build a printer request, which requires the following - * attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri - */ - - 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); - - /* - * 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(title); - 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(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_set_allowed_users()' - Set the allowed/denied users for a queue. - */ - -static void -do_set_allowed_users(http_t *http) /* I - HTTP connection */ -{ - int i; /* Looping var */ - ipp_t *request, /* IPP request */ - *response; /* IPP response */ + 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? */ @@ -2526,7 +2901,7 @@ do_set_allowed_users(http_t *http) /* I - HTTP connection */ if (!printer) { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); cgiStartHTML(cgiText(_("Set Allowed Users"))); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); @@ -2602,6 +2977,9 @@ do_set_allowed_users(http_t *http) /* I - HTTP connection */ while (*ptr == ',' || isspace(*ptr & 255)) ptr ++; + if (!*ptr) + break; + if (*ptr == '\'' || *ptr == '\"') { /* @@ -2667,6 +3045,9 @@ do_set_allowed_users(http_t *http) /* I - HTTP connection */ while (*ptr == ',' || isspace(*ptr & 255)) ptr ++; + if (!*ptr) + break; + if (*ptr == '\'' || *ptr == '\"') { /* @@ -2701,7 +3082,7 @@ do_set_allowed_users(http_t *http) /* I - HTTP connection */ * Add the name... */ - attr->values[i].string.text = strdup(ptr); + attr->values[i].string.text = _cupsStrAlloc(ptr); /* * Advance to the next name... @@ -2754,6 +3135,89 @@ do_set_allowed_users(http_t *http) /* I - HTTP connection */ } +/* + * 'do_set_default()' - Set the server default printer/class. + */ + +static void +do_set_default(http_t *http) /* I - HTTP connection */ +{ + const char *title; /* Page title */ + ipp_t *request; /* IPP request */ + char uri[HTTP_MAX_URI]; /* Printer URI */ + const char *printer, /* Printer name (purge-jobs) */ + *is_class; /* Is a class? */ + + + is_class = cgiGetVariable("IS_CLASS"); + printer = cgiGetVariable("PRINTER_NAME"); + title = cgiText(_("Set As Server Default")); + + if (!printer) + { + cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); + cgiStartHTML(title); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + /* + * Build a printer request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNewRequest(CUPS_SET_DEFAULT); + + 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); + + /* + * 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(title); + cgiShowIPPError(_("Unable to set server default:")); + } + 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(title); + cgiCopyTemplateLang("printer-default.tmpl"); + } + + cgiEndHTML(); +} + + /* * 'do_set_options()' - Configure the default options for a queue. */ @@ -2774,13 +3238,16 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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 */ + 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_attr_t *protocol; /* cupsProtocol attribute */ + ppd_coption_t *coption; /* Custom option */ + ppd_cparam_t *cparam; /* Custom parameter */ + ppd_attr_t *ppdattr; /* PPD attribute */ const char *title; /* Page title */ @@ -2799,7 +3266,7 @@ do_set_options(http_t *http, /* I - HTTP connection */ printer); else { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); cgiStartHTML(title); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); @@ -2808,6 +3275,17 @@ do_set_options(http_t *http, /* I - HTTP connection */ fprintf(stderr, "DEBUG: printer=\"%s\", uri=\"%s\"...\n", printer, uri); + /* + * If the user clicks on the Auto-Configure button, send an AutoConfigure + * command file to the printer... + */ + + if (cgiGetVariable("AUTOCONFIGURE")) + { + cgiPrintCommand(http, printer, "AutoConfigure", "Set Default Options"); + return; + } + /* * Get the PPD file... */ @@ -2847,32 +3325,19 @@ do_set_options(http_t *http, /* I - HTTP connection */ { ppdMarkDefaults(ppd); - DEBUG_printf(("

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

    \n", ppd->num_groups)); - - for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + for (option = ppdFirstOption(ppd); + option; + option = ppdNextOption(ppd)) { - DEBUG_printf(("
  • %s
      \n", group->text)); - - 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 */ - - DEBUG_puts("
  • "); + if ((var = cgiGetVariable(option->keyword)) != NULL) + { + have_options = 1; + ppdMarkOption(ppd, option->keyword, var); + fprintf(stderr, "DEBUG: Set %s to %s...\n", option->keyword, var); + } + else + fprintf(stderr, "DEBUG: Didn't find %s...\n", option->keyword); } - - DEBUG_printf(("
\n" - "

ppdConflicts(ppd) = %d\n", ppdConflicts(ppd))); } if (!have_options || ppdConflicts(ppd)) @@ -2883,6 +3348,83 @@ do_set_options(http_t *http, /* I - HTTP connection */ fputs("DEBUG: Showing options...\n", stderr); + /* + * Show auto-configure button if supported... + */ + + if (ppd) + { + if (ppd->num_filters == 0 || + ((ppdattr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL && + ppdattr->value && strstr(ppdattr->value, "AutoConfigure"))) + cgiSetVariable("HAVE_AUTOCONFIGURE", "YES"); + else + { + for (i = 0; i < ppd->num_filters; i ++) + if (!strncmp(ppd->filters[i], "application/vnd.cups-postscript", 31)) + { + cgiSetVariable("HAVE_AUTOCONFIGURE", "YES"); + break; + } + } + } + + /* + * Get the printer attributes... + */ + + 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); + + response = cupsDoRequest(http, request, "/"); + + /* + * List the groups used as "tabs"... + */ + + i = 0; + + if (ppd) + { + for (group = ppd->groups; + i < ppd->num_groups; + i ++, group ++) + { + cgiSetArray("GROUP_ID", i, group->name); + + if (!strcmp(group->name, "InstallableOptions")) + cgiSetArray("GROUP", i, cgiText(_("Options Installed"))); + else + cgiSetArray("GROUP", i, group->text); + } + } + + if (ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) + { + cgiSetArray("GROUP_ID", i, "CUPS_BANNERS"); + cgiSetArray("GROUP", i ++, cgiText(_("Banners"))); + } + + if (ippFindAttribute(response, "printer-error-policy-supported", + IPP_TAG_ZERO) || + ippFindAttribute(response, "printer-op-policy-supported", + IPP_TAG_ZERO)) + { + cgiSetArray("GROUP_ID", i, "CUPS_POLICIES"); + cgiSetArray("GROUP", i ++, cgiText(_("Policies"))); + } + + if ((attr = ippFindAttribute(response, "port-monitor-supported", + IPP_TAG_NAME)) != NULL && attr->num_values > 1) + { + cgiSetArray("GROUP_ID", i, "CUPS_PORT_MONITOR"); + cgiSetArray("GROUP", i, cgiText(_("Port Monitor"))); + } + cgiStartHTML(cgiText(_("Set Printer Options"))); cgiCopyTemplateLang("set-printer-options-header.tmpl"); @@ -2902,6 +3444,16 @@ do_set_options(http_t *http, /* I - HTTP connection */ { cgiSetArray("ckeyword", k, option->keyword); cgiSetArray("ckeytext", k, option->text); + + for (m = 0; m < option->num_choices; m ++) + { + if (option->choices[m].marked) + { + cgiSetArray("cchoice", k, option->choices[m].text); + break; + } + } + k ++; } @@ -2912,23 +3464,39 @@ do_set_options(http_t *http, /* I - HTTP connection */ i > 0; i --, group ++) { + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + if (!strcmp(option->keyword, "PageRegion")) + continue; + + if (option->num_choices > 1) + break; + } + + if (j == 0) + continue; + + cgiSetVariable("GROUP_ID", group->name); + 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")) + if (!strcmp(option->keyword, "PageRegion") || option->num_choices < 2) continue; cgiSetVariable("KEYWORD", option->keyword); cgiSetVariable("KEYTEXT", option->text); - + if (option->conflicted) cgiSetVariable("CONFLICTED", "1"); else @@ -2938,13 +3506,6 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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); @@ -2954,6 +3515,117 @@ do_set_options(http_t *http, /* I - HTTP connection */ cgiSetVariable("DEFCHOICE", option->choices[k].choice); } + cgiSetSize("PARAMS", 0); + cgiSetSize("PARAMTEXT", 0); + cgiSetSize("PARAMVALUE", 0); + cgiSetSize("INPUTTYPE", 0); + + if ((coption = ppdFindCustomOption(ppd, option->keyword))) + { + const char *units = NULL; /* Units value, if any */ + + cgiSetVariable("ISCUSTOM", "1"); + + for (cparam = ppdFirstCustomParam(coption), m = 0; + cparam; + cparam = ppdNextCustomParam(coption), m ++) + { + 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; + } + } + + if (units) + { + cgiSetArray("PARAMS", m, "Units"); + cgiSetArray("PARAMTEXT", m, cgiText(_("Units"))); + cgiSetArray("PARAMVALUE", m, units); + } + } + else + cgiSetVariable("ISCUSTOM", "0"); + switch (option->ui) { case PPD_UI_BOOLEAN : @@ -2972,38 +3644,70 @@ do_set_options(http_t *http, /* I - HTTP connection */ } } - /* - * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the - * following attributes: - * - * attributes-charset - * attributes-natural-language - * printer-uri - */ + if ((attr = ippFindAttribute(response, "job-sheets-supported", + IPP_TAG_ZERO)) != NULL) + { + /* + * Add the job sheets options... + */ - request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); + cgiSetVariable("GROUP_ID", "CUPS_BANNERS"); + cgiSetVariable("GROUP", cgiText(_("Banners"))); + cgiCopyTemplateLang("option-header.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); + 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); + } - /* - * Do the request and get back a response... - */ + attr = ippFindAttribute(response, "job-sheets-default", IPP_TAG_ZERO); - if ((response = cupsDoRequest(http, request, "/")) != NULL) + cgiSetVariable("KEYWORD", "job_sheets_start"); + cgiSetVariable("KEYTEXT", + /* TRANSLATORS: Banner/cover sheet before the print job. */ + cgiText(_("Starting Banner"))); + cgiSetVariable("DEFCHOICE", attr != NULL ? + attr->values[0].string.text : ""); + + cgiCopyTemplateLang("option-pickone.tmpl"); + + cgiSetVariable("KEYWORD", "job_sheets_end"); + cgiSetVariable("KEYTEXT", + /* TRANSLATORS: Banner/cover sheet after the print job. */ + 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)) { - if ((attr = ippFindAttribute(response, "job-sheets-supported", - IPP_TAG_ZERO)) != NULL) - { - /* - * Add the job sheets options... - */ + /* + * Add the error and operation policy options... + */ - cgiSetVariable("GROUP", cgiText(_("Banners"))); - cgiCopyTemplateLang("option-header.tmpl"); + cgiSetVariable("GROUP_ID", "CUPS_POLICIES"); + 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 ++) @@ -3012,136 +3716,80 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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"); + attr = ippFindAttribute(response, "printer-error-policy", + IPP_TAG_ZERO); - cgiCopyTemplateLang("option-trailer.tmpl"); + cgiSetVariable("KEYWORD", "printer_error_policy"); + cgiSetVariable("KEYTEXT", cgiText(_("Error Policy"))); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); } - 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"); + cgiCopyTemplateLang("option-pickone.tmpl"); - /* - * Error policy... - */ + /* + * Operation policy... + */ - attr = ippFindAttribute(response, "printer-error-policy-supported", - IPP_TAG_ZERO); + attr = ippFindAttribute(response, "printer-op-policy-supported", + IPP_TAG_ZERO); - if (attr) + if (attr) + { + cgiSetSize("CHOICES", attr->num_values); + cgiSetSize("TEXT", attr->num_values); + for (k = 0; k < attr->num_values; k ++) { - 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); - } + 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); + attr = ippFindAttribute(response, "printer-op-policy", IPP_TAG_ZERO); - cgiSetVariable("KEYWORD", "printer_error_policy"); - cgiSetVariable("KEYTEXT", cgiText(_("Error Policy"))); - cgiSetVariable("DEFCHOICE", attr == NULL ? - "" : attr->values[0].string.text); - } + cgiSetVariable("KEYWORD", "printer_op_policy"); + cgiSetVariable("KEYTEXT", cgiText(_("Operation 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); - - cgiCopyTemplateLang("option-pickone.tmpl"); - } - - cgiCopyTemplateLang("option-trailer.tmpl"); } - ippDelete(response); + cgiCopyTemplateLang("option-trailer.tmpl"); } /* * Binary protocol support... */ - if (ppd && ppd->protocols && strstr(ppd->protocols, "BCP")) + if ((attr = ippFindAttribute(response, "port-monitor-supported", + IPP_TAG_NAME)) != NULL && attr->num_values > 1) { - protocol = ppdFindAttr(ppd, "cupsProtocol", NULL); + cgiSetVariable("GROUP_ID", "CUPS_PORT_MONITOR"); + cgiSetVariable("GROUP", cgiText(_("Port Monitor"))); - cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol"))); - cgiCopyTemplateLang("option-header.tmpl"); + cgiSetSize("CHOICES", attr->num_values); + cgiSetSize("TEXT", attr->num_values); - 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 + for (i = 0; i < attr->num_values; i ++) { - cgiSetArray("CHOICES", 1, "BCP"); - cgiSetArray("TEXT", 1, "BCP"); + cgiSetArray("CHOICES", i, attr->values[i].string.text); + cgiSetArray("TEXT", i, attr->values[i].string.text); } - cgiSetVariable("KEYWORD", "protocol"); - cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol"))); - cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None"); + attr = ippFindAttribute(response, "port-monitor", IPP_TAG_NAME); + cgiSetVariable("KEYWORD", "port_monitor"); + cgiSetVariable("KEYTEXT", cgiText(_("Port Monitor"))); + cgiSetVariable("DEFCHOICE", attr ? attr->values[0].string.text : "none"); + cgiCopyTemplateLang("option-header.tmpl"); cgiCopyTemplateLang("option-pickone.tmpl"); - cgiCopyTemplateLang("option-trailer.tmpl"); } cgiCopyTemplateLang("set-printer-options-trailer.tmpl"); cgiEndHTML(); + + ippDelete(response); } else { @@ -3178,7 +3826,7 @@ do_set_options(http_t *http, /* I - HTTP connection */ while (cupsFileGets(in, line, sizeof(line))) { - if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol")) + if (!strncmp(line, "*cupsProtocol:", 14)) continue; else if (strncmp(line, "*Default", 8)) cupsFilePrintf(out, "%s\n", line); @@ -3199,20 +3847,17 @@ do_set_options(http_t *http, /* I - HTTP connection */ if (!strcmp(keyword, "PageRegion") || !strcmp(keyword, "PaperDimension") || !strcmp(keyword, "ImageableArea")) - var = cgiGetVariable("PageSize"); + var = get_option_value(ppd, "PageSize", value, sizeof(value)); else - var = cgiGetVariable(keyword); + var = get_option_value(ppd, keyword, value, sizeof(value)); - if (var != NULL) - cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); - else + if (!var) cupsFilePrintf(out, "%s\n", line); + else + cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); } } - if ((var = cgiGetVariable("protocol")) != NULL) - cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol")); - cupsFileClose(in); cupsFileClose(out); } @@ -3250,12 +3895,16 @@ do_set_options(http_t *http, /* I - HTTP connection */ 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); + 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); + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-op-policy", NULL, var); + + if ((var = cgiGetVariable("port_monitor")) != NULL) + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "port-monitor", NULL, var); /* * Do the request and get back a response... @@ -3307,7 +3956,7 @@ do_set_options(http_t *http, /* I - HTTP connection */ /* - * 'do_set_sharing()' - Set printer-is-shared value... + * 'do_set_sharing()' - Set printer-is-shared value. */ static void @@ -3327,7 +3976,7 @@ do_set_sharing(http_t *http) /* I - HTTP connection */ if (!printer || !shared) { - cgiSetVariable("ERROR", cgiText(_("Missing form variable!"))); + cgiSetVariable("ERROR", cgiText(_("Missing form variable"))); cgiStartHTML(cgiText(_("Set Publishing"))); cgiCopyTemplateLang("error.tmpl"); cgiEndHTML(); @@ -3400,54 +4049,293 @@ do_set_sharing(http_t *http) /* I - HTTP connection */ /* - * 'match_string()' - Return the number of matching characters. + * 'get_option_value()' - Return the value of an option. + * + * This function also handles generation of custom option values. */ -static int /* O - Number of matching characters */ -match_string(const char *a, /* I - First string */ - const char *b) /* I - Second string */ +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 */ { - int count; /* Number of matching characters */ + 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 */ /* - * Loop through both strings until we hit the end of either or we find - * a non-matching character. For the purposes of comparison, we ignore - * whitespace and do a case-insensitive comparison so that we have a - * better chance of finding a match... + * See if we have a custom option choice... */ - for (count = 0; *a && *b; a++, b++, count ++) + if ((val = cgiGetVariable(name)) == NULL) { /* - * Skip leading whitespace characters... + * Option not found! */ - while (isspace(*a & 255)) - a ++; - - while (isspace(*b & 255)) - b ++; - + return (NULL); + } + else if (strcasecmp(val, "Custom") || + (coption = ppdFindCustomOption(ppd, name)) == NULL) + { /* - * Break out if we run out of characters... + * Not a custom choice... */ - if (!*a || !*b) - break; + strlcpy(buffer, val, bufsize); + return (buffer); + } - /* - * Do a case-insensitive comparison of the next two chars... - */ + /* + * OK, we have a custom option choice, format it... + */ - if (tolower(*a & 255) != tolower(*b & 255)) - break; + *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); - return (count); + 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); +} + + /* - * End of "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $". + * End of "$Id: admin.c 8029 2008-10-08 21:07:45Z mike $". */