]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Update (and use) web interface stylesheet.
authormike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 17 Aug 2005 21:15:41 +0000 (21:15 +0000)
committermike <mike@7a7537e8-13f0-0310-91df-b6672ffda945>
Wed, 17 Aug 2005 21:15:41 +0000 (21:15 +0000)
Implement fast printer adds from the admin page.

Remove @ALL from policies - not needed.

Add debug logging to basic server settings, and start implementing
config file updater.

Add make and model to device URI that is passed to allow for
automatic driver selection.

git-svn-id: svn+ssh://src.apple.com/svn/cups/cups.org/trunk@4581 7a7537e8-13f0-0310-91df-b6672ffda945

cgi-bin/admin.c
cgi-bin/ipp-var.c
cgi-bin/ipp-var.h
conf/cupsd.conf.in
doc/cups.css
scheduler/conf.c
scheduler/policy.c
templates/admin.tmpl
templates/choose-device.tmpl
templates/header.tmpl

index f24f060c5eb510f98aacf694219ddc4bb21f843f..e63ec40b447f9706185ef8f6c41cc4a30cdd9a7f 100644 (file)
  *
  * Contents:
  *
- *   main()                 - Main entry for CGI.
- *   do_am_class()          - Add or modify a class.
- *   do_am_printer()        - Add or modify a printer.
- *   do_config_printer()    - Configure the default options for a printer.
- *   do_delete_class()      - Delete a class...
- *   do_delete_printer()    - Delete a printer...
- *   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.
- *   get_line()             - Get a line that is terminated by a LF, CR, or CR LF.
+ *   main()                    - Main entry for CGI.
+ *   compare_printer_devices() - Compare two printer devices.
+ *   do_am_class()             - Add or modify a class.
+ *   do_am_printer()           - Add or modify a printer.
+ *   do_config_printer()       - Configure the default options for a printer.
+ *   do_config_server()        - Configure server settings.
+ *   do_delete_class()         - Delete a class...
+ *   do_delete_printer()       - Delete a printer...
+ *   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.
+ *   form_encode()             - Encode a string as a form variable...
+ *   get_line()                - Get a line that is terminated by a LF, CR, or CR LF.
+ *   match_string()            - Return the number of matching characters.
  */
 
 /*
 static void    do_am_class(http_t *http, cups_lang_t *language, int modify);
 static void    do_am_printer(http_t *http, cups_lang_t *language, int modify);
 static void    do_config_printer(http_t *http, cups_lang_t *language);
+static void    do_config_server(http_t *http, cups_lang_t *language);
 static void    do_delete_class(http_t *http, cups_lang_t *language);
 static void    do_delete_printer(http_t *http, cups_lang_t *language);
 static void    do_menu(http_t *http, cups_lang_t *language);
 static void    do_printer_op(http_t *http, cups_lang_t *language, ipp_op_t op);
 static void    do_set_allowed_users(http_t *http, cups_lang_t *language);
+static void    form_encode(char *dst, const char *src, size_t dstsize);
 static char    *get_line(char *buf, int length, FILE *fp);
+static int     match_string(const char *a, const char *b);
 
 
 /*
@@ -146,6 +153,8 @@ main(int  argc,                             /* I - Number of command-line arguments */
       do_delete_printer(http, language);
     else if (!strcmp(op, "config-printer"))
       do_config_printer(http, language);
+    else if (!strcmp(op, "config-server"))
+      do_config_server(http, language);
     else
     {
      /*
@@ -190,6 +199,18 @@ main(int  argc,                            /* I - Number of command-line arguments */
 }
 
 
+/*
+ * 'compare_printer_devices()' - Compare two printer devices.
+ */
+
+static int                             /* O - Result of comparison */
+compare_printer_devices(const void *a, /* I - First device */
+                        const void *b) /* I - Second device */
+{
+  return (strcmp(*((char **)a), *((char **)b)));
+}
+
+
 /*
  * 'do_am_class()' - Add or modify a class.
  */
