]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cgi-bin/admin.c
Merge changes from CUPS 1.4svn-r7994.
[thirdparty/cups.git] / cgi-bin / admin.c
index e67582d0202435d81fe437a75376d5a81696dd27..70a57dc5e0e0d7a35bb6fae7101b67b2e4abdb5f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $"
+ * "$Id: admin.c 7888 2008-08-29 21:16:56Z mike $"
  *
  *   Administration CGI for the Common UNIX Printing System (CUPS).
  *
  *   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 @@ static void   do_printer_op(http_t *http,
                              ipp_op_t op, const char *title);
 static void    do_set_allowed_users(http_t *http);
 static void    do_set_sharing(http_t *http);
+static char    *get_option_value(ppd_file_t *ppd, const char *name,
+                                 char *buffer, size_t bufsize);
+static double  get_points(double number, const char *uval);
 static int     match_string(const char *a, const char *b);
 
 
@@ -109,7 +115,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
   * See if we have form data...
   */
 
-  if (!cgiInitialize())
+  if (!cgiInitialize() || !cgiGetVariable("OP"))
   {
    /*
     * Nope, send the administration menu...
@@ -177,7 +183,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")));
@@ -198,6 +204,8 @@ 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);
     else
@@ -206,7 +214,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
   else
   {
    /*
-    * Form data but no operation code...  Display an error...
+    * Form data but no operation code - display an error...
     */
 
     cgiStartHTML(cgiText(_("Administration")));
@@ -902,7 +910,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 +957,15 @@ 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);
+      }
 
       cgiCopyTemplateLang("modify-printer.tmpl");
     }
@@ -959,6 +975,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");
     }
 
@@ -1169,6 +1192,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 +1211,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 +1247,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);
 
@@ -1378,17 +1410,32 @@ 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, /* BrowseWebIF value */
+                       *preserve_job_history,
+                                       /* PreserveJobHistory value */
+                       *preserve_job_files,
+                                       /* PreserveJobFiles value */
+                       *max_clients,   /* MaxClients value */
+                       *max_jobs,      /* MaxJobs value */
+                       *max_log_size;  /* MaxLogSize value */
+    char               local_protocols[255],
+                                       /* BrowseLocalProtocols */
+                       remote_protocols[255];
+                                       /* BrowseRemoteProtocols */
 #ifdef HAVE_GSSAPI
     char               default_auth_type[255];
                                        /* DefaultAuthType value */
+    const char         *val;           /* Setting value */ 
 #endif /* HAVE_GSSAPI */
 
 
@@ -1396,12 +1443,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 +1558,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));
@@ -1443,23 +1573,46 @@ do_config_server(http_t *http)          /* I - HTTP connection */
     * 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 = cupsGetOption("BrowseLocalProtocols", num_settings, settings) ||
+               strcasecmp(local_protocols,
+                          CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS) ||
+               cupsGetOption("BrowseRemoteProtocols", num_settings,
+                             settings) ||
+               strcasecmp(remote_protocols,
+                          CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS) ||
+               cupsGetOption("BrowseWebIF", num_settings, settings) ||
+               strcasecmp(browse_web_if, "No") ||
+               cupsGetOption("PreserveJobHistory", num_settings, settings) ||
+               strcasecmp(preserve_job_history, "Yes") ||
+               cupsGetOption("PreserveJobFiles", num_settings, settings) ||
+               strcasecmp(preserve_job_files, "No") ||
+               cupsGetOption("MaxClients", num_settings, settings) ||
+               strcasecmp(max_clients, "100") ||
+               cupsGetOption("MaxJobs", num_settings, settings) ||
+               strcasecmp(max_jobs, "500") ||
+               cupsGetOption("MaxLogSize", num_settings, settings) ||
+               strcasecmp(max_log_size, "1m");
+
+    if (changed)
     {
      /*
       * Settings *have* changed, so save the changes...
@@ -1485,6 +1638,47 @@ do_config_server(http_t *http)           /* I - HTTP connection */
                                    num_settings, &settings);
 #endif /* HAVE_GSSAPI */
 
