CUPS web UI should support new UIOption types (int, string, password) #1729

Closed
michaelrsweet opened this Issue May 27, 2006 · 14 comments

Comments

Projects
None yet
1 participant
Collaborator

michaelrsweet commented May 27, 2006

Version: 1.4-feature
CUPS.org User: georgeliuyue

If the web ui of CUPS 1.2 could support input types (int, string, password), that will make the new UIOption features in CUPS 1.2 really useful.

Collaborator

michaelrsweet commented Jul 13, 2006

CUPS.org User: georgeliuyue

Type-in value support is something that user has asked for a long time. If 1.2 has implemented PPD parsing, adding HTML support shouldn't be super difficult.
Personally, I would vote this feature in 1.3 since it's too late for 1.2

Collaborator

michaelrsweet commented Dec 8, 2006

CUPS.org User: georgeliuyue

Can this feature be moved to CUPS 1.3 time frame?
FC6 already ships gtk+ 2.10 printing dialog, which supports custom type in value. (I tried the test.ppd with a demo print dialog, it works)

Easysoft has put in lots of effort into this feature, and CUPS 1.2 has already supported PPD parsing. With a little bit more effort, it could be visible to end users. I strongly suggest to move this feature support into 1.3.

Collaborator

michaelrsweet commented Apr 24, 2008

CUPS.org User: till.kamppeter

Patch posted as STR #2807 (http://www.cups.org/str.php?L2807).

Collaborator

michaelrsweet commented Apr 25, 2008

CUPS.org User: larsuebernickel

however your patch will still require a bit of work since we can't
depend on Javascript for the user interface (that breaks text-only
browsers which we do support).

Oh - I didn't know that. But how should this be done without JavaScript? Should all custom options be shown all the time, even if the user did not select the "Custom" entry for the option? Should the page be reloaded every time the user chooses "Custom" in for one of the options?

I think there are many people who do not access the webinterface through a text-only browser. For those, the js version is superior to any of the approaches above. Do you think we could leave the JavaScript version in there? Could be as a compile time option for CUPS or even a hybrid approach based on the browser identification.

Collaborator

michaelrsweet commented Apr 25, 2008

CUPS.org User: mike

One option would be to show the custom option fields by default and then have javascript that hides them until "Custom" is chosen. That will allow the text-only browser to continue working as before while providing a better UI for Javascript-capable browsers.

BTW, this isn't just limited to text-only browsers; all versions of Firefox with the NoScript plug-in will block the javascript on the CUPS web interface by default. We don't want a lot of bug reports saying "I can't set the custom option values"... :)

Collaborator

michaelrsweet commented May 2, 2008

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 2, 2008

CUPS.org User: mike

George,

Please file a separate feature request for the extended string/password option support. This bug only covers the web interface.

Collaborator

michaelrsweet commented May 11, 2008

CUPS.org User: larsuebernickel

Mike,

I've done as you've suggested - JavaScript now hides the custom parameters after the page has been loaded. For browsers which don't understand JavaScript, the parameters are always shown. I've tested with lynx and Firefox's NoScript extension.

New patch is attached. It works fine against current svn (r7549).

Can we still get this into 1.4? Or is it already past feature freeze?

Lars
Collaborator

michaelrsweet commented May 11, 2008

CUPS.org User: larsuebernickel

Oops, already found a small bug. Custom option parameters were hidden even if the option was set to "Custom". Fixed in r3.

Lars
Collaborator

michaelrsweet commented Jul 25, 2008

CUPS.org User: mike

OK, after looking at the patch, it still needs a lot of work - there is no input validation for the custom values, and custom page sizes in particular do not have any way to specify units so users would have to enter points (not too user-friendly...)

Anyways, I'm working on that part and will likely stick with your HTML changes with a few minor fixes (remove XMLisms and add comments around javascript code so it doesn't get displayed...)

Collaborator

michaelrsweet commented Jul 25, 2008

CUPS.org User: mike

Fixed in Subversion repository.

Collaborator

michaelrsweet commented Jul 25, 2008

"cups-expose-coptions-r2.patch":

Index: doc/cups.css

--- doc/cups.css (revision 7549)
+++ doc/cups.css (working copy)
@@ -220,6 +220,12 @@
vertical-align: top;
}