@@ -498,7 +519,6 @@ do_am_printer(http_t      *http,    /* I - HTTP connection */
                *uriptr;                /* Pointer into URI */
   int          maxrate;                /* Maximum baud rate */
   char         baudrate[255];          /* Baud rate string */
-  char         make[255];              /* Make string */
   const char   *name,                  /* Pointer to class name */
                *ptr;                   /* Pointer to CGI variable */
   static int   baudrates[] =           /* Baud rates */
@@ -695,11 +715,11 @@ do_am_printer(http_t      *http,  /* I - HTTP connection */
       * Get the PPD file...
       */
 
-      int              fd;                     /* PPD file */
-      char             filename[1024];         /* PPD filename */
-      ppd_file_t       *ppd;                   /* PPD information */
-      char             buffer[1024];           /* Buffer */
-      int              bytes;                  /* Number of bytes */
+      int              fd;             /* PPD file */
+      char             filename[1024]; /* PPD filename */
+      ppd_file_t       *ppd;           /* PPD information */
+      char             buffer[1024];   /* Buffer */
+      int              bytes;          /* Number of bytes */
 
 
       snprintf(uri, sizeof(uri), "/printers/%s.ppd", name);
@@ -731,6 +751,39 @@ do_am_printer(http_t      *http,   /* I - HTTP connection */
       else
         httpFlush(http);
     }
+    else if ((uriptr = strrchr(cgiGetVariable("DEVICE_URI"), ';')) != NULL)
+    {
+     /*
+      * Extract make and make/model from device URI string...
+      */
+
+      char     make[1024],             /* Make string */
+               *makeptr;               /* Pointer into make */
+
+
+      *uriptr++ = '\0';
+
+      strlcpy(make, uriptr, sizeof(make));
+
+      if ((makeptr = strchr(make, ' ')) != NULL)
+        *makeptr = '\0';
+      else if ((makeptr = strchr(make, '-')) != NULL)
+        *makeptr = '\0';
+      else if (!strncasecmp(make, "laserjet", 8) ||
+               !strncasecmp(make, "deskjet", 7) ||
+               !strncasecmp(make, "designjet", 9))
+        strcpy(make, "HP");
+      else if (!strncasecmp(make, "phaser", 6))
+        strcpy(make, "Xerox");
+      else if (!strncasecmp(make, "stylus", 6))
+        strcpy(make, "Epson");
+      else
+        strcpy(make, "Generic");
+
+      cgiSetVariable("CURRENT_MAKE", make);
+      cgiSetVariable("PPD_MAKE", make);
+      cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr);
+    }
 
    /*
     * Build a CUPS_GET_PPDS request, which requires the following
@@ -761,7 +814,22 @@ do_am_printer(http_t      *http,   /* I - HTTP connection */
 
     if ((response = cupsDoRequest(http, request, "/")) != NULL)
     {
-      if ((var = cgiGetVariable("PPD_MAKE")) == NULL)
+     /*
+      * Got the list of PPDs, see if the user has selected a make...
+      */
+
+      if ((var = cgiGetVariable("PPD_MAKE")) != NULL)
+      {
+       /*
+        * Yes, copy those attributes, but check if the make doesn't
+       * exist...
+       */
+
+        if (ippSetCGIVars(response, "ppd-make", var, NULL, 0) <= 0)
+         var = NULL;
+      }
+
+      if (var == NULL)
       {
        /*
        * Let the user choose a make...
@@ -789,13 +857,51 @@ do_am_printer(http_t      *http,  /* I - HTTP connection */
        * Let the user choose a model...
        */
 
-        strlcpy(make, var, sizeof(make));
+        const char     *make_model;    /* Current make/model string */
+
+
+        if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL)
+       {
+        /*
+         * Scan for "close" matches...
+         */
+
+          int          match,          /* Current match */
+                       best_match,     /* Best match so far */
+                       count;          /* Number of drivers */
+         const char    *best,          /* Best matching string */
+                       *current;       /* Current string */
+
+
+          count = cgiGetSize("PPD_MAKE_AND_MODEL");
+
+         for (i = 0, best_match = 0, best = NULL; i < count; i ++)
+         {
+           current = cgiGetArray("PPD_MAKE_AND_MODEL", i);
+           match   = match_string(make_model, current);
+
+           if (match > best_match)
+           {
+             best_match = match;
+             best       = current;
+           }
+         }
+
+          if (best_match > strlen(var))
+         {
+          /*
+           * Found a match longer than the make...
+           */
+
+            cgiSetVariable("CURRENT_MAKE_AND_MODEL", best);
+         }
+       }
 
-        ippSetCGIVars(response, "ppd-make", make, NULL, 0);
        cgiCopyTemplateLang(stdout, TEMPLATES, "choose-model.tmpl",
                            getenv("LANG"));
       }
 
+      
       ippDelete(response);
     }
     else
@@ -1332,6 +1438,253 @@ do_config_printer(http_t      *http,    /* I - HTTP connection */
 }
 
 
