Support AllowedChars for String/Password type custom PPD options #2814

Closed
michaelrsweet opened this Issue May 2, 2008 · 9 comments

Comments

Projects
None yet
1 participant
Collaborator

michaelrsweet commented May 2, 2008

Version: -feature
CUPS.org User: georgeliuyue

I'd like to further propose a new syntax to specify allowed characters for string and password type PPD options.
For example, allowed chars for phone numbers is (0-9, '-' and space)
Allowed chars for userid is (0-9a-zA-Z and '_')

A password type with allowe chars "0-9" is equivalent to passcode type.

Collaborator

michaelrsweet commented May 12, 2008

CUPS.org User: larsuebernickel

I have a patch ready which adds a 5th parameter to *ParamCustom, using the same syntax as scanf(2) for character ranges.

For example:

*CustomUserId True:
*ParamCustomUserId UserId/User Id: 1 string 0 64 [0-9a-zA-Z_]

This parameter is only valid for string and password options.

But I have a small problem: CUPS doesn't seem to enforce the min/max parameters for incoming custom option parameters. Therefore, I don't know where the allowed chars setting should be enforced. Is that the responsibility of the filters? Does it even make sense to read the min/max/allowedchars from the ppd file if they are never used?

As with the web interface for the custom options, I would like to see this in 1.4 - is there still time for that?

Lars
Collaborator

michaelrsweet commented May 12, 2008

CUPS.org User: till.kamppeter

I am not sure whether I am right, but the min, max, allowed characters, ... should be enforced once by the driver (as foomatic-rip does it already for the Foomatic string and password options), and second, by the client-side GUIs, like the web interfaces, and all printing dialogs which support custom options.