+      if (advanced)
+      {
+       /*
+        * Add advanced settings...
+       */
+
+       if (cupsGetOption("BrowseLocalProtocols", num_settings, settings) ||
+           strcasecmp(local_protocols, CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS))
+         num_settings = cupsAddOption("BrowseLocalProtocols", local_protocols,
+                                      num_settings, &settings);
+       if (cupsGetOption("BrowseRemoteProtocols", num_settings, settings) ||
+           strcasecmp(remote_protocols, CUPS_DEFAULT_BROWSE_REMOTE_PROTOCOLS))
+         num_settings = cupsAddOption("BrowseRemoteProtocols", remote_protocols,
+                                      num_settings, &settings);
+       if (cupsGetOption("BrowseWebIF", num_settings, settings) ||
+           strcasecmp(browse_web_if, "No"))
+         num_settings = cupsAddOption("BrowseWebIF", browse_web_if,
+                                      num_settings, &settings);
+       if (cupsGetOption("PreserveJobHistory", num_settings, settings) ||
+           strcasecmp(preserve_job_history, "Yes"))
+         num_settings = cupsAddOption("PreserveJobHistory",
+                                      preserve_job_history, num_settings,
+                                      &settings);
+       if (cupsGetOption("PreserveJobFiles", num_settings, settings) ||
+           strcasecmp(preserve_job_files, "No"))
+         num_settings = cupsAddOption("PreserveJobFiles", preserve_job_files,
+                                      num_settings, &settings);
+        if (cupsGetOption("MaxClients", num_settings, settings) ||
+           strcasecmp(max_clients, "100"))
+         num_settings = cupsAddOption("MaxClients", max_clients, num_settings,
+                                      &settings);
+        if (cupsGetOption("MaxJobs", num_settings, settings) ||
+           strcasecmp(max_jobs, "500"))
+         num_settings = cupsAddOption("MaxJobs", max_jobs, num_settings,
+                                      &settings);
+        if (cupsGetOption("MaxLogSize", num_settings, settings) ||
+           strcasecmp(max_log_size, "1m"))
+         num_settings = cupsAddOption("MaxLogSize", max_log_size, num_settings,
+                                      &settings);
+      }
+
       if (!cupsAdminSetServerSettings(http, num_settings, settings))
       {
         if (cupsLastError() == IPP_NOT_AUTHORIZED)
@@ -1769,7 +1963,7 @@ do_config_server(http_t *http)            /* I - HTTP connection */
 
 
 /*
- * 'do_delete_class()' - Delete a class...
+ * 'do_delete_class()' - Delete a class.
  */
 
 static void
@@ -1854,7 +2048,7 @@ do_delete_class(http_t *http)             /* I - HTTP connection */
 
 
 /*
- * 'do_delete_printer()' - Delete a printer...
+ * 'do_delete_printer()' - Delete a printer.
  */
 
 static void
@@ -1939,7 +2133,7 @@ do_delete_printer(http_t *http)           /* I - HTTP connection */
 
 
 /*
- * 'do_export()' - Export printers to Samba...
+ * 'do_export()' - Export printers to Samba.
  */
 
 static void
@@ -2075,7 +2269,7 @@ do_export(http_t *http)                   /* I - HTTP connection */
 
 
 /*
- * 'do_list_printers()' - List available printers...
+ * 'do_list_printers()' - List available printers.
  */
 
 static void
@@ -2278,7 +2472,7 @@ do_list_printers(http_t *http)            /* I - HTTP connection */
 
 
 /*
- * 'do_menu()' - Show the main menu...
+ * 'do_menu()' - Show the main menu.
  */
 
 static void
@@ -2336,6 +2530,94 @@ do_menu(http_t *http)                    /* I - HTTP connection */
     cgiSetVariable("KERBEROS", "CHECKED");
 #endif /* HAVE_GSSAPI */
 
+#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);
 
  /*
@@ -2602,6 +2884,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 +2952,9 @@ do_set_allowed_users(http_t *http)        /* I - HTTP connection */
         while (*ptr == ',' || isspace(*ptr & 255))
          ptr ++;
 
+        if (!*ptr)
+         break;
+
         if (*ptr == '\'' || *ptr == '\"')
        {
         /*
@@ -2774,13 +3062,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 */
 
 
@@ -2808,6 +3099,67 @@ 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"))
+  {
+    int                        job_id;         /* Command file job */
+    char               refresh[1024];  /* Refresh URL */
+    http_status_t      status;         /* Document status */
+    static const char  *autoconfigure =/* Command file */
+                       "#CUPS-COMMAND\n"
+                       "AutoConfigure\n";
+
+
+    if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, printer, "Auto-Configure",
+                                0, NULL)) < 1)
+    {
+      cgiSetVariable("ERROR", cgiText(_("Unable to send auto-configure command "
+                                        "to printer driver!")));
+      cgiStartHTML(title);
+      cgiCopyTemplateLang("error.tmpl");
+      cgiEndHTML();
+      return;
+    }
+
+    status = cupsStartDocument(CUPS_HTTP_DEFAULT, printer, job_id,
+                               "AutoConfigure.command", CUPS_FORMAT_COMMAND, 1);
+    if (status == HTTP_CONTINUE)
+      status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, autoconfigure,
+                                    strlen(autoconfigure));
+    if (status == HTTP_CONTINUE)
+      cupsFinishDocument(CUPS_HTTP_DEFAULT, printer);
+
+    if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
+    {
+      cgiSetVariable("ERROR", cupsLastErrorString());
+      cgiStartHTML(title);
+      cgiCopyTemplateLang("error.tmpl");
+      cgiEndHTML();
+
+      cupsCancelJob(printer, job_id);
+      return;
+    }
+
+   /*
+    * Redirect successful updates back to the printer page...
+    */
+
+    cgiFormEncode(uri, printer, sizeof(uri));
+    snprintf(refresh, sizeof(refresh), "5;URL=/admin/?OP=redirect&URL=/%s/%s",
+            is_class ? "classes" : "printers", uri);
+    cgiSetVariable("refresh_page", refresh);
+
+    cgiStartHTML(title);
+
+    cgiCopyTemplateLang("printer-configured.tmpl");
+    cgiEndHTML();
+    return;
+  }
+
  /*
   * Get the PPD file...
   */