+/*
+ * 'do_config_server()' - Configure server settings.
+ */
+
+static void
+do_config_server(http_t      *http,    /* I - HTTP connection */
+                 cups_lang_t *language)        /* I - Client's language */
+{
+  cups_file_t  *cupsd;                 /* cupsd.conf file */
+  char         tempfile[1024];         /* Temporary new cupsd.conf */
+  int          tempfd;                 /* Temporary file descriptor */
+  cups_file_t  *temp;                  /* Temporary file */
+  char         line[1024],             /* Line from cupsd.conf file */
+               *value;                 /* Value on line */
+  const char   *server_root;           /* Location of config files */
+  const char   *val;                   /* CGI form variable value */
+  int          linenum,                /* Line number in file */
+               in_policy,              /* In a policy section? */
+               in_cancel_job,          /* In a cancel-job section? */
+               in_admin_location;      /* In the /admin location? */
+  int          remote_printers,        /* Show remote printers */
+               share_printers,         /* Share local printers */
+               remote_admin,           /* Remote administration allowed? */
+               user_cancel_any,        /* Cancel-job policy set? */
+               debug_logging;          /* LogLevel debug set? */
+  int          wrote_port_listen,      /* Wrote the port/listen lines? */
+               wrote_browsing,         /* Wrote the browsing lines? */
+               wrote_browse_address,   /* Wrote the BrowseAddress lines? */
+               wrote_policy,           /* Wrote the policy? */
+               wrote_admin_location;   /* Wrote the /admin location? */
+
+
+ /*
+  * Get form variables...
+  */
+
+  remote_printers = cgiGetVariable("REMOTE_PRINTERS") != NULL;
+  share_printers  = cgiGetVariable("SHARE_PRINTERS") != NULL;
+  remote_admin    = cgiGetVariable("REMOTE_ADMIN") != NULL;
+  user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") != NULL;
+  debug_logging   = cgiGetVariable("DEBUG_LOGGING") != NULL;
+
+ /*
+  * Locate the cupsd.conf file...
+  */
+
+  if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
+    server_root = CUPS_SERVERROOT;
+
+  snprintf(line, sizeof(line), "%s/cupsd.conf", server_root);
+
+  printf("<!-- \"%s\" -->\n", line);
+
+ /*
+  * Open the cupsd.conf file...
+  */
+
+  if ((cupsd = cupsFileOpen(line, "r")) == NULL)
+  {
+   /*
+    * Unable to open - log an error...
+    */
+
+    perror(line);
+    return;
+  }
+
+ /*
+  * Create a temporary file for the new cupsd.conf file...
+  */
+
+  if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
+  {
+    perror(tempfile);
+    cupsFileClose(cupsd);
+    return;
+  }
+
+  if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL)
+  {
+    perror(tempfile);
+    close(tempfd);
+    unlink(tempfile);
+    cupsFileClose(cupsd);
+    return;
+  }
+
+  printf("<!-- tempfile=\"%s\" -->\n", tempfile);
+
+ /*
+  * Copy the old file to the new, making changes along the way...
+  */
+
+  in_admin_location    = 0;
+  in_cancel_job        = 0;
+  in_policy            = 0;
+  linenum              = 0;
+  wrote_admin_location = 0;
+  wrote_browsing       = 0;
+  wrote_browse_address = 0;
+  wrote_policy         = 0;
+  wrote_port_listen    = 0;
+
+  while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
+  {
+    if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen"))
+    {
+      if (!wrote_port_listen)
+      {
+        wrote_port_listen = 1;
+
+       if (share_printers || remote_admin)
+       {
+         cupsFilePuts(temp, "# Allow remote access\n");
+         cupsFilePrintf(temp, "Port %d\n", ippPort());
+       }
+       else
+       {
+         cupsFilePuts(temp, "# Only listen for connections from the local machine.\n");
+         cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort());
+       }
+      }
+    }
+    else if (!strcasecmp(line, "Browsing") ||
+             !strcasecmp(line, "BrowseAddress") ||
+             !strcasecmp(line, "BrowseAllow") ||
+             !strcasecmp(line, "BrowseDeny") ||
+             !strcasecmp(line, "BrowseOrder"))
+    {
+      if (!wrote_browsing)
+      {
+        wrote_browsing = 1;
+
+        if (remote_printers || share_printers)
+       {
+         if (remote_printers && share_printers)
+           cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n");
+         else if (remote_printers)
+           cupsFilePuts(temp, "# Show shared printers on the local network.\n");
+         else
+           cupsFilePuts(temp, "# Share local printers on the local network.\n");
+
+         cupsFilePuts(temp, "Browsing On\n");
+         cupsFilePuts(temp, "BrowseOrder allow,deny\n");
+
+         if (remote_printers)
+           cupsFilePuts(temp, "BrowseAllow @LOCAL\n");
+         
+         if (share_printers)
+           cupsFilePuts(temp, "BrowseAddress @LOCAL\n");
+        }
+       else
+       {
+         cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n");
+         cupsFilePuts(temp, "Browsing Off\n");
+       }
+      }
+    }
+    else if (!strcasecmp(line, "LogLevel"))
+    {
+      if (debug_logging)
+      {
+        cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n");
+       cupsFilePuts(temp, "LogLevel debug\n");
+      }
+      else
+      {
+        cupsFilePuts(temp, "# Show general information in error_log.\n");
+       cupsFilePuts(temp, "LogLevel info\n");
+      }
+    }
+    else if (line[0] == '<' && value)
+      cupsFilePrintf(temp, "%s %s>\n", line, value);
+    else if (value)
+      cupsFilePrintf(temp, "%s %s\n", line, value);
+    else
+      cupsFilePrintf(temp, "%s\n", line);
+#if 0
+    else if (!strcasecmp(line, "Policy") && !strcasecmp(value, "default"))
+    {
+      in_policy = 1;
+    }
+    else if (!strcasecmp(line, "</Policy>"))
+    {
+      in_policy = 0;
+    }
+    else if (!strcasecmp(line, "<Limit") && in_policy)
+    {
+     /*
+      * See if the policy limit is for the Cancel-Job operation...
+      */
+
+      char     *valptr;                /* Pointer into value */
+
+
+      while (*value)
+      {
+       for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++);
+
+       if (*valptr)
+         *valptr++ = '\0';
+
+        if (!strcasecmp(value, "cancel-job"))
+       {
+         in_cancel_job = 1;
+         break;
+       }
+
+        for (value = valptr; isspace(*value & 255); value ++);
+      }
+    }
+    else if (!strcasecmp(line, "</Limit>"))
+    {
+      in_cancel_job = 0;
+    }
+    else if (!strcasecmp(line, "Order") && in_cancel_job)
+    {
+     /*
+      * See if we are allowing all users to cancel jobs...
+      */
+
+      if (!strcasecmp(value, "deny,allow"))
+       cancel_policy = 1;
+    }
+    else if (!strcasecmp(line, "<Location") && !strcasecmp(value, "/admin"))
+    {
+      in_admin_location = 1;
+    }
+    else if (!strcasecmp(line, "</Location>"))
+    {
+      in_admin_location = 0;
+    }
+    else if (!strcasecmp(line, "Allow") && in_admin_location &&
+             strcasecmp(value, "localhost") && strcasecmp(value, "127.0.0.1"))
+    {
+      remote_admin = 1;
+    }
+#endif /* 0 */
+  }
+
+  cupsFileClose(cupsd);
+  cupsFileClose(temp);
+
+  puts("<p>Boo!</p>");
+}
+
+
 /*
  * 'do_delete_class()' - Delete a class...
  */
