]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cgi-bin/ipp-var.c
Update svn:keyword properties.
[thirdparty/cups.git] / cgi-bin / ipp-var.c
index 4639643de475c4f9c393427dd70262600e196821..38120da080168c98d85fb4cdf0200ad6f218fd3d 100644 (file)
@@ -1,32 +1,24 @@
 /*
- * "$Id: ipp-var.c 6244 2007-02-06 21:08:59Z mike $"
+ * "$Id$"
  *
- *   CGI <-> IPP variable routines for the Common UNIX Printing System (CUPS).
+ *   CGI <-> IPP variable routines for CUPS.
  *
- *   Copyright 1997-2006 by Easy Software Products.
+ *   Copyright 2007-2012 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  * Contents:
  *
- *   cgiGetAttributes()    - Get the list of attributes that are needed
- *                           by the template file.
+ *   cgiGetAttributes()    - Get the list of attributes that are needed by the
+ *                           template file.
  *   cgiGetIPPObjects()    - Get the objects in an IPP response.
  *   cgiMoveJobs()         - Move one or more jobs.
+ *   cgiPrintCommand()     - Print a CUPS command job.
  *   cgiPrintTestPage()    - Print a test page.
  *   cgiRewriteURL()       - Rewrite a printer URI into a web browser URL...
  *   cgiSetIPPObjectVars() - Set CGI variables from an IPP object.
@@ -122,7 +114,7 @@ cgiGetAttributes(ipp_t      *request,       /* I - IPP request */
       */
 
       for (nameptr = name; (ch = getc(in)) != EOF;)
-        if (strchr("}]<>=! \t\n", ch))
+        if (strchr("}]<>=!~ \t\n", ch))
           break;
         else if (nameptr > name && ch == '?')
          break;
@@ -137,7 +129,7 @@ cgiGetAttributes(ipp_t      *request,       /* I - IPP request */
       *nameptr = '\0';
 
       if (!strncmp(name, "printer_state_history", 21))
-        strcpy(name, "printer_state_history");
+        strlcpy(name, "printer_state_history", sizeof(name));
 
      /*
       * Possibly add it to the list of attributes...
@@ -167,6 +159,8 @@ cgiGetAttributes(ipp_t      *request,       /* I - IPP request */
     for (i = 0; i < num_attrs; i ++)
       free(attrs[i]);
   }
+
+  fclose(in);
 }
 
 
@@ -291,11 +285,14 @@ cgiMoveJobs(http_t     *http,             /* I - Connection to server */
 
 
  /*
-  * See who is logged in...
+  * Make sure we have a username...
   */
 
   if ((user = getenv("REMOTE_USER")) == NULL)
-    user = "guest";
+  {
+    puts("Status: 401\n");
+    exit(0);
+  }
 
  /*
   * See if the user has already selected a new destination...
@@ -340,7 +337,7 @@ cgiMoveJobs(http_t     *http,               /* I - Connection to server */
                    NULL, job_uri);
       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                    "requested-attributes", NULL, "job-printer-uri");