+TH.sublabel {

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

HR {
border: solid thin;
}
Index: templates/set-printer-options-trailer.tmpl

--- templates/set-printer-options-trailer.tmpl (revision 7549)
+++ templates/set-printer-options-trailer.tmpl (working copy)
@@ -1 +1,10 @@
+
+<script type="text/javascript">
+// hide custom options parameters for browsers that understand javascript
+var paramtables = document.getElementsByClassName("paramtable");
+document.write("Length: " + paramtables.length)
+for (i = 0; i < paramtables.length; i++)

  • paramtables[i].style.display = "none";
    +</script>
Index: templates/set-printer-options-header.tmpl =================================================================== --- templates/set-printer-options-header.tmpl (revision 7549) +++ templates/set-printer-options-header.tmpl (working copy) @@ -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> + Index: templates/option-pickone.tmpl =================================================================== --- templates/option-pickone.tmpl (revision 7549) +++ templates/option-pickone.tmpl (working copy) @@ -1,6 +1,15 @@ {keytext}: - + {[choices]{text}} - + +{iscustom=1?{[params] - - - - +}
{paramtext}: - -
+:} Index: cgi-bin/admin.c =================================================================== --- cgi-bin/admin.c (revision 7549) +++ cgi-bin/admin.c (working copy) @@ -2753,7 +2753,55 @@ } }

+/*

  • * 'get_coption_value_string' - Create the value string for the custom
  • * parameters of an option.
  • /
    +static void
    +get_coption_value_string(char *valstr, /
    O - Resulting value string */
  •        size_t size,       /\* I - Maximum size of valstr */
    
  •        ppd_coption_t _opt)    /_ I - Option */
    
    +{
  • ppd_cparam_t *cparam;
  • size_t pos;
  • char keyword[2*PPD_MAX_NAME];
  • const char *var, *var2;
  • if (!strcmp(opt->keyword, "PageSize"))
  • {
  • var = cgiGetVariable("PageSize.Width");
  • var2 = cgiGetVariable("PageSize.Height");
  • snprintf(valstr, size, "Custom.%sx%s", var ? var : "0", var2 ? var2 : "0");
  • }
  • else 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)
  •  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)
    
  • continue;
  •  pos += snprintf(&valstr[pos], size - pos, "%s=%s, ", cparam->name, var);
    
  • }
  • /* Remove the last ',' */
  • if (pos > 3)
  •  strlcpy(&valstr[pos -3], "}", size);
    
  • }
    +}

/*

  • 'do_set_options()' - Configure the default options for a queue.
    /
    @@ -2780,10 +2828,12 @@
    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];

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

fprintf(stderr, "DEBUG: do_set_options(http=%p, is_class=%d)\n", http,
@@ -2928,7 +2978,7 @@

  cgiSetVariable("KEYWORD", option->keyword);
  cgiSetVariable("KEYTEXT", option->text);
    • if (option->conflicted)
      cgiSetVariable("CONFLICTED", "1");
      else
      @@ -2938,13 +2988,6 @@
      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 +2997,64 @@
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);
    
  •     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 +3068,14 @@
      break;
      }
      }
  • cgiCopyTemplateLang("option-trailer.tmpl");
  • 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);
    }
    }

@@ -3203,10 +3310,15 @@
else
var = cgiGetVariable(keyword);

  • if (var != NULL)
    
  • if (var == NULL)
    
  •   cupsFilePrintf(out, "%s\n", line);
    
  • else if (!strcmp(var, "Custom") && (coption = ppdFindCustomOption(ppd, keyword)))
    
  • {
    
  •   get_coption_value_string(tmp, 1024, coption);
    
  •   cupsFilePrintf(out, "*Default%s: %s\n", keyword, tmp);
    
  • }
    
  • else
    cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
    
  • else
    
  •   cupsFilePrintf(out, "%s\n", line);
    
    }
    }
Collaborator

michaelrsweet commented Jul 25, 2008

"cups-expose-coptions-r3.patch":

diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c
index 0d5c556..bfc977f 100644
--- a/cgi-bin/admin.c
+++ b/cgi-bin/admin.c
@@ -2753,6 +2753,54 @@ do_set_allowed_users(http_t http) / I - HTTP connection */
}
}