@@ -1496,6 +1849,9 @@ do_menu(http_t      *http,                /* I - HTTP connection */
   char         line[1024],             /* Line from cupsd.conf file */
                *value;                 /* Value on line */
   const char   *server_root;           /* Location of config files */
+  ipp_t                *request,               /* IPP request */
+               *response;              /* IPP response */
+  ipp_attribute_t *attr;               /* IPP attribute */
 
 
  /*
@@ -1531,10 +1887,12 @@ do_menu(http_t      *http,              /* I - HTTP connection */
                remote_admin = 0,       /* Remote administration allowed? */
                browsing = 1,           /* Browsing enabled? */
                browse_address = 0,     /* Browse address set? */
-               cancel_policy = 0;      /* Cancel-job policy set? */
+               cancel_policy = 0,      /* Cancel-job policy set? */
+               debug_logging = 0;      /* LogLevel debug set? */
     int                linenum = 0,            /* Line number in file */
                in_policy = 0,          /* In a policy section? */
-               in_cancel_job = 0;      /* In a cancel-job section? */
+               in_cancel_job = 0,      /* In a cancel-job section? */
+               in_admin_location = 0;  /* In the /admin location? */
 
 
     while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum))
@@ -1556,25 +1914,26 @@ do_menu(http_t      *http,              /* I - HTTP connection */
       }
       else if (!strcasecmp(line, "Browsing"))
       {
-        if (!strcasecmp(value, "yes") || !strcasecmp(value, "on") ||
-           !strcasecmp(value, "true"))
-         browsing = 1;
-        else
-         browsing = 0;
+        browsing = !strcasecmp(value, "yes") || !strcasecmp(value, "on") ||
+                  !strcasecmp(value, "true");
       }
       else if (!strcasecmp(line, "BrowseAddress"))
       {
         browse_address = 1;
       }
-      else if (!strcasecmp(line, "Policy"))
+      else if (!strcasecmp(line, "LogLevel"))
+      {
+        debug_logging = !strncasecmp(value, "debug", 5);
+      }
+      else if (!strcasecmp(line, "Policy") && !strcasecmp(value, "default"))
       {
         in_policy = 1;
       }
-      else if (!strcasecmp(line, "/Policy"))
+      else if (!strcasecmp(line, "</Policy>"))
       {
         in_policy = 0;
       }
-      else if (!strcasecmp(line, "Limit") && in_policy)
+      else if (!strcasecmp(line, "<Limit") && in_policy)
       {
        /*
         * See if the policy limit is for the Cancel-Job operation...
@@ -1599,19 +1958,32 @@ do_menu(http_t      *http,              /* I - HTTP connection */
           for (value = valptr; isspace(*value & 255); value ++);
         }
       }
-      else if (!strcasecmp(line, "/Limit"))
+      else if (!strcasecmp(line, "</Limit>"))
       {
         in_cancel_job = 0;
       }
-      else if (!strcasecmp(line, "Allow") && in_cancel_job)
+      else if (!strcasecmp(line, "Order") && in_cancel_job)
       {
        /*
         * See if we are allowing all users to cancel jobs...
        */
 
-        if (!strcasecmp(value, "@ALL"))
+        if (!strcasecmp(value, "deny,allow"))
          cancel_policy = 1;
       }