-      
+
       if ((response = cupsDoRequest(http, request, "/")) != NULL)
       {
         if ((attr = ippFindAttribute(response, "job-printer-uri",
@@ -365,7 +362,7 @@ cgiMoveJobs(http_t     *http,               /* I - Connection to server */
        */
 
         cgiStartHTML(cgiText(_("Move Job")));
-       cgiShowIPPError(_("Unable to find destination for job!"));
+       cgiShowIPPError(_("Unable to find destination for job"));
        cgiEndHTML();
        return;
       }
@@ -380,8 +377,14 @@ cgiMoveJobs(http_t     *http,              /* I - Connection to server */
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                  "requested-attributes", NULL, "printer-uri-supported");
 
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-                 "requesting-user-name", NULL, user);
+    if (user)
+      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                  "requesting-user-name", NULL, user);
+
+    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_SCANNER);
 
     if ((response = cupsDoRequest(http, request, "/")) != NULL)
     {
@@ -401,7 +404,7 @@ cgiMoveJobs(http_t     *http,               /* I - Connection to server */
         * If the name is not the same as the current destination, add it!
        */
 
-        if (strcasecmp(name, dest))
+        if (_cups_strcasecmp(name, dest))
        {
          cgiSetArray("JOB_PRINTER_URI", i, attr->values[0].string.text);
          cgiSetArray("JOB_PRINTER_NAME", i, name);
@@ -421,7 +424,18 @@ cgiMoveJobs(http_t     *http,              /* I - Connection to server */
     else
       cgiStartHTML(cgiText(_("Move All Jobs")));
 
-    cgiCopyTemplateLang("job-move.tmpl");
+    if (cgiGetSize("JOB_PRINTER_NAME") > 0)
+      cgiCopyTemplateLang("job-move.tmpl");
+    else
+    {
+      if (job_id)
+       cgiSetVariable("MESSAGE", cgiText(_("Unable to move job")));
+      else
+       cgiSetVariable("MESSAGE", cgiText(_("Unable to move jobs")));
+
+      cgiSetVariable("ERROR", cgiText(_("No destinations added.")));
+      cgiCopyTemplateLang("error.tmpl");
+    }
   }
   else
   {
@@ -481,10 +495,19 @@ cgiMoveJobs(http_t     *http,             /* I - Connection to server */
 
     if (cupsLastError() <= IPP_OK_CONFLICT)
     {
-      cgiRewriteURL(job_printer_uri, resource, sizeof(resource), NULL);
-      cgiFormEncode(uri, resource, sizeof(uri));
-      snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
-      cgiSetVariable("refresh_page", refresh);
+      const char *path = strstr(job_printer_uri, "/printers/");
+      if (!path)
+      {
+        path = strstr(job_printer_uri, "/classes/");
+        cgiSetVariable("IS_CLASS", "YES");
+      }
+
+      if (path)
+      {
+        cgiFormEncode(uri, path, sizeof(uri));
+        snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
+       cgiSetVariable("refresh_page", refresh);
+      }
     }
 
     if (job_id)
@@ -510,6 +533,168 @@ cgiMoveJobs(http_t     *http,             /* I - Connection to server */
 }
 
 
+/*
+ * 'cgiPrintCommand()' - Print a CUPS command job.
+ */
+
+void
+cgiPrintCommand(http_t     *http,      /* I - Connection to server */
+                const char *dest,      /* I - Destination printer */
+                const char *command,   /* I - Command to send */
+               const char *title)      /* I - Page/job title */
+{
+  int          job_id;                 /* Command file job */
+  char         uri[HTTP_MAX_URI],      /* Job URI */
+               resource[1024],         /* Printer resource path */
+               refresh[1024],          /* Refresh URL */
+               command_file[1024];     /* Command "file" */
+  http_status_t        status;                 /* Document status */
+  cups_option_t        hold_option;            /* job-hold-until option */
+  const char   *user;                  /* User name */
+  ipp_t                *request,               /* Get-Job-Attributes request */
+               *response;              /* Get-Job-Attributes response */
+  ipp_attribute_t *attr;               /* Current job attribute */
+  static const char * const job_attrs[] =/* Job attributes we want */
+               {
+                 "job-state",
+                 "job-printer-state-message"
+               };
+
+
+ /*
+  * Create the CUPS command file...
+  */
+
+  snprintf(command_file, sizeof(command_file), "#CUPS-COMMAND\n%s\n", command);
+
+ /*
+  * Show status...
+  */
+
+  if (cgiSupportsMultipart())
+  {
+    cgiStartMultipart();
+    cgiStartHTML(title);
+    cgiCopyTemplateLang("command.tmpl");
+    cgiEndHTML();
+    fflush(stdout);
+  }
+
+ /*
+  * Send the command file job...
+  */
+
+  hold_option.name  = "job-hold-until";
+  hold_option.value = "no-hold";
+
+  if ((user = getenv("REMOTE_USER")) != NULL)
+    cupsSetUser(user);
+  else
+    cupsSetUser("anonymous");
+
+  if ((job_id = cupsCreateJob(http, dest, title,
+                             1, &hold_option)) < 1)
+  {
+    cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
+    cgiSetVariable("ERROR", cupsLastErrorString());
+    cgiStartHTML(title);
+    cgiCopyTemplateLang("error.tmpl");
+    cgiEndHTML();
+
+    if (cgiSupportsMultipart())
+      cgiEndMultipart();
+    return;
+  }
+
+  status = cupsStartDocument(http, dest, job_id, NULL, CUPS_FORMAT_COMMAND, 1);
+  if (status == HTTP_CONTINUE)
+    status = cupsWriteRequestData(http, command_file,
+                                 strlen(command_file));
+  if (status == HTTP_CONTINUE)
+    cupsFinishDocument(http, dest);
+
+  if (cupsLastError() >= IPP_REDIRECTION_OTHER_SITE)
+  {
+    cgiSetVariable("MESSAGE", cgiText(_("Unable to send command to printer driver")));
+    cgiSetVariable("ERROR", cupsLastErrorString());
+    cgiStartHTML(title);
+    cgiCopyTemplateLang("error.tmpl");
+    cgiEndHTML();
+
+    if (cgiSupportsMultipart())
+      cgiEndMultipart();
+
+    cupsCancelJob(dest, job_id);
+    return;
+  }
+
+ /*
+  * Wait for the job to complete...
+  */
+
+  if (cgiSupportsMultipart())
+  {
+    for (;;)
+    {
+     /*
+      * Get the current job state...
+      */
+
+      snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
+      request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
+      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+                  NULL, uri);
+      if (user)
+       ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                    "requesting-user-name", NULL, user);
+      ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+                   "requested-attributes", 2, NULL, job_attrs);
+
+      if ((response = cupsDoRequest(http, request, "/")) != NULL)
+       cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+      attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM);
+      if (!attr || attr->values[0].integer >= IPP_JOB_STOPPED ||
+          attr->values[0].integer == IPP_JOB_HELD)
+      {
+       ippDelete(response);
+       break;
+      }
+
+     /*
+      * Job not complete, so update the status...
+      */
+
+      ippDelete(response);
+
+      cgiStartHTML(title);
+      cgiCopyTemplateLang("command.tmpl");
+      cgiEndHTML();
+      fflush(stdout);
+
+      sleep(5);
+    }
+  }
+
+ /*
+  * Send the final page that reloads the printer's page...
+  */
+
+  snprintf(resource, sizeof(resource), "/printers/%s", dest);
+
+  cgiFormEncode(uri, resource, sizeof(uri));
+  snprintf(refresh, sizeof(refresh), "5;URL=%s", uri);
+  cgiSetVariable("refresh_page", refresh);
+
+  cgiStartHTML(title);
+  cgiCopyTemplateLang("command.tmpl");
+  cgiEndHTML();
+
+  if (cgiSupportsMultipart())
+    cgiEndMultipart();
+}
+
+
 /*
  * 'cgiPrintTestPage()' - Print a test page.
  */
@@ -532,8 +717,7 @@ cgiPrintTestPage(http_t     *http,  /* I - Connection to server */
   * See who is logged in...
   */
 
-  if ((user = getenv("REMOTE_USER")) == NULL)
-    user = "guest";
+  user = getenv("REMOTE_USER");
 
  /*
   * Locate the test page file...
@@ -542,7 +726,7 @@ cgiPrintTestPage(http_t     *http,  /* I - Connection to server */
   if ((datadir = getenv("CUPS_DATADIR")) == NULL)
     datadir = CUPS_DATADIR;
 
-  snprintf(filename, sizeof(filename), "%s/data/testprint.ps", datadir);
+  snprintf(filename, sizeof(filename), "%s/data/testprint", datadir);
 
  /*
   * Point to the printer/class...
@@ -563,7 +747,6 @@ cgiPrintTestPage(http_t     *http,  /* I - Connection to server */
   *    attributes-natural-language
   *    printer-uri
   *    requesting-user-name
-  *    document-format
   */
 
   request = ippNewRequest(IPP_PRINT_JOB);
@@ -571,15 +754,13 @@ cgiPrintTestPage(http_t     *http,        /* I - Connection to server */
   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
                NULL, uri);
 
-  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-               "requesting-user-name", NULL, user);
+  if (user)
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+                "requesting-user-name", NULL, user);
 
   ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
                NULL, "Test Page");
 