@@ -2847,32 +3199,14 @@ do_set_options(http_t *http,            /* I - HTTP connection */
   {
     ppdMarkDefaults(ppd);
 
-    DEBUG_printf(("<P>ppd->num_groups = %d\n"
-                 "<UL>\n", ppd->num_groups));
-
-    for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++)
-    {
-      DEBUG_printf(("<LI>%s<UL>\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(("</UL>\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))
@@ -2883,6 +3217,23 @@ do_set_options(http_t *http,             /* I - HTTP connection */
 
     fputs("DEBUG: Showing options...\n", stderr);
 
+    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;
+         }
+      }
+    }
+
     cgiStartHTML(cgiText(_("Set Printer Options")));
     cgiCopyTemplateLang("set-printer-options-header.tmpl");
 
@@ -2928,7 +3279,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 +3289,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 +3298,118 @@ 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 :
@@ -3110,7 +3566,7 @@ do_set_options(http_t *http,              /* I - HTTP connection */
 
     if (ppd && ppd->protocols && strstr(ppd->protocols, "BCP"))
     {
-      protocol = ppdFindAttr(ppd, "cupsProtocol", NULL);
+      ppdattr = ppdFindAttr(ppd, "cupsProtocol", NULL);
 
       cgiSetVariable("GROUP", cgiText(_("PS Binary Protocol")));
       cgiCopyTemplateLang("option-header.tmpl");
@@ -3133,7 +3589,7 @@ do_set_options(http_t *http,              /* I - HTTP connection */
 
       cgiSetVariable("KEYWORD", "protocol");
       cgiSetVariable("KEYTEXT", cgiText(_("PS Binary Protocol")));
-      cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None");
+      cgiSetVariable("DEFCHOICE", ppdattr ? ppdattr->value : "None");
 
       cgiCopyTemplateLang("option-pickone.tmpl");
 
@@ -3199,17 +3655,21 @@ 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);
        }
       }
 
+     /*
+      * TODO: We need to set the port-monitor attribute!
+      */
+
       if ((var = cgiGetVariable("protocol")) != NULL)
        cupsFilePrintf(out, "*cupsProtocol: %s\n", var);
 
@@ -3307,7 +3767,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
@@ -3399,6 +3859,294 @@ do_set_sharing(http_t *http)            /* I - HTTP connection */
 }
 
 