+/*

  • * 'get_coption_value_string' - Create the value string for the custom
  • * parameters of an option.
  • /
    +static void
    +get_coption_value_string(char *valstr, /
    O - Resulting value string */
  •        size_t size,       /\* I - Maximum size of valstr */
    
  •        ppd_coption_t _opt)    /_ I - Option */
    
    +{
  • ppd_cparam_t *cparam;
  • size_t pos;
  • char keyword[2*PPD_MAX_NAME];
  • const char *var, *var2;
  • if (!strcmp(opt->keyword, "PageSize"))
  • {
  • var = cgiGetVariable("PageSize.Width");
  • var2 = cgiGetVariable("PageSize.Height");
  • snprintf(valstr, size, "Custom.%sx%s", var ? var : "0", var2 ? var2 : "0");
  • }
  • else 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)
  •  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)
    
  • continue;
  •  pos += snprintf(&valstr[pos], size - pos, "%s=%s, ", cparam->name, var);
    
  • }
  • /* Remove the last ',' */
  • if (pos > 3)
  •  strlcpy(&valstr[pos -3], "}", size);
    
  • }
    +}

/*

  • 'do_set_options()' - Configure the default options for a queue.
    @@ -2780,9 +2828,11 @@ 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];

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

@@ -2928,7 +2978,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 +2988,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 +2997,64 @@ 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);
    
  •     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 +3068,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);
    }
    }

@@ -3203,10 +3310,15 @@ 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)))
    
  • {
    
  •   get_coption_value_string(tmp, 1024, coption);
    
  •   cupsFilePrintf(out, "*Default%s: %s\n", keyword, tmp);
    
  • }
    
  • else
    
  •   cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
    
    }
    }

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/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}: - -
+:} 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> +
Collaborator

michaelrsweet commented Jul 25, 2008

"str1729.patch":

Index: doc/cups.css

--- doc/cups.css (revision 7797)
+++ doc/cups.css (working copy)
@@ -204,6 +204,12 @@
vertical-align: top;
}

+TH.sublabel {

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

HR {
border: solid thin;
}

Index: CHANGES.txt

--- CHANGES.txt (revision 7800)
+++ CHANGES.txt (working copy)
@@ -3,6 +3,8 @@

CHANGES IN CUPS V1.4b1

    • Added support for custom options in the web interface
  • (STR #1729)
    
    • Added support for Mozilla LDAP, reconnection to LDAP servers,
      and improved LDAP performance (STR #1962)
    • Added Solaris SMF support (STR #1477)
      Index: templates/set-printer-options-trailer.tmpl

      --- templates/set-printer-options-trailer.tmpl (revision 7797)
      +++ templates/set-printer-options-trailer.tmpl (working copy)
      @@ -1 +1,12 @@
      +<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>
Index: templates/set-printer-options-header.tmpl =================================================================== --- templates/set-printer-options-header.tmpl (revision 7797) +++ templates/set-printer-options-header.tmpl (working copy) @@ -1,3 +1,16 @@ + +<SCRIPT TYPE="text/javascript"></SCRIPT> + Index: templates/option-pickone.tmpl =================================================================== --- templates/option-pickone.tmpl (revision 7797) +++ templates/option-pickone.tmpl (working copy) @@ -1,6 +1,18 @@ {keytext}: - + {[choices]{text}} - + +{iscustom=1?{[params] + + +}
{paramtext}:{params=Units? +Points +Millimeters +Centimeters +Inches +Feet +Meters +:}
+:} Index: cgi-bin/admin.c =================================================================== --- cgi-bin/admin.c (revision 7797) +++ cgi-bin/admin.c (working copy) @@ -20,15 +20,17 @@ - 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_delete_class() - Delete a class. - \* do_delete_printer() - Delete a printer. - \* do_export() - Export printers to Samba. - \* do_list_printers() - List available printers. - \* do_menu() - Show the main menu. - do_printer_op() - Do a printer operation. - do_set_allowed_users() - Set the allowed/denied users for a queue. - do_set_options() - Configure the default options for a queue. - \* do_set_sharing() - Set printer-is-shared value... - \* do_set_sharing() - Set printer-is-shared value. - \* get_option_value() - Return the value of an option. - \* get_points() - Get a value in points. - match_string() - Return the number of matching characters. */

@@ -43,6 +45,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
+#include <limits.h>