+      else if (!strcasecmp(line, "<Location") && !strcasecmp(value, "/admin"))
+      {
+        in_admin_location = 1;
+      }
+      else if (!strcasecmp(line, "</Location>"))
+      {
+        in_admin_location = 0;
+      }
+      else if (!strcasecmp(line, "Allow") && in_admin_location &&
+               strcasecmp(value, "localhost") && strcasecmp(value, "127.0.0.1"))
+      {
+        remote_admin = 1;
+      }
     }
 
     cupsFileClose(cupsd);
@@ -1628,10 +2000,233 @@ do_menu(http_t      *http,             /* I - HTTP connection */
     if (cancel_policy)
       cgiSetVariable("USER_CANCEL_ANY", "CHECKED");
 
-    printf("<!-- browsing=%d, browse_address=%d, cancel_policy=%d, remote_access=%d, remote_admin=%d -->\n",
-           browsing, browse_address, cancel_policy, remote_access, remote_admin);
+    if (debug_logging)
+      cgiSetVariable("DEBUG_LOGGING", "CHECKED");
+
+    printf("<!-- browsing=%d, browse_address=%d, cancel_policy=%d, debug_logging=%d, remote_access=%d, remote_admin=%d -->\n",
+           browsing, browse_address, cancel_policy, debug_logging, remote_access, remote_admin);
   }
 
+ /*
+  * Get the list of printers and their devices...
+  */
+
+  request = ippNew();
+  request->request.op.operation_id = CUPS_GET_PRINTERS;
+  request->request.op.request_id   = 1;
+
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+               "attributes-charset", NULL, cupsLangEncoding(language));
+
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+               "attributes-natural-language", NULL, language->language);
+
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+               "requested-attributes", NULL, "device-uri");
+
+  ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type",
+                CUPS_PRINTER_LOCAL);
+  ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask",
+                CUPS_PRINTER_LOCAL);
+
+  if ((response = cupsDoRequest(http, request, "/")) != NULL)
+  {
+   /*
+    * Got the printer list, now load the devices...
+    */
+
+    int                i;                      /* Looping var */
+    int                num_printer_devices;    /* Number of devices for local printers */
+    char       **printer_devices;      /* Printer devices for local printers */
+
+
+   /*
+    * Count the number of printers we have...
+    */
+
+    for (num_printer_devices = 0,
+             attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
+         attr;
+        num_printer_devices ++,
+            attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI));
+
+    if (num_printer_devices > 0)
+    {
+     /*
+      * Allocate an array and copy the device strings...
+      */
+
+      printer_devices = calloc(num_printer_devices, sizeof(char *));
+
+      for (i = 0, attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI);
+           attr;
+          i ++,  attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI))
+      {
+       printer_devices[i] = strdup(attr->values[0].string.text);
+      }
+
+     /*
+      * Sort the printer devices as needed...
+      */
+
+      if (num_printer_devices > 1)
+        qsort(printer_devices, num_printer_devices, sizeof(char *),
+             compare_printer_devices);
+    }
+
+   /*
+    * Free the printer list and get the device list...
+    */
+
+    ippDelete(response);
+
+    request = ippNew();
+    request->request.op.operation_id = CUPS_GET_DEVICES;
+    request->request.op.request_id   = 1;
+
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+                "attributes-charset", NULL, cupsLangEncoding(language));
+
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+                "attributes-natural-language", NULL, language->language);
+
+    if ((response = cupsDoRequest(http, request, "/")) != NULL)
+    {
+     /*
+      * Got the device list, let's parse it...
+      */
+
+      const char *device_uri,          /* device-uri attribute value */
+               *device_make_and_model, /* device-make-and-model value */
+               *device_info;           /* device-info value */
+
+
+      for (i = 0, attr = response->attrs; attr; attr = attr->next)
+      {
+       /*
+        * Skip leading attributes until we hit a device...
+       */
+
+       while (attr && attr->group_tag != IPP_TAG_PRINTER)
+          attr = attr->next;
+
+       if (!attr)
+          break;
+
+       /*
+       * Pull the needed attributes from this device...
+       */
+
+       device_info           = NULL;
+       device_make_and_model = NULL;
+       device_uri            = NULL;
+
+       while (attr && attr->group_tag == IPP_TAG_PRINTER)
+       {
+          if (strcmp(attr->name, "device-info") == 0 &&
+             attr->value_tag == IPP_TAG_TEXT)
+           device_info = attr->values[0].string.text;
+
+          if (strcmp(attr->name, "device-make-and-model") == 0 &&
+             attr->value_tag == IPP_TAG_TEXT)
+           device_make_and_model = attr->values[0].string.text;
+
+          if (strcmp(attr->name, "device-uri") == 0 &&
+             attr->value_tag == IPP_TAG_URI)
+           device_uri = attr->values[0].string.text;
+
+          attr = attr->next;
+       }
+
+       /*
+       * See if we have everything needed...
+       */
+
+       if (device_info && device_make_and_model && device_uri &&
+           strcasecmp(device_make_and_model, "unknown") &&
+           strchr(device_uri, ':'))
+       {
+        /*
+         * Yes, now see if there is already a printer for this
+         * device...
+         */
+
+          if (!bsearch(&device_uri, printer_devices, num_printer_devices,
+                      sizeof(char *), compare_printer_devices))
+          {
+          /*
+           * Not found, so it must be a new printer...
+           */
+
+            char       options[1024],  /* Form variables for this device */
+                       *options_ptr;   /* Pointer into string */
+           const char  *ptr;           /* Pointer into device string */
+
+
+           /*
+           * Format the printer name variable for this device...
+           *
+           * TODO: check for existing names, add number/address...
+           */
+
+           strcpy(options, "PRINTER_NAME=");
+           options_ptr = options + strlen(options);
+
+           for (ptr = device_make_and_model;
+                options_ptr < (options + sizeof(options) - 1) && *ptr;
+                ptr ++)
+             if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-')
+               *options_ptr++ = *ptr;
+             else if (*ptr == ' ')
+               *options_ptr++ = '_';
+           /*
+           * Then copy the device URI...
+           */
+
+            strlcpy(options_ptr, "&PRINTER_LOCATION=&PRINTER_INFO=&DEVICE_URI=",
+                   sizeof(options) - (options_ptr - options));
+           options_ptr += strlen(options_ptr);
+
+            form_encode(options_ptr, device_uri,
+                       sizeof(options) - (options_ptr - options));
+           options_ptr += strlen(options_ptr);
+
+            if (options_ptr < (options + sizeof(options) - 1))
+           {
+             *options_ptr++ = ';';
+             form_encode(options_ptr, device_make_and_model,
+                         sizeof(options) - (options_ptr - options));
+           }
+
+           /*
+           * Finally, set the form variables for this printer...
+           */
+
+           cgiSetArray("device_info", i, device_info);
+           cgiSetArray("device_make_and_model", i, device_make_and_model);
+           cgiSetArray("device_options", i, options);
+            cgiSetArray("device_uri", i, device_uri);
+           i ++;
+         }
+       }
+
+        if (!attr)
+         break;
+      }
+
+     /*
+      * Free the device list...
+      */
+
+      ippDelete(response);
+    }
+  }
+
+ /*
+  * Finally, show the main menu template...
+  */
+
   cgiCopyTemplateLang(stdout, TEMPLATES, "admin.tmpl", getenv("LANG"));
 }
 