+/*
+ * 'get_option_value()' - Return the value of an option.
+ *
+ * This function also handles generation of custom option values.
+ */
+
+static char *                          /* O - Value string or NULL on error */
+get_option_value(
+    ppd_file_t    *ppd,                        /* I - PPD file */
+    const char    *name,               /* I - Option name */
+    char          *buffer,             /* I - String buffer */
+    size_t        bufsize)             /* I - Size of buffer */
+{
+  char         *bufptr,                /* Pointer into buffer */
+               *bufend;                /* End of buffer */
+  ppd_coption_t *coption;              /* Custom option */
+  ppd_cparam_t *cparam;                /* Current custom parameter */
+  char         keyword[256];           /* Parameter name */
+  const char   *val,                   /* Parameter value */
+               *uval;                  /* Units value */
+  long         integer;                /* Integer value */
+  double       number,                 /* Number value */
+               number_points;          /* Number in points */
+
+
+ /*
+  * See if we have a custom option choice...
+  */
+
+  if ((val = cgiGetVariable(name)) == NULL)
+  {
+   /*
+    * Option not found!
+    */
+
+    return (NULL);
+  }
+  else if (strcasecmp(val, "Custom") ||
+           (coption = ppdFindCustomOption(ppd, name)) == NULL)
+  {
+   /*
+    * Not a custom choice...
+    */
+
+    strlcpy(buffer, val, bufsize);
+    return (buffer);
+  }
+
+ /*
+  * OK, we have a custom option choice, format it...
+  */
+
+  *buffer = '\0';
+
+  if (!strcmp(coption->keyword, "PageSize"))
+  {
+    const char *lval;                  /* Length string value */
+    double     width,                  /* Width value */
+               width_points,           /* Width in points */
+               length,                 /* Length value */
+               length_points;          /* Length in points */
+
+
+    val  = cgiGetVariable("PageSize.Width");
+    lval = cgiGetVariable("PageSize.Height");
+    uval = cgiGetVariable("PageSize.Units");
+
+    if (!val || !lval || !uval ||
+        (width = strtod(val, NULL)) == 0.0 ||
+        (length = strtod(lval, NULL)) == 0.0 ||
+        (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+        strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+      return (NULL);
+
+    width_points  = get_points(width, uval);
+    length_points = get_points(length, uval);
+
+    if (width_points < ppd->custom_min[0] ||
+        width_points > ppd->custom_max[0] ||
+        length_points < ppd->custom_min[1] ||
+       length_points > ppd->custom_max[1])
+      return (NULL);
+
+    snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval);
+  }
+  else if (cupsArrayCount(coption->params) == 1) 
+  {
+    cparam = ppdFirstCustomParam(coption);
+    snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name);
+
+    if ((val = cgiGetVariable(keyword)) == NULL)
+      return (NULL);
+
+    switch (cparam->type)
+    {
+      case PPD_CUSTOM_CURVE :
+      case PPD_CUSTOM_INVCURVE :
+      case PPD_CUSTOM_REAL :
+         if ((number = strtod(val, NULL)) == 0.0 ||
+             number < cparam->minimum.custom_real ||
+             number > cparam->maximum.custom_real)
+           return (NULL);
+
+          snprintf(buffer, bufsize, "Custom.%g", number);
+          break;
+
+      case PPD_CUSTOM_INT :
+          if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+             integer == LONG_MAX ||
+             integer < cparam->minimum.custom_int ||
+             integer > cparam->maximum.custom_int)
+            return (NULL);
+
+          snprintf(buffer, bufsize, "Custom.%ld", integer);
+          break;
+
+      case PPD_CUSTOM_POINTS :
+          snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+         if ((number = strtod(val, NULL)) == 0.0 ||
+             (uval = cgiGetVariable(keyword)) == NULL ||
+             (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") &&
+              strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m")))
+           return (NULL);
+
+         number_points = get_points(number, uval);
+         if (number_points < cparam->minimum.custom_points ||
+             number_points > cparam->maximum.custom_points)
+           return (NULL);
+
+         snprintf(buffer, bufsize, "Custom.%g%s", number, uval);
+          break;
+
+      case PPD_CUSTOM_PASSCODE :
+          for (uval = val; *uval; uval ++)
+           if (!isdigit(*uval & 255))
+             return (NULL);
+
+      case PPD_CUSTOM_PASSWORD :
+      case PPD_CUSTOM_STRING :
+          integer = (long)strlen(val);
+         if (integer < cparam->minimum.custom_string ||
+             integer > cparam->maximum.custom_string)
+           return (NULL);
+
+          snprintf(buffer, bufsize, "Custom.%s", val);
+         break;
+    }
+  }
+  else
+  {
+    const char *prefix = "{";          /* Prefix string */
+
+
+    bufptr = buffer;
+    bufend = buffer + bufsize;
+
+    for (cparam = ppdFirstCustomParam(coption);
+        cparam;
+        cparam = ppdNextCustomParam(coption))
+    {
+      snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword,
+               cparam->name);
+
+      if ((val = cgiGetVariable(keyword)) == NULL)
+       return (NULL);
+
+      snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name);
+      bufptr += strlen(bufptr);
+      prefix = " ";
+
+      switch (cparam->type)
+      {
+       case PPD_CUSTOM_CURVE :
+       case PPD_CUSTOM_INVCURVE :
+       case PPD_CUSTOM_REAL :
+           if ((number = strtod(val, NULL)) == 0.0 ||
+               number < cparam->minimum.custom_real ||
+               number > cparam->maximum.custom_real)
+             return (NULL);
+
+           snprintf(bufptr, bufend - bufptr, "%g", number);
+           break;
+
+       case PPD_CUSTOM_INT :
+           if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN ||
+               integer == LONG_MAX ||
+               integer < cparam->minimum.custom_int ||
+               integer > cparam->maximum.custom_int)
+             return (NULL);
+
+           snprintf(bufptr, bufend - bufptr, "%ld", integer);
+           break;
+
+       case PPD_CUSTOM_POINTS :
+           snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword);
+
+           if ((number = strtod(val, NULL)) == 0.0 ||
+               (uval = cgiGetVariable(keyword)) == NULL ||
+               (strcmp(uval, "pt") && strcmp(uval, "in") &&
+                strcmp(uval, "ft") && strcmp(uval, "cm") &&
+                strcmp(uval, "mm") && strcmp(uval, "m")))
+             return (NULL);
+
+           number_points = get_points(number, uval);
+           if (number_points < cparam->minimum.custom_points ||
+               number_points > cparam->maximum.custom_points)
+             return (NULL);
+
+           snprintf(bufptr, bufend - bufptr, "%g%s", number, uval);
+           break;
+
+       case PPD_CUSTOM_PASSCODE :
+           for (uval = val; *uval; uval ++)
+             if (!isdigit(*uval & 255))
+               return (NULL);
+
+       case PPD_CUSTOM_PASSWORD :
+       case PPD_CUSTOM_STRING :
+           integer = (long)strlen(val);
+           if (integer < cparam->minimum.custom_string ||
+               integer > cparam->maximum.custom_string)
+             return (NULL);
+
+           if ((bufptr + 2) > bufend)
+             return (NULL);
+
+           bufend --;
+           *bufptr++ = '\"';
+
+           while (*val && bufptr < bufend)
+           {
+             if (*val == '\\' || *val == '\"')
+             {
+               if ((bufptr + 1) >= bufend)
+                 return (NULL);
+
+               *bufptr++ = '\\';
+             }
+
+             *bufptr++ = *val++;
+           }
+
+           if (bufptr >= bufend)
+             return (NULL);
+
+           *bufptr++ = '\"';
+           *bufptr   = '\0';
+           bufend ++;
+           break;
+      }
+
+      bufptr += strlen(bufptr);
+    }
+
+    if (bufptr == buffer || (bufend - bufptr) < 2)
+      return (NULL);
+
+    strcpy(bufptr, "}");
+  }
+
+  return (buffer);
+}
+
+
+/*
+ * 'get_points()' - Get a value in points.
+ */
+
+static double                          /* O - Number in points */
+get_points(double     number,          /* I - Original number */
+           const char *uval)           /* I - Units */
+{
+  if (!strcmp(uval, "mm"))             /* Millimeters */
+    return (number * 72.0 / 25.4);
+  else if (!strcmp(uval, "cm"))                /* Centimeters */
+    return (number * 72.0 / 2.54);
+  else if (!strcmp(uval, "in"))                /* Inches */
+    return (number * 72.0);
+  else if (!strcmp(uval, "ft"))                /* Feet */
+    return (number * 72.0 * 12.0);
+  else if (!strcmp(uval, "m"))         /* Meters */
+    return (number * 72.0 / 0.0254);
+  else                                 /* Points */
+    return (number);
+}
+
+
 /*
  * 'match_string()' - Return the number of matching characters.
  */
@@ -3449,5 +4197,5 @@ match_string(const char *a,               /* I - First string */
 
     
 /*
- * End of "$Id: admin.c 7438 2008-04-09 03:27:37Z mike $".
+ * End of "$Id: admin.c 7888 2008-08-29 21:16:56Z mike $".
  */