So it should be done the following:

  1. Lars, your patch to let the CUPS web interface support the custom options should also enforce all restrictions of these options. So do not let it accept too long or too short strings, and also not input which violates your new [parameter of allowed characters. But make sure that if a PPD does not have your restriction on allowed characters that this is counted as no restriction, to be backward compatible wth older PPDs.
  2. Lars, you (and also Alex) should take into account that the restrictions get read out and enforced in the Common Printing Dialog.
  3. Mike, George, Lars, and anyone else here who develops CUPS filters (printer drivers) should make sure that the filters/drivers enforce the restrictions of the custom options.

Mike, am I right? Or does the CUPS core (scheduler, libcups, ...) also enforce the restrictions of these options? And if yes, where?

Collaborator

michaelrsweet commented May 12, 2008

CUPS.org User: mike

I am hesitant to extend the custom option syntax in 1.4 without some more discussion. In particular, it seems like using the POSIX regular expression syntax would be better than a simple set of allowed characters and open up more robust string validation.

As for range limiting the custom input, that is the responsibility of the caller/application - the custom parameter data is provided so that the UI can map the limits appropriately to UI controls/feedback. Like UIConstraints, they aren't enforced by the library because the recovery mode (what to do when a custom parameter is out of range or when a conflicting choice is made) cannot be described in the PPD.

Collaborator

michaelrsweet commented May 12, 2008

CUPS.org User: till.kamppeter

Mike, I agree with you to use Posix regexps for restricting the allowed characters. This is much more flexible and even allows a basic syntax check of the input. AFAIR there is also a C library for parsing POSIX regexps (Lars, you have probably used that for foomatic-rip). So let's settle on that.

As the CUPS core is not involved in the enforcing of the restrictions, we should go the way of my previous posting.

So we can delegate most of the fix to Lars: Lars, can you update the patch for the web interface, foomatic-rip, and also implement this in the Common Printing Dialog (if it falls into your area, otherwise it is Alex' task).

Mike, your part of the implementation will be to update the documentation, and perhaps some rasterto... drivers of CUPS, CUPS DDK, and perhaps Gutenprint.

But at first we have to agree on the syntax. My suggestion is to follow Lars' suggestion but replacing the character list by a POSIX regexp.

Lars, then this will be more or less an equivalent of "_FoomaticRIPOptionAllowedRegExp" keyword. A Character lis as supplied with the "_FoomaticRIPOptionAllowedChars" keyword has to be surrounded by "^[...]*$".

Collaborator

michaelrsweet commented May 15, 2008

CUPS.org User: larsuebernickel

Okay, the patch was a bit more work than I hoped it would be ...

It includes the following:

*ParamCustom commands of type string and password can have a POSIX extended regular expression as a 5th parameter. For a custom option value to be valid, it must be matched by the regexp.

The web interface exposes a "Custom" choice for all options which can be set to custom values (this is the patch from STR #1729). It accepts only valid values (i.e. correct type, between range, matches regexp) and displays a detailed error message for invalid entries on the top of the "Set Printer Options" page. The user then has the chance to modify the values according to the restrictions.

The patch compiles fine against latest svn (r7563).

Hope you like it ;)

Lars
Collaborator

michaelrsweet commented Jun 5, 2008

CUPS.org User: larsuebernickel

Mike,

did you have a chance to look at my patch, yet?

Lars
Collaborator

michaelrsweet commented Jun 5, 2008

CUPS.org User: mike

I did not, but you can be sure that this patch will not be incorporated into CUPS before version 1.5...

Collaborator

michaelrsweet commented Feb 7, 2009

CUPS.org User: mike

Given the limited usefulness of even regular expressions for validating what are supposed to be user-defined (custom) strings, we have decided not to implement this.

Collaborator

michaelrsweet commented Feb 7, 2009

"cups-coptions.patch":

diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c
index 0d5c556..71ba024 100644
--- a/cgi-bin/admin.c
+++ b/cgi-bin/admin.c
@@ -39,10 +39,12 @@
#include "cgi-private.h"
#include <cups/adminutil.h>
#include <cups/file.h>
+#include <cups/array.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
+#include <regex.h>

/*
@@ -53,7 +55,7 @@ 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_set_options(http_t *http, int is_class, cups_array_t *invalid_values);
static void do_config_server(http_t *http);
static void do_delete_class(http_t *http);
static void do_delete_printer(http_t *http);
@@ -163,9 +165,9 @@ main(int argc, /
I - Number of command-line arguments */
else if (!strcmp(op, "delete-printer"))
do_delete_printer(http);
else if (!strcmp(op, "set-class-options"))

  •  do_set_options(http, 1);
    
  •  do_set_options(http, 1, NULL);
    

    else if (!strcmp(op, "set-printer-options"))

  •  do_set_options(http, 0);
    
  •  do_set_options(http, 0, NULL);
    

    else if (!strcmp(op, "config-server"))
    do_config_server(http);
    else if (!strcmp(op, "export-samba"))
    @@ -1269,7 +1271,7 @@ do_am_printer(http_t http, / I - HTTP connection */
    */

    cgiSetVariable("OP", "set-printer-options");

  •  do_set_options(http, 0);
    
  •  do_set_options(http, 0, NULL);
    

    return;
    }

@@ -2754,13 +2756,219 @@ do_set_allowed_users(http_t http) / I - HTTP connection */
}

+#define INV_VALUE_HASH_SIZE 32
+
+typedef struct {

  • char name[2 * PPD_MAX_NAME +1];
  • ppd_coption_t *coption;
  • ppd_cparam_t *cparam;
  • char *value;
    +} invalid_value_t;

+void add_invalid_value(cups_array_t *a,

  •          ppd_coption_t *coption,
    
  •          ppd_cparam_t *cparam,
    
  •          const char *value)
    
    +{
  • invalid_value_t *val = malloc(sizeof(invalid_value_t));
  • snprintf(val->name, 2 * PPD_MAX_NAME +1, "%s.%s",
  •   coption->keyword, cparam->name);
    
  • val->coption = coption;
  • val->cparam = cparam;
  • val->value = strdup(value);
  • cupsArrayAdd(a, val);
    +}

+int compare_invalid_values(invalid_value_t *v1,

  •          invalid_value_t *v2,
    
  •          void *user_data)
    
    +{
  • return strcmp(v1->name, v2->name);
    +}

+int hash_invalid_value(invalid_value_t *v, void *user_data)
+{

  • unsigned char hash = 0, t;
  • int i;
  • size_t len = strlen(v->name);
  • for (i = 0; i < len; i++)
  • {
  •  t = hash ^ v->name[i];
    
  •  hash += (t >> 3) | (t << 5);
    
  • }
  • return (int)hash % INV_VALUE_HASH_SIZE;
    +}

+int /* O - Non-zero on success. /
+matches_regexp(const char *str, /
I - The value to be verified */

  •      const char _regexp)  /_ I - Regexp to match agains str. If
    
  •                      empty, str always matches*/
    
    +{
  • regex_t rx;
  • int result;
  • if (!regexp || !regexp[0])
  • return 1;
  • if (regcomp(&rx, regexp, REG_EXTENDED) != 0)
  • return 0;
  • result = (regexec(&rx, str, 0, NULL, 0) == 0);
  • regfree(&rx);
  • return result;
    +}