@@ -1969,6 +2564,77 @@ do_set_allowed_users(
 }
 
 
+/*
+ * 'form_encode()' - Encode a string as a form variable...
+ */
+
+static void
+form_encode(char       *dst,           /* I - Destination string */
+            const char *src,           /* I - Source string */
+           size_t     dstsize)         /* I - Size of destination string */
+{
+  char                 *dstend;        /* End of destination */
+  static const char    *hex =          /* Hexadecimal characters */
+                       "0123456789ABCDEF";
+
+
+ /*
+  * Mark the end of the string...
+  */
+
+  dstend = dst + dstsize - 1;
+
+ /*
+  * Loop through the source string and copy...
+  */
+
+  while (*src && dst < dstend)
+  {
+    switch (*src)
+    { 
+      case ' ' :
+         /*
+         * Encode spaces with a "+"...
+         */
+
+          *dst++ = '+';
+         src ++;
+         break;
+
+      case '&' :
+      case '%' :
+      case '+' :
+         /*
+         * Encode special characters with %XX escape...
+         */
+
+          if (dst < (dstend - 2))
+         {
+           *dst++ = '%';
+           *dst++ = hex[(*src & 255) >> 4];
+           *dst++ = hex[*src & 15];
+           src ++;
+         }
+          break;
+
+      default :
+         /*
+         * Copy other characters literally...
+         */
+
+          *dst++ = *src++;
+         break;
+    }
+  }
+
+ /*
+  * Nul-terminate the destination string...
+  */
+
+  *dst = '\0';
+}
+
+
 /*
  * 'get_line()' - Get a line that is terminated by a LF, CR, or CR LF.
  */
@@ -2017,6 +2683,55 @@ get_line(char *buf,                      /* I - Line buffer */
 }
 
 
+/*
+ * 'match_string()' - Return the number of matching characters.
+ */
+
+static int                             /* O - Number of matching characters */
+match_string(const char *a,            /* I - First string */
+             const char *b)            /* I - Second string */
+{
+  int  count;                          /* Number of matching characters */
+
+
+ /*
+  * Loop through both strings until we hit the end of either or we find
+  * a non-matching character.  For the purposes of comparison, we ignore
+  * whitespace and do a case-insensitive comparison so that we have a
+  * better chance of finding a match...
+  */
+
+  for (count = 0; *a && *b; a++, b++, count ++)
+  {
+   /*
+    * Skip leading whitespace characters...
+    */
+
+    while (isspace(*a & 255))
+      a ++;
+
+    while (isspace(*b & 255))
+      b ++;
+
+   /*
+    * Break out if we run out of characters...
+    */
+
+    if (!*a || !*b)
+      break;
+
+   /*
+    * Do a case-insensitive comparison of the next two chars...
+    */
+
+    if (tolower(*a & 255) != tolower(*b & 255))
+      break;
+  }
+
+  return (count);
+}
+
+    
 /*
  * End of "$Id$".
  */