/*
@@ -64,6 +67,9 @@
ipp_op_t op, const char *title);
static void do_set_allowed_users(http_t *http);
static void do_set_sharing(http_t *http);
+static char *get_option_value(ppd_file_t *ppd, const char *name,

  •                     char *buffer, size_t bufsize);
    
    +static double get_points(double number, const char *uval);
    static int match_string(const char *a, const char *b);

@@ -177,7 +183,7 @@
else
{
/*

  •  \* Bad operation code...  Display an error...
    
  •  * Bad operation code - display an error...
    

    */

    cgiStartHTML(cgiText(_("Administration")));
    @@ -206,7 +212,7 @@
    else
    {
    /*

  • * Form data but no operation code... Display an error...

    • Form data but no operation code - display an error...
      */

      cgiStartHTML(cgiText(_("Administration")));
      @@ -1769,7 +1775,7 @@

    /*

  • * 'do_delete_class()' - Delete a class...

    • 'do_delete_class()' - Delete a class.
      */

    static void
    @@ -1854,7 +1860,7 @@

    /*

  • * 'do_delete_printer()' - Delete a printer...

    • 'do_delete_printer()' - Delete a printer.
      */

    static void
    @@ -1939,7 +1945,7 @@

    /*

  • * 'do_export()' - Export printers to Samba...

    • 'do_export()' - Export printers to Samba.
      */

    static void
    @@ -2075,7 +2081,7 @@

    /*

  • * 'do_list_printers()' - List available printers...

    • 'do_list_printers()' - List available printers.
      */

    static void
    @@ -2278,7 +2284,7 @@

    /*

  • * 'do_menu()' - Show the main menu...

    • 'do_menu()' - Show the main menu.
      */

    static void
    @@ -2774,12 +2780,15 @@
    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_coption_t coption; / Custom option */

  • ppd_cparam_t cparam; / Custom parameter /
    ppd_attr_t *protocol; /
    cupsProtocol attribute /
    const char *title; /
    Page title */

@@ -2847,32 +2856,14 @@
{
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 ++)
  • {

- 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(("<LI>%s = \"%s\"</LI>\n", option->keyword, var));
      
    • have_options = 1;
      
    • ppdMarkOption(ppd, option->keyword, var);
      
    • }
      -#ifdef DEBUG
    • else
    • printf("<LI>%s not defined!</LI>\n", option->keyword);
      

      -#endif /* DEBUG */

    •  DEBUG_puts("</UL></LI>");
      

    - }

    • DEBUG_printf(("

    \n"

  •     "<P>ppdConflicts(ppd) = %d\n", ppdConflicts(ppd)));
    
  • for (option = ppdFirstOption(ppd);

  •     option;
    
  • option = ppdNextOption(ppd))

  •  if ((var = cgiGetVariable(option->keyword)) != NULL)
    
  •  {
    
  • have_options = 1;

  • ppdMarkOption(ppd, option->keyword, var);

  •  }
    

    }

    if (!have_options || ppdConflicts(ppd))
    @@ -2928,7 +2919,7 @@

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

    • if (option->conflicted)
      cgiSetVariable("CONFLICTED", "1");
      else
      @@ -2938,13 +2929,6 @@
      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 +2938,118 @@
    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 :
        @@ -3199,17 +3295,21 @@
        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)
      
    • if (!var)
      
    •   cupsFilePrintf(out, "%s\n", line);
      
    • else
      cupsFilePrintf(out, "*Default%s: %s\n", keyword, var);
      
    • else
      
    •   cupsFilePrintf(out, "%s\n", line);
      

      }
      }

    • /*
      
    •  \* TODO: We need to set the port-monitor attribute!
      
    •  _/
      
      • if ((var = cgiGetVariable("protocol")) != NULL)
        cupsFilePrintf(out, "_cupsProtocol: %s\n", var);

    @@ -3307,7 +3407,7 @@

    /*

    • * 'do_set_sharing()' - Set printer-is-shared value...

      • 'do_set_sharing()' - Set printer-is-shared value.
        */

      static void
      @@ -3400,6 +3500,294 @@

      /*

    • * 'get_option_value()' - Return the value of an option.

    • * This function also handles generation of custom option values.

    • /
      +
      +static char * /
      O - Value string or NULL on error */
      +get_option_value(

    • ppd_file_t ppd, / I - PPD file */

    • const char name, / I - Option name */

    • char buffer, / I - String buffer */

    • size_t bufsize) /* I - Size of buffer */
      +{

    • char bufptr, / Pointer into buffer */

    •   _bufend;        /_ End of buffer */
      
    • ppd_coption_t coption; / Custom option */

    • ppd_cparam_t cparam; / Current custom parameter */

    • char keyword[256]; /* Parameter name */

    • const char val, / Parameter value */

    •   _uval;          /_ Units value */
      
    • long integer; /* Integer value */

    • double number, /* Number value */

    •   number_points;      /\* Number in points */
      
    • /*

    • * See if we have a custom option choice...

    • */

    • if ((val = cgiGetVariable(name)) == NULL)
    • {
    • /*
    • * Option not found!
    • */
    • return (NULL);
    • }
    • else if (strcasecmp(val, "Custom") ||
    •       (coption = ppdFindCustomOption(ppd, name)) == NULL)
      
    • {
    • /*
    • * Not a custom choice...
    • */
    • strlcpy(buffer, val, bufsize);
    • return (buffer);
    • }
    • /*
    • * OK, we have a custom option choice, format it...
    • */
    • *buffer = '\0';
    • if (!strcmp(coption->keyword, "PageSize"))
    • {
    • const char lval; / Length string value */
    • double width, /* Width value */
    •   width_points,       /\* Width in points */
      
    •   length,         /\* Length value */
      
    •   length_points;      /\* Length in points */
      
    • val = cgiGetVariable("PageSize.Width");
    • lval = cgiGetVariable("PageSize.Height");
    • uval = cgiGetVariable("PageSize.Units");
    • if (!val || !lval || !uval ||
    •    (width = strtod(val, NULL)) == 0.0 ||
      
    •    (length = strtod(lval, NULL)) == 0.0 ||
      
    •    (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
      
    • strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
    •  return (NULL);
      
    • width_points = get_points(width, uval);
    • length_points = get_points(length, uval);
    • if (width_points < ppd->custom_min[0] ||
    •    width_points > ppd->custom_max[0] ||
      
    •    length_points < ppd->custom_min[1] ||
      
    • length_points > ppd->custom_max[1])
    •  return (NULL);
      
    • snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
    • }
    • else if (cupsArrayCount(coption->params) == 1)
    • {
    • cparam = ppdFirstCustomParam(coption);
    • snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
    • if ((val = cgiGetVariable(keyword)) == NULL)
    •  return (NULL);
      
    • switch (cparam->type)
    • {
    •  case PPD_CUSTOM_CURVE :
      
    •  case PPD_CUSTOM_INVCURVE :
      
    •  case PPD_CUSTOM_REAL :
      
    • if ((number = strtod(val, NULL)) == 0.0 ||
      
    •     number < cparam->minimum.custom_real ||
      
    •     number > cparam->maximum.custom_real)
      
    •   return (NULL);
      
    •      snprintf(buffer, bufsize, "Custom.%g", number);
      
    •      break;
      
    •  case PPD_CUSTOM_INT :
      
    •      if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
      
    •     integer == LONG_MAX ||
      
    •     integer < cparam->minimum.custom_int ||
      
    •     integer > cparam->maximum.custom_int)
      
    •        return (NULL);
      
    •      snprintf(buffer, bufsize, "Custom.%ld", integer);
      
    •      break;
      
    •  case PPD_CUSTOM_POINTS :
      
    •      snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
      
    • if ((number = strtod(val, NULL)) == 0.0 ||
      
    •     (uval = cgiGetVariable(keyword)) == NULL ||
      
    •     (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
      
    •      strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
      
    •   return (NULL);
      
    • number_points = get_points(number, uval);
      
    • if (number_points < cparam->minimum.custom_points ||
      
    •     number_points > cparam->maximum.custom_points)
      
    •   return (NULL);
      
    • snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
      
    •      break;
      
    •  case PPD_CUSTOM_PASSCODE :
      
    •      for (uval = val; *uval; uval ++)
      
    •   if (!isdigit(*uval & 255))
      
    •     return (NULL);
      
    •  case PPD_CUSTOM_PASSWORD :
      
    •  case PPD_CUSTOM_STRING :
      
    •      integer = (long)strlen(val);
      
    • if (integer < cparam->minimum.custom_string ||
      
    •     integer > cparam->maximum.custom_string)
      
    •   return (NULL);
      
    •      snprintf(buffer, bufsize, "Custom.%s", val);
      
    • break;
      
    • }
    • }
    • else
    • {
    • const char prefix = "{"; / Prefix string */
    • bufptr = buffer;
    • bufend = buffer + bufsize;
    • for (cparam = ppdFirstCustomParam(coption);
    • cparam;
    • cparam = ppdNextCustomParam(coption))
    • {
    •  snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
      
    •           cparam->name);
      
    •  if ((val = cgiGetVariable(keyword)) == NULL)
      
    • return (NULL);
    •  snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
      
    •  bufptr += strlen(bufptr);
      
    •  prefix = " ";
      
    •  switch (cparam->type)
      
    •  {
      
    • case PPD_CUSTOM_CURVE :
    • case PPD_CUSTOM_INVCURVE :
    • case PPD_CUSTOM_REAL :
    •   if ((number = strtod(val, NULL)) == 0.0 ||
      
    •   number < cparam->minimum.custom_real ||
      
    •   number > cparam->maximum.custom_real)
      
    •     return (NULL);
      
    •   snprintf(bufptr, bufend - bufptr, "%g", number);
      
    •   break;
      
    • case PPD_CUSTOM_INT :
    •   if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
      
    •   integer == LONG_MAX ||
      
    •   integer < cparam->minimum.custom_int ||
      
    •   integer > cparam->maximum.custom_int)
      
    •     return (NULL);
      
    •   snprintf(bufptr, bufend - bufptr, "%ld", integer);
      
    •   break;
      
    • case PPD_CUSTOM_POINTS :
    •   snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
      
    •   if ((number = strtod(val, NULL)) == 0.0 ||
      
    •   (uval = cgiGetVariable(keyword)) == NULL ||
      
    •   (strcmp(uval, "pt") && strcmp(uval, "in") &&
      
    •    strcmp(uval, "ft") && strcmp(uval, "cm") &&
      
    •    strcmp(uval, "mm") && strcmp(uval, "m")))
      
    •     return (NULL);
      
    •   number_points = get_points(number, uval);
      
    •   if (number_points < cparam->minimum.custom_points ||
      
    •   number_points > cparam->maximum.custom_points)
      
    •     return (NULL);
      
    •   snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
      
    •   break;
      
    • case PPD_CUSTOM_PASSCODE :
    •   for (uval = val; *uval; uval ++)
      
    •     if (!isdigit(*uval & 255))
      
    •   return (NULL);
      
    • case PPD_CUSTOM_PASSWORD :
    • case PPD_CUSTOM_STRING :
    •   integer = (long)strlen(val);
      
    •   if (integer < cparam->minimum.custom_string ||
      
    •   integer > cparam->maximum.custom_string)
      
    •     return (NULL);
      
    •   if ((bufptr + 2) > bufend)
      
    •     return (NULL);
      
    •   bufend --;
      
    •   *bufptr++ = '\"';
      
    •   while (*val && bufptr < bufend)
      
    •   {
      
    •     if (*val == '\' || *val == '\"')
      
    •     {
      
    •   if ((bufptr + 1) >= bufend)
      
    •     return (NULL);
      
    •   *bufptr++ = '\';
      
    •     }
      
    •     *bufptr++ = *val++;
      
    •   }
      
    •   if (bufptr >= bufend)
      
    •     return (NULL);
      
    •   *bufptr++ = '\"';
      
    •   *bufptr   = '\0';
      
    •   bufend ++;
      
    •   break;
      
    •  }
      
    •  bufptr += strlen(bufptr);
      
    • }
    • if (bufptr == buffer || (bufend - bufptr) < 2)
    •  return (NULL);
      
    • strcpy(bufptr, "}");
    • }
    • return (buffer);
      +}

    +/*

    • * 'get_points()' - Get a value in points.
    • /
      +
      +static double /
      O - Number in points /
      +get_points(double number, /
      I - Original number */
    •       const char _uval)       /_ I - Units */
      
      +{
    • if (!strcmp(uval, "mm")) /* Millimeters */
    • return (number * 72.0 / 25.4);
    • else if (!strcmp(uval, "cm")) /* Centimeters */
    • return (number * 72.0 / 2.54);
    • else if (!strcmp(uval, "in")) /* Inches */
    • return (number * 72.0);
    • else if (!strcmp(uval, "ft")) /* Feet */
    • return (number * 72.0 * 12.0);
    • else if (!strcmp(uval, "m")) /* Meters */
    • return (number * 72.0 / 0.0254);
    • else /* Points */
    • return (number);
      +}

    +/*

    • 'match_string()' - Return the number of matching characters.
      */

    @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