+void
+cparam_restriction_string(char *str, size_t len, ppd_cparam_t *cparam)
+{

  • switch (cparam->type) {
  • /* Float value */
  • case PPD_CUSTOM_CURVE:
  • case PPD_CUSTOM_INVCURVE:
  • case PPD_CUSTOM_REAL:
  • case PPD_CUSTOM_POINTS:
  •  snprintf(str, len, "must be a floating point number in the range from "
    
  •   "%f to %f.", cparam->minimum.custom_real,
    
  •   cparam->maximum.custom_real);
    
  •  break;
    
  • /* Integer value */
  • case PPD_CUSTOM_INT:
  •  snprintf(str, len, "must be an integer in the range from %d to %d.",
    
  •  cparam->minimum.custom_int, cparam->maximum.custom_int);
    
  •  break;
    
  • /* String and password values */
  • case PPD_CUSTOM_PASSCODE:
  • case PPD_CUSTOM_PASSWORD:
  • case PPD_CUSTOM_STRING:
  •  if (cparam->allowedregexp[0])
    
  • snprintf(str, len, "must be between %d and %d characters long and match "
  •   "the regular expression %s.", cparam->minimum.custom_string,
    
  •   cparam->maximum.custom_string, cparam->allowedregexp);
    
  •  else
    
  • snprintf(str, len, "must be between %d and %d characters long.",
  •   cparam->minimum.custom_string, cparam->maximum.custom_string);
    
  •  break;
    
  • }
    +}

+int /* O - True if 'value' is valid /
+cparam_value_valid(ppd_cparam_t *cparam, /
I - Custom parameter */

  •         const char _value)    /_ I - Value for 'cparam' */
    
    +{
  • int ival;
  • float fval;
  • size_t len;
  • switch (cparam->type) {
  • /* Float value */
  • case PPD_CUSTOM_CURVE:
  • case PPD_CUSTOM_INVCURVE:
  • case PPD_CUSTOM_REAL:
  • case PPD_CUSTOM_POINTS:
  •  fval = atof(value);
    
  •  return (fval >= cparam->minimum.custom_real && fval <= cparam->maximum.custom_real);
    
  • /* Integer value */
  • case PPD_CUSTOM_INT:
  •  ival = atoi(value);
    
  •  return (ival >= cparam->minimum.custom_int && ival <= cparam->maximum.custom_int);
    
  • /* String and password values */
  • case PPD_CUSTOM_PASSCODE:
  • case PPD_CUSTOM_PASSWORD:
  • case PPD_CUSTOM_STRING:
  •  len = strlen(value);
    
  •  return (len >= cparam->minimum.custom_string &&
    
  •     len <= cparam->maximum.custom_string &&
    
  •     matches_regexp(value, cparam->allowedregexp));
    
  • }
  • return 0;
    +}