index a64c6eaf662847592c755c68273feaffb38a3e55..95d2105b55287b6b49eee049c748977ffb56cb29 100644 (file)
@@ -339,7 +339,7 @@ ippSetServerVersion(void)
  * 'ippSetCGIVars()' - Set CGI variables from an IPP response.
  */
 
-void
+int                                    /* O - Maximum number of elements */
 ippSetCGIVars(ipp_t      *response,    /* I - Response data to be copied... */
               const char *filter_name, /* I - Filter name */
              const char *filter_value, /* I - Filter value */
@@ -397,7 +397,7 @@ ippSetCGIVars(ipp_t      *response, /* I - Response data to be copied... */
          break;
 
       if (!filter)
-        return;
+        return (element + 1);
 
       if (filter->group_tag == IPP_TAG_ZERO)
       {
@@ -567,6 +567,8 @@ ippSetCGIVars(ipp_t      *response, /* I - Response data to be copied... */
   }
 
   DEBUG_puts("<P>Leaving ippSetCGIVars()...");
+
+  return (element + 1);
 }
 
 
index b1d6e29f6d94d3e197396fe01fcc40571d6c8df8..f57b0442aab9237e55e39116285c9d03b9700bc4 100644 (file)
@@ -49,7 +49,7 @@ extern void   ippGetAttributes(ipp_t *request, const char *directory,
 extern char    *ippGetTemplateDir(void);
 extern char    *ippRewriteURL(const char *, char *, int, const char *);
 extern void    ippSetServerVersion(void);
-extern void    ippSetCGIVars(ipp_t *, const char *, const char *,
+extern int     ippSetCGIVars(ipp_t *, const char *, const char *,
                              const char *, int);
 
 
index 1aaf5c8906af55b21c2fe504a44344b708671c00..a9d972c89779080c8c7ed5362c071271887232bf 100644 (file)
@@ -6,6 +6,11 @@
 #   file.
 #
 
+# Log general information in error_log - change "info" to "debug" for
+# troubleshooting...
+LogLevel info
+
+
 # Only listen for connections from the local machine.
 Listen 127.0.0.1:@DEFAULT_IPP_PORT@
 @CUPS_LISTEN_DOMAINSOCKET@
index 9285a5b5eeccefce1f27d016062469ab258d3a2d..7d8f7254e13246612aadc94cd3f743c6537329ed 100644 (file)
@@ -1,4 +1,53 @@
-H1 { font-family: sans-serif }
-H2 { font-family: sans-serif }
-TH { text-align: left }
+BODY {
+  background: #cccc99;
+  color: #000000;
+  font-family: sans-serif;
+}
 
+H1, H2, H3, H4, H5, H6, P {
+  font-family: sans-serif;
+}
+
+TD, TH {
+  font-family: sans-serif;
+  text-align: left
+}
+
+KBD {
+  color: #006600;
+  font-family: monospace;
+  font-weight: bold;
+}
+
+PRE {
+  color: #7f0000;
+  font-family: monospace;
+}
+
+PRE.command {
+  margin-left: 3em;
+}
+
+A:link, A:visited {
+  text-decoration: none;
+  font-weight: bold;
+  color: #993300;
+}
+
+A:link:hover, A:visited:hover, A:active {
+  text-decoration: underline;
+  font-weight: bold;
+  color: #bb5500;
+}
+
+INPUT[TYPE="TEXT"], TEXTAREA {
+  font-family: monospace;
+}
+
+LI {
+  margin-bottom: 1em;
+}
+
+SUB, SUP {
+  font-size: 50%;
+}
index e2608ced801e941efc170f5df99e35135e780fb0..325043accb66288c1d4d1574e77cf6a71bc504ee 100644 (file)
@@ -682,7 +682,7 @@ ReadConfiguration(void)
       {
         snprintf(groupname, sizeof(groupname), "@%s", SystemGroups[i]);
        AddPolicyOpName(po, POLICY_ALLOW, groupname);
-       LogMessage(L_INFO, "Allow %s", groupname);
+       LogMessage(L_INFO, "Allow @%s", groupname);
       }
 
       AddPolicyOp(p, po, IPP_SEND_URI);
@@ -725,7 +725,7 @@ ReadConfiguration(void)
       {
         snprintf(groupname, sizeof(groupname), "@%s", SystemGroups[i]);
        AddPolicyOpName(po, POLICY_ALLOW, groupname);
-       LogMessage(L_INFO, "Allow %s", groupname);
+       LogMessage(L_INFO, "Allow @%s", groupname);
       }
 
       AddPolicyOp(p, po, IPP_RESUME_PRINTER);
index 5c1839646006b8a542c2f165133d5a20a40e7b3e..a5cf374941df50ed98c391fead704cb89b1a8c49 100644 (file)
@@ -523,8 +523,6 @@ check_op(policyop_t *po,            /* I - Policy operation */
       if (owner && !strcasecmp(name, owner))
         return (1);
     }
-    else if (!strcasecmp(pn->name, "@ALL"))
-      return (1);
     else if (pn->name[0] == '@')
     {
       if (check_group(name, pn->name + 1))
index e197294fccf71e103c13fe1cb82965ce0a7a3e50..effd4a8b258826d0a620a59a505dfd6e147c8e8d 100644 (file)
        <IMG SRC="/images/add-printer.gif" ALT="Add Printer" BORDER="0"></A>
        <A HREF="/printers/">
        <IMG SRC="/images/manage-printers.gif" ALT="Manage Printers" BORDER="0"></A>
-       {#device_uri=0?:{[device_uri]
-       <p>{device_make_and_model} ({device_info})
-       <A HREF="/admin/?op=add-printer&amp;{device_options}">
-       <IMG SRC="/images/add-printer.gif" ALT="Add Printer" BORDER="0"></A></P>
-       }}</TD>
+       {#device_uri=0?:<P><B>New Printers Found:</B></P><UL>{[device_uri]
+       <LI>{device_make_and_model} ({device_info})
+       <A HREF="/admin/?op=add-printer&amp;{device_options}"><IMG
+       SRC="/images/add-printer.gif" ALT="Add Printer" BORDER="0"
+       ALIGN="MIDDLE"></A></LI>
+       }</UL>}</TD>
 </TR>
 <TR>
        <TD>&nbsp;</TD>
 </TR>
 <TR>
        <TH BGCOLOR="#999966"><IMG SRC="/images/left.gif" ALT=""></TH>
-       <TH BGCOLOR="#999966">Server Settings</TH>
+       <TH BGCOLOR="#999966">Server</TH>
        <TH WIDTH="16"><IMG SRC="/images/right.gif" ALT=""></TH>
 </TR>
 <TR>
 </TR>
 <TR>
        <TD></TD>
-       <TD><FORM METHOD="POST" ACTION="/admin">
-       <INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
-       <INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Show printers shared by other systems<br />
-       <INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Share printers connected to this system<br />
-       <INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Allow remote administration<br />
-       <INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Allow users to cancel any job (not just their own)<br />
-       <INPUT TYPE="IMAGE" SRC="/images/change-settings.gif" ALT="Change Settings" BORDER="0">
+       <TD><FORM METHOD="POST" ACTION="/admin"><P><B>Basic Server Settings:</B><P>
+       <P><INPUT TYPE="HIDDEN" NAME="OP" VALUE="config-server">
+       <INPUT TYPE="CHECKBOX" NAME="REMOTE_PRINTERS" {?remote_printers}> Show printers shared by other systems<BR>
+       <INPUT TYPE="CHECKBOX" NAME="SHARE_PRINTERS" {?share_printers}> Share printers connected to this system<BR>
+       <INPUT TYPE="CHECKBOX" NAME="REMOTE_ADMIN" {?remote_admin}> Allow remote administration<BR>
+       <INPUT TYPE="CHECKBOX" NAME="USER_CANCEL_ANY" {?user_cancel_any}> Allow users to cancel any job (not just their own)<BR>
+       <INPUT TYPE="CHECKBOX" NAME="DEBUG_LOGGING" {?debug_logging}> Save debugging information for troubleshooting</P>
+       <P><INPUT TYPE="IMAGE" SRC="/images/change-settings.gif" ALT="Change Settings" BORDER="0"></P>
        </FORM></TD>
 </TR>
 <TR>
index f6481091005b00d267cb52cf2af3b265082e1691..45011392b1ec082f8f5ef3c990b88f80d0effc56 100644 (file)
@@ -18,7 +18,7 @@
        <TD ALIGN="RIGHT">Device:&nbsp;</TD>
        <TD>
        <SELECT NAME="DEVICE_URI">
-       {[device_uri]<OPTION VALUE="{device_uri}" {?current_device_uri={device_uri}?SELECTED:}>
+       {[device_uri]<OPTION VALUE="{device_uri}{?device_make_and_model!Unknown?;{device_make_and_model}:}" {?current_device_uri={device_uri}?SELECTED:}>
        {device_info} {?device_make_and_model!Unknown?({device_make_and_model}):}
        }</SELECT>
        </TD>
index a573838782085e21389876722c59abe150b5e5ab..4e40d9b0b2b22879a1b7e238f9edc18f63d069c2 100644 (file)
@@ -17,7 +17,7 @@
                <AREA SHAPE="RECT" COORDS="496,0,568,30" HREF="http://www.cups.org" ALT="Download the Current CUPS Software">
        </MAP>
 </HEAD>
-<BODY BGCOLOR="#cccc99" TEXT="#000000" LINK="#0000FF" VLINK="#FF00FF">
+<BODY>
 <CENTER>
 <IMG SRC="/images/navbar.gif" WIDTH="583" HEIGHT="30" USEMAP="#navbar" BORDER="0" ALT="Common UNIX Printing System">
 </CENTER>