-  ippAddString(request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
-               NULL, "application/postscript");
-
  /*
   * Do the request and get back a response...
   */
@@ -602,11 +783,16 @@ cgiPrintTestPage(http_t     *http,        /* I - Connection to server */
     snprintf(refresh, sizeof(refresh), "2;URL=%s", uri);
     cgiSetVariable("refresh_page", refresh);
   }
+  else if (cupsLastError() == IPP_NOT_AUTHORIZED)
+  {
+    puts("Status: 401\n");
+    exit(0);
+  }
 
   cgiStartHTML(cgiText(_("Print Test Page")));
 
   if (cupsLastError() > IPP_OK_CONFLICT)
-    cgiShowIPPError(_("Unable to print test page:"));
+    cgiShowIPPError(_("Unable to print test page"));
   else
   {
     cgiSetVariable("PRINTER_NAME", dest);
@@ -628,7 +814,7 @@ cgiRewriteURL(const char *uri,              /* I - Current URI */
              int        urlsize,       /* I - Size of URL buffer */
              const char *newresource)  /* I - Replacement resource */
 {
-  char                 method[HTTP_MAX_URI],
+  char                 scheme[HTTP_MAX_URI],
                        userpass[HTTP_MAX_URI],
                        hostname[HTTP_MAX_URI],
                        rawresource[HTTP_MAX_URI],
@@ -675,13 +861,13 @@ cgiRewriteURL(const char *uri,            /* I - Current URI */
   * Convert the URI to a URL...
   */
 
-  httpSeparateURI(HTTP_URI_CODING_ALL, uri, method, sizeof(method), userpass,
+  httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
                   sizeof(userpass), hostname, sizeof(hostname), &port,
                  rawresource, sizeof(rawresource));
 
-  if (!strcmp(method, "ipp") ||
-      !strcmp(method, "http") ||
-      !strcmp(method, "https"))
+  if (!strcmp(scheme, "ipp") ||
+      !strcmp(scheme, "http") ||
+      !strcmp(scheme, "https"))
   {
     if (newresource)
     {
@@ -720,10 +906,12 @@ cgiRewriteURL(const char *uri,            /* I - Current URI */
     * Map local access to a local URI...
     */
 
-    if (!strcasecmp(hostname, "localhost") ||
-       !strncasecmp(hostname, "localhost.", 10) ||
-       !strcasecmp(hostname, server) ||
-       !strcasecmp(hostname, servername))
+    if (!_cups_strcasecmp(hostname, "127.0.0.1") ||
+       !_cups_strcasecmp(hostname, "[::1]") ||
+       !_cups_strcasecmp(hostname, "localhost") ||
+       !_cups_strncasecmp(hostname, "localhost.", 10) ||
+       !_cups_strcasecmp(hostname, server) ||
+       !_cups_strcasecmp(hostname, servername))
     {
      /*
       * Make URI relative to the current server...
@@ -742,7 +930,7 @@ cgiRewriteURL(const char *uri,              /* I - Current URI */
                 ishttps ? "https" : "http",
                 userpass, hostname, port, resource);
       else
-       snprintf(url, urlsize, "%s://%s:%d%s", 
+       snprintf(url, urlsize, "%s://%s:%d%s",
                 ishttps ? "https" : "http",
                 hostname, port, resource);
     }
@@ -828,6 +1016,144 @@ cgiSetIPPObjectVars(
       cgiSetArray("job_printer_name", element, valptr);
     }
 
+   /*
+    * Localize event names in "notify_events" variable...
+    */
+
+    if (!strcmp(name, "notify_events"))
+    {
+      size_t   remaining;              /* Remaining bytes in buffer */
+
+
+      value[0] = '\0';
+      valptr   = value;
+
+      for (i = 0; i < attr->num_values; i ++)
+      {
+        if (valptr >= (value + sizeof(value) - 3))
+         break;
+
+        if (i)
+       {
+         *valptr++ = ',';
+         *valptr++ = ' ';
+        }
+
+        remaining = sizeof(value) - (valptr - value);
+
+        if (!strcmp(attr->values[i].string.text, "printer-stopped"))
+         strlcpy(valptr, _("Printer Paused"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "printer-added"))
+         strlcpy(valptr, _("Printer Added"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "printer-modified"))
+         strlcpy(valptr, _("Printer Modified"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "printer-deleted"))
+         strlcpy(valptr, _("Printer Deleted"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "job-created"))
+         strlcpy(valptr, _("Job Created"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "job-completed"))
+         strlcpy(valptr, _("Job Completed"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "job-stopped"))
+         strlcpy(valptr, _("Job Stopped"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "job-config-changed"))
+         strlcpy(valptr, _("Job Options Changed"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "server-restarted"))
+         strlcpy(valptr, _("Server Restarted"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "server-started"))
+         strlcpy(valptr, _("Server Started"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "server-stopped"))
+         strlcpy(valptr, _("Server Stopped"), remaining);
+       else if (!strcmp(attr->values[i].string.text, "server-audit"))
+         strlcpy(valptr, _("Server Security Auditing"), remaining);
+       else
+          strlcpy(valptr, attr->values[i].string.text, remaining);
+
+        valptr += strlen(valptr);
+      }
+
+      cgiSetArray("notify_events", element, value);
+      continue;
+    }
+
+   /*
+    * Add "notify_printer_name" variable if we have a "notify_printer_uri"
+    * attribute...
+    */
+
+    if (!strcmp(name, "notify_printer_uri"))
+    {
+      if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
+       valptr = "unknown";
+      else
+       valptr ++;
+
+      cgiSetArray("notify_printer_name", element, valptr);
+    }
+
+   /*
+    * Add "notify_recipient_name" variable if we have a "notify_recipient_uri"
+    * attribute, and rewrite recipient URI...
+    */
+
+    if (!strcmp(name, "notify_recipient_uri"))
+    {
+      char     uri[1024],              /* New URI */
+               scheme[32],             /* Scheme portion of URI */
+               userpass[256],          /* Username/password portion of URI */
+               host[1024],             /* Hostname portion of URI */
+               resource[1024],         /* Resource portion of URI */
+               *options;               /* Options in URI */
+      int      port;                   /* Port number */
+
+
+      httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
+                      scheme, sizeof(scheme), userpass, sizeof(userpass),
+                     host, sizeof(host), &port, resource, sizeof(resource));
+
+      if (!strcmp(scheme, "rss"))
+      {
+       /*
+        * RSS notification...
+       */
+
+        if ((options = strchr(resource, '?')) != NULL)
+         *options = '\0';
+
+        if (host[0])
+       {
+        /*
+         * Link to remote feed...
+         */
+
+         httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "http",
+                         userpass, host, port, resource);
+          strlcpy(name, uri, sizeof(name));
+       }
+       else
+       {
+        /*
+         * Link to local feed...
+         */
+
+         snprintf(uri, sizeof(uri), "/rss%s", resource);
+          strlcpy(name, resource + 1, sizeof(name));
+       }
+      }
+      else
+      {
+       /*
+        * Other...
+       */
+
+        strlcpy(uri, attr->values[0].string.text, sizeof(uri));
+       strlcpy(name, resource, sizeof(name));
+      }
+
+      cgiSetArray("notify_recipient_uri", element, uri);
+      cgiSetArray("notify_recipient_name", element, name);
+      continue;
+    }
+
    /*
     * Add "admin_uri" variable if we have a "printer_uri_supported"
     * attribute...
@@ -851,7 +1177,7 @@ cgiSetIPPObjectVars(
     for (i = 0; i < attr->num_values; i ++)
     {
       if (i)
-       strlcat(valptr, ",", sizeof(value) - (valptr - value));
+       strlcat(valptr, ", ", sizeof(value) - (valptr - value));
 
       valptr += strlen(valptr);
 
@@ -893,7 +1219,7 @@ cgiSetIPPObjectVars(
                     "%dx%d%s", attr->values[i].resolution.xres,
                     attr->values[i].resolution.yres,
                     attr->values[i].resolution.units == IPP_RES_PER_INCH ?
-                        "dpi" : "dpc");
+                        "dpi" : "dpcm");
            break;
 
        case IPP_TAG_URI :
@@ -1021,7 +1347,7 @@ cgiSetIPPVars(ipp_t      *response,       /* I - Response data to be copied... */
             (filter->value_tag >= IPP_TAG_TEXTLANG &&
              filter->value_tag <= IPP_TAG_MIMETYPE)) &&
            filter->values[0].string.text != NULL &&
-           !strcasecmp(filter->values[0].string.text, filter_value))
+           !_cups_strcasecmp(filter->values[0].string.text, filter_value))
          break;
 
       if (!filter)
@@ -1076,11 +1402,12 @@ cgiShowJobs(http_t     *http,           /* I - Connection to server */
   int                  ascending,      /* Order of jobs (0 = descending) */
                        first,          /* First job to show */
                        count;          /* Number of jobs */
-  const char           *var;           /* Form variable */
+  const char           *var,           /* Form variable */
+                       *query,         /* Query string */
+                       *section;       /* Section in web interface */
   void                 *search;        /* Search data */
-  char                 url[1024],      /* URL for prev/next/this */
-                       *urlptr,        /* Position in URL */
-                       *urlend;        /* End of URL */
+  char                 url[1024],      /* Printer URI */
+                       val[1024];      /* Form variable */
 
 
  /*
@@ -1102,10 +1429,10 @@ cgiShowJobs(http_t     *http,           /* I - Connection to server */
                  NULL, url);
   }
   else