+/*

  • * 'get_coption_value_string' - Create the value string for the custom
  • * parameters of an option.
  • /
    +static int /
    O - Non-zero on success /
    +get_coption_value_string(char *valstr, /
    O - Resulting value string */
  •        size_t size,       /\* I - Maximum size of valstr */
    
  •        ppd_coption_t _opt,    /_ I - Option */
    
  •        cups_array_t _invvalues)   /_ O - append invalid values */
    
    +{
  • ppd_cparam_t *cparam;
  • size_t pos;
  • char keyword[2*PPD_MAX_NAME];
  • const char *var;
  • if (cupsArrayCount(opt->params) == 1)
  • {
  • cparam = ppdFirstCustomParam(opt);
  • snprintf(keyword, 2*PPD_MAX_NAME, "%s.%s", opt->keyword, cparam->name);
  • var = cgiGetVariable(keyword);
  • if (!var || !cparam_value_valid(cparam, var)) {
  • add_invalid_value(invvalues, opt, cparam, var ? var : "");
  • return 0;
  • }
  • snprintf(valstr, size, "Custom.%s", var);
  • }
  • else if (cupsArrayCount(opt->params) > 1)
  • {
  • valstr[0] = '{';
  • for (cparam = ppdFirstCustomParam(opt), pos = 1;
  • cparam && pos < size;
  • cparam = ppdNextCustomParam(opt))
  • {
  •  snprintf(keyword, 2 \* PPD_MAX_NAME, "%s.%s", opt->keyword, cparam->name);
    
  •  var = cgiGetVariable(keyword);
    
  •  if (!var || !cparam_value_valid(cparam, var)) {
    
  • add_invalid_value(invvalues, opt, cparam, var ? var : "");
  • /* Continue to check parameters, but do not update valstr anymore */
  • pos = -1;
  •  }
    
  •  if (pos > 0)
    
  •    pos += snprintf(&valstr[pos], size - pos, "%s=%s, ", cparam->name, var);
    
  • }
  • if (pos < 0)
  •  return 0;
    
  • /* Remove the last ',' */
  • if (pos > 3)
  •  strlcpy(&valstr[pos -3], "}", size);
    
  • }
  • /*
  • * Special case for "PageSize"
  • * Do it after the general cases in order for range checking to work
  • */
  • if (!strcmp(opt->keyword, "PageSize"))
  • {
  • strlcpy(valstr, "Custom.", size);
  • var = cgiGetVariable("PageSize.Width");
  • strlcat(valstr, var, size);
  • strlcat(valstr, ".", size);
  • var = cgiGetVariable("PageSize.Height");
  • strlcat(valstr, var, size);
  • }
  • return 1;
    +}