-    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL,
-                "ipp://localhost/jobs");
+    ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+                "ipp://localhost/");
 
-  if ((which_jobs = cgiGetVariable("which_jobs")) != NULL)
+  if ((which_jobs = cgiGetVariable("which_jobs")) != NULL && *which_jobs)
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
                  NULL, which_jobs);
 
@@ -1121,10 +1448,14 @@ cgiShowJobs(http_t     *http,           /* I - Connection to server */
     * Get a list of matching job objects.
     */
 
-    if ((var = cgiGetVariable("QUERY")) != NULL)
-      search = cgiCompileSearch(var);
+    if ((query = cgiGetVariable("QUERY")) != NULL &&
+        !cgiGetVariable("CLEAR"))
+      search = cgiCompileSearch(query);
     else
+    {
+      query  = NULL;
       search = NULL;
+    }
 
     jobs  = cgiGetIPPObjects(response, search);
     count = cupsArrayCount(jobs);
@@ -1149,16 +1480,28 @@ cgiShowJobs(http_t     *http,           /* I - Connection to server */
     if (first < 0)
       first = 0;
 
-    sprintf(url, "%d", count);
-    cgiSetVariable("TOTAL", url);
-
-    if ((var = cgiGetVariable("ORDER")) != NULL)
-      ascending = !strcasecmp(var, "asc");
+    if ((var = cgiGetVariable("ORDER")) != NULL && *var)
+      ascending = !_cups_strcasecmp(var, "asc");
     else
-    {
-      ascending = !which_jobs || !strcasecmp(which_jobs, "not-completed");
-      cgiSetVariable("ORDER", ascending ? "asc" : "dec");
-    }
+      ascending = !which_jobs || !*which_jobs ||
+                  !_cups_strcasecmp(which_jobs, "not-completed");
+
+    section = cgiGetVariable("SECTION");
+
+    cgiClearVariables();
+
+    if (query)
+      cgiSetVariable("QUERY", query);
+
+    cgiSetVariable("ORDER", ascending ? "asc" : "dec");
+
+    cgiSetVariable("SECTION", section);
+
+    sprintf(val, "%d", count);
+    cgiSetVariable("TOTAL", val);
+
+    if (which_jobs)
+      cgiSetVariable("WHICH_JOBS", which_jobs);
 
     if (ascending)
     {
@@ -1179,61 +1522,27 @@ cgiShowJobs(http_t     *http,           /* I - Connection to server */
     * Save navigation URLs...
     */
 
-    urlend = url + sizeof(url);
-
-    if ((var = cgiGetVariable("QUERY")) != NULL)
+    if (dest)
     {
-      if (dest)
-        snprintf(url, sizeof(url), "/%s/%s?QUERY=", cgiGetVariable("SECTION"),
-                dest);
-      else
-        strlcpy(url, "/jobs/?QUERY=", sizeof(url));
-
-      urlptr = url + strlen(url);
-
-      cgiFormEncode(urlptr, var, urlend - urlptr);
-      urlptr += strlen(urlptr);
-
-      strlcpy(urlptr, "&", urlend - urlptr);
-      urlptr += strlen(urlptr);
+      snprintf(val, sizeof(val), "/%s/%s", section, dest);
+      cgiSetVariable("PRINTER_NAME", dest);
+      cgiSetVariable("PRINTER_URI_SUPPORTED", val);
     }
     else
-    {
-      if (dest)
-        snprintf(url, sizeof(url), "/%s/%s?", cgiGetVariable("SECTION"), dest);
-      else
-        strlcpy(url, "/jobs/?", sizeof(url));
-
-      urlptr = url + strlen(url);
-    }
-
-    if (which_jobs)
-    {
-      strlcpy(urlptr, "WHICH_JOBS=", urlend - urlptr);
-      urlptr += strlen(urlptr);
-
-      cgiFormEncode(urlptr, which_jobs, urlend - urlptr);
-      urlptr += strlen(urlptr);
-
-      strlcpy(urlptr, "&", urlend - urlptr);
-      urlptr += strlen(urlptr);
-    }
+      strlcpy(val, "/jobs/", sizeof(val));
 
-    snprintf(urlptr, urlend - urlptr, "FIRST=%d", first);
-    cgiSetVariable("THISURL", url);
+    cgiSetVariable("THISURL", val);
 
     if (first > 0)
     {
-      snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s",
-              first - CUPS_PAGE_MAX, ascending ? "asc" : "dec");
-      cgiSetVariable("PREVURL", url);
+      sprintf(val, "%d", first - CUPS_PAGE_MAX);
+      cgiSetVariable("PREV", val);
     }
 
     if ((first + CUPS_PAGE_MAX) < count)
     {
-      snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s",
-              first + CUPS_PAGE_MAX, ascending ? "asc" : "dec");
-      cgiSetVariable("NEXTURL", url);
+      sprintf(val, "%d", first + CUPS_PAGE_MAX);
+      cgiSetVariable("NEXT", val);
     }
 
    /*
@@ -1247,12 +1556,12 @@ cgiShowJobs(http_t     *http,           /* I - Connection to server */
 
     cgiCopyTemplateLang("jobs-header.tmpl");
 
-    if (count > 0)
+    if (count > CUPS_PAGE_MAX)
       cgiCopyTemplateLang("pager.tmpl");
 
     cgiCopyTemplateLang("jobs.tmpl");
 
-    if (count > 0)
+    if (count > CUPS_PAGE_MAX)
       cgiCopyTemplateLang("pager.tmpl");
 
     cupsArrayDelete(jobs);
@@ -1280,5 +1589,5 @@ cgiText(const char *message)              /* I - Message */
 
 
 /*
- * End of "$Id: ipp-var.c 6244 2007-02-06 21:08:59Z mike $".
+ * End of "$Id$".
  */