/*

  • '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    is_class,        /\* I - Set options for class? */
    
  •      cups_array_t _invalid_values) /_ I - invalid values from last do_set_options _/
    
    {
    int i, j, k, m; /_ Looping vars /
    int have_options; /
    Have options? /
    @@ -2780,9 +2988,13 @@ do_set_options(http_t *http, /
    I - HTTP connection /
    ppd_file_t *ppd; /
    PPD file /
    ppd_group_t *group; /
    Option group /
    ppd_option_t *option; /
    Option */
  • ppd_coption_t coption; / Custom Option */
  • ppd_cparam_t cparam; / Custom param /
    ppd_attr_t *protocol; /
    cupsProtocol attribute /
    const char *title; /
    Page title */
  • char tmp[1024];
  • cups_array_t *new_invalid_values = NULL;
  • invalid_value_t *invalid_value;

title = cgiText(is_class ? _("Set Class Options") : _("Set Printer Options"));

@@ -2875,7 +3087,7 @@ do_set_options(http_t http, / I - HTTP connection */
"

ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
}

  • if (!have_options || ppdConflicts(ppd))

  • if (!have_options || ppdConflicts(ppd) || invalid_values)
    {
    /*

  • Show the options to the user...
    @@ -2908,6 +3120,24 @@ do_set_options(http_t http, / I - HTTP connection */
    cgiCopyTemplateLang("option-conflict.tmpl");
    }

  •  if (invalid_values)
    
  •  {
    
  • i = 0;

  • invalid_value = (invalid_value_t *)cupsArrayFirst(invalid_values);

  • while (invalid_value)

  • {

  • cgiSetArray("iv_keyword", i, invalid_value->coption->keyword);
    
  • cgiSetArray("iv_keytext", i, invalid_value->coption->option->text);
    
  • cgiSetArray("iv_cparam", i, invalid_value->cparam->name);
    
  • cparam_restriction_string(tmp, 1024, invalid_value->cparam);
    
  • cgiSetArray("iv_error", i, tmp);
    
  • invalid_value = (invalid_value_t *)cupsArrayNext(invalid_values);
    
  • i++;
    
  • }

  • cgiCopyTemplateLang("option-invalid-custom-param.tmpl");

  •  }
    
    • for (i = ppd->num_groups, group = ppd->groups;
      i > 0;
      i --, group ++)
      @@ -2928,7 +3158,7 @@ do_set_options(http_t http, / I - HTTP connection */

      cgiSetVariable("KEYWORD", option->keyword);
      cgiSetVariable("KEYTEXT", option->text);

    • if (option->conflicted)
      cgiSetVariable("CONFLICTED", "1");
      else
      @@ -2938,13 +3168,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 +3177,83 @@ 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)))
    
  • {
    
  •   cgiSetVariable("ISCUSTOM", "1");
    
  •   /*
    
  •    \* TODO Can these be traversed sorted by their order? (The params
    
  •    \* for PageSize gets all messed up this way)
    
  •    */
    
  •   for (cparam = ppdFirstCustomParam(coption), m = 0;
    
  •    cparam;
    
  •    cparam = ppdNextCustomParam(coption))
    
  •   {
    
  •     cgiSetArray("PARAMS", m, cparam->name);
    
  •     cgiSetArray("PARAMTEXT", m, cparam->text);
    
  •     /*
    
  •      \* If this option was set to an invalid value in the last run,
    
  •      \* use that value instead of the default one to allow the user to
    
  •      \* tweak it.
    
  •      */
    
  •     snprintf(tmp, 1024, "%s.%s", option->keyword, cparam->name);
    
  •     invalid_value = (invalid_value_t *)cupsArrayFind(invalid_values, tmp);
    
  •     if (invalid_value)
    
  •     {
    
  •   cgiSetArray("PARAMVALUE", m, invalid_value->value);
    
  •   if (cparam->type == PPD_CUSTOM_PASSCODE ||
    
  •           cparam->type == PPD_CUSTOM_PASSWORD)
    
  •     cgiSetArray("INPUTTYPE", m, "password");
    
  •   else
    
  •     cgiSetArray("INPUTTYPE", m, "text");
    
  •     }
    
  •     else
    
  •     {
    
  •   switch (cparam->type) {
    
  •     case PPD_CUSTOM_CURVE:
    
  •     case PPD_CUSTOM_INVCURVE:
    
  •     case PPD_CUSTOM_REAL:
    
  •     case PPD_CUSTOM_POINTS:
    
  •       snprintf(tmp, 50, "%f", cparam->current.custom_real);
    
  •       cgiSetArray("PARAMVALUE", m, tmp);
    
  •       cgiSetArray("INPUTTYPE", m, "text");
    
  •       break;
    
  •     case PPD_CUSTOM_INT:
    
  •       snprintf(tmp, 50, "%d", cparam->current.custom_int);
    
  •       cgiSetArray("PARAMVALUE", m, tmp);
    
  •       cgiSetArray("INPUTTYPE", m, "text");
    
  •       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, "");
    
  •       cgiSetArray("INPUTTYPE", m, "text");
    
  •       break;
    
  •       }
    
  •     }
    
  •     m++;
    
  •   }
    
  • }
    
  • else
    
  •   cgiSetVariable("ISCUSTOM", "0");
    
    • switch (option->ui)
      {
      case PPD_UI_BOOLEAN :
      @@ -2967,8 +3267,14 @@ do_set_options(http_t http, / I - HTTP connection */
      break;
      }
      }
    cgiCopyTemplateLang("option-trailer.tmpl");
    +
  • /* Clear some cgi vars (for future options) */
  • cgiSetVariable("ISCUSTOM", "0");
  • cgiSetSize("PARAMS", 0);
  • cgiSetSize("PARAMTEXT", 0);
  • cgiSetSize("PARAMVALUE", 0);
  • cgiSetSize("INPUTTYPE", 0);
    }
    }

@@ -3176,6 +3482,9 @@ do_set_options(http_t http, / I - HTTP connection */
return;
}

  •  new_invalid_values = cupsArrayNew2((cups_array_func_t)compare_invalid_values,
    
  •     NULL, (cups_ahash_func_t)hash_invalid_value, INV_VALUE_HASH_SIZE);
    
    • while (cupsFileGets(in, line, sizeof(line)))
      {
      if (!strncmp(line, "cupsProtocol:", 14) && cgiGetVariable("protocol"))
      @@ -3203,10 +3512,18 @@ do_set_options(http_t *http, /
      I - HTTP connection */
      else
      var = cgiGetVariable(keyword);
  • if (var != NULL)
    
  •   cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
    
  • else
    
  • if (var == NULL)
    cupsFilePrintf(out, "%s\n", line);
    
  • else if (!strcmp(var, "Custom") && (coption = ppdFindCustomOption(ppd, keyword)))
    
  • {
    
  •   if (get_coption_value_string(tmp, 1024, coption, new_invalid_values))
    
  •     cupsFilePrintf(out, "*Default%s: %s\n", keyword, tmp);
    
  •   else
    
  •     /\* Invalid custom option value, use previous default value */
    
  •     cupsFilePrintf(out, "*Default%s: %s\n", keyword, coption->option->defchoice);
    
  • }
    
  • else
    
  •   cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
    

    }
    }

@@ -3276,6 +3593,21 @@ do_set_options(http_t http, / I - HTTP connection */
cgiStartHTML(title);
cgiShowIPPError(_("Unable to set options:"));
}

  • if (cupsArrayCount(new_invalid_values) > 0)
  • {
  •  /*
    
  •   \* At least one invalid value was found, send the option page again.
    
  •   */
    
  •  do_set_options(http, is_class, new_invalid_values);
    
  •  for (invalid_value = (invalid_value_t *)cupsArrayFirst(new_invalid_values);
    
  •  invalid_value != NULL;
    
  •  invalid_value = (invalid_value_t *)cupsArrayNext(new_invalid_values))
    
  •  {
    
  • free(invalid_value->value);
  • free(invalid_value);
  •  }
    
  • }
    else
    {
    /*
    @@ -3303,6 +3635,9 @@ do_set_options(http_t http, / I - HTTP connection */

if (filename)
unlink(filename);
+

  • if (new_invalid_values)
  • cupsArrayDelete(new_invalid_values);
    }

diff --git a/cups/ppd.c b/cups/ppd.c
index bb517ec..785023c 100644
--- a/cups/ppd.c
+++ b/cups/ppd.c
@@ -63,6 +63,7 @@
#include "globals.h"
#include "debug.h"
#include <stdlib.h>
+#include <regex.h>

/*
@@ -894,7 +895,8 @@ ppdOpen2(cups_file_t fp) / I - File to read from /
int corder; /
Order number /
char ctype[33], /
Data type /
cminimum[65], /
Minimum value */

  •       cmaximum[65];   /\* Maximum value */
    
  •       cmaximum[65],   /\* Maximum value */
    
  •       callowedregexp[64] = "";   /* Allowed regualar expression */
    

    /*
    @@ -919,14 +921,27 @@ ppdOpen2(cups_file_t fp) / I - File to read from */

    • Get the parameter data...
      */
  •  if (sscanf(string, "%d%32s%64s%64s", &corder, ctype, cminimum,
    
  •             cmaximum) != 4)
    
  •  if (sscanf(string, "%d%32s%64s%64s %63c", &corder, ctype, cminimum,
    
  •             cmaximum, callowedregexp) < 4)
    

    {
    cg->ppd_status = PPD_BAD_CUSTOM_PARAM;

    goto error;
    }

  •  /* Validate the regexp */
    
  •  if (callowedregexp[0])
    
  •  {
    
  • regex_t rx;

  • if (regcomp(&rx, callowedregexp, REG_EXTENDED) != 0)

  • {

  • regfree(&rx);
    
  • cg->ppd_status = PPD_BAD_CUSTOM_PARAM;
    
  • goto error;
    
  • }

  • regfree(&rx);

  •  }
    
    • cparam->order = corder;

      if (!strcmp(ctype, "curve"))
      @@ -984,6 +999,11 @@ ppdOpen2(cups_file_t fp) / I - File to read from */
      goto error;
      }

  •  if (callowedregexp[0]) {
    
  •    if (cparam->type == PPD_CUSTOM_STRING || cparam->type == PPD_CUSTOM_PASSWORD)
    
  •        strlcpy(cparam->allowedregexp, callowedregexp, 64);
    
  •  }
    
    • /*
    • Now special-case for CustomPageSize...
      /
      diff --git a/cups/ppd.h b/cups/ppd.h
      index 4c40a7d..db8f521 100644
      --- a/cups/ppd.h
      +++ b/cups/ppd.h
      @@ -258,6 +258,7 @@ typedef struct ppd_cparam_s /
      *** Custom Parameter @SInCE CUPS 1.2@ ***/
      ppd_cptype_t type; /
      Parameter type /
      ppd_cplimit_t minimum, /
      Minimum value /
      maximum; /
      Maximum value */
  • char allowedregexp[64]; /* Allowed regular expression /
    ppd_cpvalue_t current; /
    Current value */
    } ppd_cparam_t;

diff --git a/doc/cups.css b/doc/cups.css
index faaef12..5daa8a4 100644
--- a/doc/cups.css
+++ b/doc/cups.css
@@ -220,6 +220,12 @@ TH.label {
vertical-align: top;
}

+TH.sublabel {

  • padding-top: 0pt;
  • text-align: right;
  • font-weight: normal;
    +}

HR {
border: solid thin;
}
diff --git a/templates/Makefile b/templates/Makefile
index d00fde3..3760e2c 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -57,6 +57,7 @@ FILES =
norestart.tmpl
option-boolean.tmpl
option-conflict.tmpl \

  •   option-invalid-custom-param.tmpl \
    option-header.tmpl \
    option-pickmany.tmpl \
    option-pickone.tmpl \
    
    diff --git a/templates/option-invalid-custom-param.tmpl b/templates/option-invalid-custom-param.tmpl
    new file mode 100644
    index 0000000..6341766
    --- /dev/null
    +++ b/templates/option-invalid-custom-param.tmpl
    @@ -0,0 +1,7 @@
    +

    Error: The following custom parameters have invalid values:


    +
    +

      +{[iv_keyword]
    • {iv_keytext} - Parameter "{iv_cparam}" ({iv_error})

    • +}

    +
    +

    All other options were applied successfully.


    diff --git a/templates/option-pickone.tmpl b/templates/option-pickone.tmpl
    index 08342d0..83fc3ca 100644
    --- a/templates/option-pickone.tmpl
    +++ b/templates/option-pickone.tmpl
    @@ -1,6 +1,15 @@ {keytext}: - + {[choices]{text}} - + +{iscustom=1?{[params]
  • +}

    {paramtext}:
  •  <INPUT type={inputtype} name="{keyword}.{params}" value="{paramvalue}"/>
    

  • +:}

    diff --git a/templates/set-printer-options-header.tmpl b/templates/set-printer-options-header.tmpl index 864f9f0..c5ff5a0 100644 --- a/templates/set-printer-options-header.tmpl +++ b/templates/set-printer-options-header.tmpl @@ -1,3 +1,16 @@ + +<script type="text/javascript"> +function update_paramtable(option) +{ - var cb = document.getElementById("select-" + option) - var paramstable = document.getElementById(option + "-params"); - if (cb.value == "Custom") - paramstable.style.display = "table"; - else - paramstable.style.display = "none"; +} +</script> + diff --git a/templates/set-printer-options-trailer.tmpl b/templates/set-printer-options-trailer.tmpl index a3d1e1f..309256e 100644 --- a/templates/set-printer-options-trailer.tmpl +++ b/templates/set-printer-options-trailer.tmpl @@ -1 +1,15 @@ + +<script type="text/javascript"> + +// hide custom options parameters for browsers that understand javascript +var paramtables = document.getElementsByName("paramtable"); +for (var i = 0; i < paramtables.length; i++) { - var opt = paramtables[i].id.substr(0, paramtables[i].id.lastIndexOf("-")); - var cb = document.getElementById("select-" + opt); - if (cb.value != "Custom") - paramtables[i].style.display = "none"; +} + +</script> +

@michaelrsweet michaelrsweet added this to the Stable milestone Mar 17, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment