summaryrefslogtreecommitdiff
path: root/cgi-bin/ipp-var.c
diff options
context:
space:
mode:
Diffstat (limited to 'cgi-bin/ipp-var.c')
-rw-r--r--cgi-bin/ipp-var.c1592
1 files changed, 1592 insertions, 0 deletions
diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c
new file mode 100644
index 0000000..8f13c27
--- /dev/null
+++ b/cgi-bin/ipp-var.c
@@ -0,0 +1,1592 @@
+/*
+ * "$Id: ipp-var.c 9793 2011-05-20 03:49:49Z mike $"
+ *
+ * CGI <-> IPP variable routines for CUPS.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * 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.
+ * 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.
+ * cgiSetIPPVars() - Set CGI variables from an IPP response.
+ * cgiShowIPPError() - Show the last IPP error message.
+ * cgiShowJobs() - Show print jobs.
+ * cgiText() - Return localized text.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cgi-private.h"
+
+
+/*
+ * 'cgiGetAttributes()' - Get the list of attributes that are needed
+ * by the template file.
+ */
+
+void
+cgiGetAttributes(ipp_t *request, /* I - IPP request */
+ const char *tmpl) /* I - Base filename */
+{
+ int num_attrs; /* Number of attributes */
+ char *attrs[1000]; /* Attributes */
+ int i; /* Looping var */
+ char filename[1024], /* Filename */
+ locale[16]; /* Locale name */
+ const char *directory, /* Directory */
+ *lang; /* Language */
+ FILE *in; /* Input file */
+ int ch; /* Character from file */
+ char name[255], /* Name of variable */
+ *nameptr; /* Pointer into name */
+
+
+ /*
+ * Convert the language to a locale name...
+ */
+
+ if ((lang = getenv("LANG")) != NULL)
+ {
+ for (i = 0; lang[i] && i < 15; i ++)
+ if (isalnum(lang[i] & 255))
+ locale[i] = tolower(lang[i]);
+ else
+ locale[i] = '_';
+
+ locale[i] = '\0';
+ }
+ else
+ locale[0] = '\0';
+
+ /*
+ * See if we have a template file for this language...
+ */
+
+ directory = cgiGetTemplateDir();
+
+ snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
+ if (access(filename, 0))
+ {
+ locale[2] = '\0';
+
+ snprintf(filename, sizeof(filename), "%s/%s/%s", directory, locale, tmpl);
+ if (access(filename, 0))
+ snprintf(filename, sizeof(filename), "%s/%s", directory, tmpl);
+ }
+
+ /*
+ * Open the template file...
+ */
+
+ if ((in = fopen(filename, "r")) == NULL)
+ return;
+
+ /*
+ * Loop through the file adding attribute names as needed...
+ */
+
+ num_attrs = 0;
+ attrs[0] = NULL; /* Eliminate compiler warning */
+
+ while ((ch = getc(in)) != EOF)
+ if (ch == '\\')
+ getc(in);
+ else if (ch == '{' && num_attrs < (sizeof(attrs) / sizeof(attrs[0])))
+ {
+ /*
+ * Grab the name...
+ */
+
+ for (nameptr = name; (ch = getc(in)) != EOF;)
+ if (strchr("}]<>=!~ \t\n", ch))
+ break;
+ else if (nameptr > name && ch == '?')
+ break;
+ else if (nameptr < (name + sizeof(name) - 1))
+ {
+ if (ch == '_')
+ *nameptr++ = '-';
+ else
+ *nameptr++ = ch;
+ }
+
+ *nameptr = '\0';
+
+ if (!strncmp(name, "printer_state_history", 21))
+ strcpy(name, "printer_state_history");
+
+ /*
+ * Possibly add it to the list of attributes...
+ */
+
+ for (i = 0; i < num_attrs; i ++)
+ if (!strcmp(attrs[i], name))
+ break;
+
+ if (i >= num_attrs)
+ {
+ attrs[num_attrs] = strdup(name);
+ num_attrs ++;
+ }
+ }
+
+ /*
+ * If we have attributes, add a requested-attributes attribute to the
+ * request...
+ */
+
+ if (num_attrs > 0)
+ {
+ ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", num_attrs, NULL, (const char **)attrs);
+
+ for (i = 0; i < num_attrs; i ++)
+ free(attrs[i]);
+ }
+
+ fclose(in);
+}
+
+
+/*
+ * 'cgiGetIPPObjects()' - Get the objects in an IPP response.
+ */
+
+cups_array_t * /* O - Array of objects */
+cgiGetIPPObjects(ipp_t *response, /* I - IPP response */
+ void *search) /* I - Search filter */
+{
+ int i; /* Looping var */
+ cups_array_t *objs; /* Array of objects */
+ ipp_attribute_t *attr, /* Current attribute */
+ *first; /* First attribute for object */
+ ipp_tag_t group; /* Current group tag */
+ int add; /* Add this object to the array? */
+
+
+ if (!response)
+ return (0);
+
+ for (add = 0, first = NULL, objs = cupsArrayNew(NULL, NULL),
+ group = IPP_TAG_ZERO, attr = response->attrs;
+ attr;
+ attr = attr->next)
+ {
+ if (attr->group_tag != group)
+ {
+ group = attr->group_tag;
+
+ if (group != IPP_TAG_ZERO && group != IPP_TAG_OPERATION)
+ {
+ first = attr;
+ add = 0;
+ }
+ else if (add && first)
+ {
+ cupsArrayAdd(objs, first);
+
+ add = 0;
+ first = NULL;
+ }
+ }
+
+ if (attr->name && attr->group_tag != IPP_TAG_OPERATION && !add)
+ {
+ if (!search)
+ {
+ /*
+ * Add all objects if there is no search...
+ */
+
+ add = 1;
+ }
+ else
+ {
+ /*
+ * Check the search string against the string and integer values.
+ */
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_TEXTLANG :
+ case IPP_TAG_NAMELANG :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_URI :
+ case IPP_TAG_MIMETYPE :
+ for (i = 0; !add && i < attr->num_values; i ++)
+ if (cgiDoSearch(search, attr->values[i].string.text))
+ add = 1;
+ break;
+
+ case IPP_TAG_INTEGER :
+ for (i = 0; !add && i < attr->num_values; i ++)
+ {
+ char buf[255]; /* Number buffer */
+
+
+ sprintf(buf, "%d", attr->values[i].integer);
+
+ if (cgiDoSearch(search, buf))
+ add = 1;
+ }
+ break;
+
+ default :
+ break;
+ }
+ }
+ }
+ }
+
+ if (add && first)
+ cupsArrayAdd(objs, first);
+
+ return (objs);
+}
+
+
+/*
+ * 'cgiMoveJobs()' - Move one or more jobs.
+ *
+ * At least one of dest or job_id must be non-zero/NULL.
+ */
+
+void
+cgiMoveJobs(http_t *http, /* I - Connection to server */
+ const char *dest, /* I - Destination or NULL */
+ int job_id) /* I - Job ID or 0 for all */
+{
+ int i; /* Looping var */
+ const char *user; /* Username */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ ipp_attribute_t *attr; /* Current attribute */
+ const char *name; /* Destination name */
+ const char *job_printer_uri; /* JOB_PRINTER_URI form variable */
+ char current_dest[1024]; /* Current destination */
+
+
+ /*
+ * Make sure we have a username...
+ */
+
+ if ((user = getenv("REMOTE_USER")) == NULL)
+ {
+ puts("Status: 401\n");
+ exit(0);
+ }
+
+ /*
+ * See if the user has already selected a new destination...
+ */
+
+ if ((job_printer_uri = cgiGetVariable("JOB_PRINTER_URI")) == NULL)
+ {
+ /*
+ * Make sure necessary form variables are set...
+ */
+
+ if (job_id)
+ {
+ char temp[255]; /* Temporary string */
+
+
+ sprintf(temp, "%d", job_id);
+ cgiSetVariable("JOB_ID", temp);
+ }
+
+ if (dest)
+ cgiSetVariable("PRINTER_NAME", dest);
+
+ /*
+ * No new destination specified, show the user what the available
+ * printers/classes are...
+ */
+
+ if (!dest)
+ {
+ /*
+ * Get the current destination for job N...
+ */
+
+ char job_uri[1024]; /* Job URI */
+
+
+ request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES);
+
+ snprintf(job_uri, sizeof(job_uri), "ipp://localhost/jobs/%d", job_id);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ 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",
+ IPP_TAG_URI)) != NULL)
+ {
+ /*
+ * Pull the name from the URI...
+ */
+
+ strlcpy(current_dest, strrchr(attr->values[0].string.text, '/') + 1,
+ sizeof(current_dest));
+ dest = current_dest;
+ }
+
+ ippDelete(response);
+ }
+
+ if (!dest)
+ {
+ /*
+ * Couldn't get the current destination...
+ */
+
+ cgiStartHTML(cgiText(_("Move Job")));
+ cgiShowIPPError(_("Unable to find destination for job"));
+ cgiEndHTML();
+ return;
+ }
+ }
+
+ /*
+ * Get the list of available destinations...
+ */
+
+ request = ippNewRequest(CUPS_GET_PRINTERS);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
+ "requested-attributes", NULL, "printer-uri-supported");
+
+ 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)
+ {
+ for (i = 0, attr = ippFindAttribute(response, "printer-uri-supported",
+ IPP_TAG_URI);
+ attr;
+ attr = ippFindNextAttribute(response, "printer-uri-supported",
+ IPP_TAG_URI))
+ {
+ /*
+ * Pull the name from the URI...
+ */
+
+ name = strrchr(attr->values[0].string.text, '/') + 1;
+
+ /*
+ * If the name is not the same as the current destination, add it!
+ */
+
+ if (_cups_strcasecmp(name, dest))
+ {
+ cgiSetArray("JOB_PRINTER_URI", i, attr->values[0].string.text);
+ cgiSetArray("JOB_PRINTER_NAME", i, name);
+ i ++;
+ }
+ }
+
+ ippDelete(response);
+ }
+
+ /*
+ * Show the form...
+ */
+
+ if (job_id)
+ cgiStartHTML(cgiText(_("Move Job")));
+ else
+ cgiStartHTML(cgiText(_("Move All Jobs")));
+
+ 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
+ {
+ /*
+ * Try moving the job or jobs...
+ */
+
+ char uri[1024], /* Job/printer URI */
+ resource[1024], /* Post resource */
+ refresh[1024]; /* Refresh URL */
+ const char *job_printer_name; /* New printer name */
+
+
+ request = ippNewRequest(CUPS_MOVE_JOB);
+
+ if (job_id)
+ {
+ /*
+ * Move 1 job...
+ */
+
+ snprintf(resource, sizeof(resource), "/jobs/%d", job_id);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", job_id);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri",
+ NULL, uri);
+ }
+ else
+ {
+ /*
+ * Move all active jobs on a destination...
+ */
+
+ snprintf(resource, sizeof(resource), "/%s/%s",
+ cgiGetVariable("SECTION"), dest);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", ippPort(), "/%s/%s",
+ cgiGetVariable("SECTION"), dest);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+ }
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-printer-uri",
+ NULL, job_printer_uri);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+ "requesting-user-name", NULL, user);
+
+ ippDelete(cupsDoRequest(http, request, resource));
+
+ /*
+ * Show the results...
+ */
+
+ job_printer_name = strrchr(job_printer_uri, '/') + 1;
+
+ if (cupsLastError() <= IPP_OK_CONFLICT)
+ {
+ 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)
+ cgiStartHTML(cgiText(_("Move Job")));
+ else
+ cgiStartHTML(cgiText(_("Move All Jobs")));
+
+ if (cupsLastError() > IPP_OK_CONFLICT)
+ {
+ if (job_id)
+ cgiShowIPPError(_("Unable to move job"));
+ else
+ cgiShowIPPError(_("Unable to move jobs"));
+ }
+ else
+ {
+ cgiSetVariable("JOB_PRINTER_NAME", job_printer_name);
+ cgiCopyTemplateLang("job-moved.tmpl");
+ }
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * '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.
+ */
+
+void
+cgiPrintTestPage(http_t *http, /* I - Connection to server */
+ const char *dest) /* I - Destination printer/class */
+{
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ char uri[HTTP_MAX_URI], /* Printer URI */
+ resource[1024], /* POST resource path */
+ refresh[1024], /* Refresh URL */
+ filename[1024]; /* Test page filename */
+ const char *datadir; /* CUPS_DATADIR env var */
+ const char *user; /* Username */
+
+
+ /*
+ * See who is logged in...
+ */
+
+ user = getenv("REMOTE_USER");
+
+ /*
+ * Locate the test page file...
+ */
+
+ if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+ datadir = CUPS_DATADIR;
+
+ snprintf(filename, sizeof(filename), "%s/data/testprint", datadir);
+
+ /*
+ * Point to the printer/class...
+ */
+
+ snprintf(resource, sizeof(resource), "/%s/%s", cgiGetVariable("SECTION"),
+ dest);
+
+ httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+ "localhost", ippPort(), "/%s/%s", cgiGetVariable("SECTION"),
+ dest);
+
+ /*
+ * Build an IPP_PRINT_JOB request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ * requesting-user-name
+ */
+
+ request = ippNewRequest(IPP_PRINT_JOB);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, uri);
+
+ 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");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoFileRequest(http, request, resource,
+ filename)) != NULL)
+ {
+ cgiSetIPPVars(response, NULL, NULL, NULL, 0);
+
+ ippDelete(response);
+ }
+
+ if (cupsLastError() <= IPP_OK_CONFLICT)
+ {
+ /*
+ * Automatically reload the printer status page...
+ */
+
+ cgiFormEncode(uri, resource, sizeof(uri));
+ 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:"));
+ else
+ {
+ cgiSetVariable("PRINTER_NAME", dest);
+
+ cgiCopyTemplateLang("test-page.tmpl");
+ }
+
+ cgiEndHTML();
+}
+
+
+/*
+ * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL...
+ */
+
+char * /* O - New URL */
+cgiRewriteURL(const char *uri, /* I - Current URI */
+ char *url, /* O - New URL */
+ int urlsize, /* I - Size of URL buffer */
+ const char *newresource) /* I - Replacement resource */
+{
+ char scheme[HTTP_MAX_URI],
+ userpass[HTTP_MAX_URI],
+ hostname[HTTP_MAX_URI],
+ rawresource[HTTP_MAX_URI],
+ resource[HTTP_MAX_URI],
+ /* URI components... */
+ *rawptr, /* Pointer into rawresource */
+ *resptr; /* Pointer into resource */
+ int port; /* Port number */
+ static int ishttps = -1; /* Using encryption? */
+ static const char *server; /* Name of server */
+ static char servername[1024];
+ /* Local server name */
+ static const char hexchars[] = "0123456789ABCDEF";
+ /* Hexadecimal conversion characters */
+
+
+ /*
+ * Check if we have been called before...
+ */
+
+ if (ishttps < 0)
+ {
+ /*
+ * No, initialize static vars for the conversion...
+ *
+ * First get the server name associated with the client interface as
+ * well as the locally configured hostname. We'll check *both* of
+ * these to see if the printer URL is local...
+ */
+
+ if ((server = getenv("SERVER_NAME")) == NULL)
+ server = "";
+
+ httpGetHostname(NULL, servername, sizeof(servername));
+
+ /*
+ * Then flag whether we are using SSL on this connection...
+ */
+
+ ishttps = getenv("HTTPS") != NULL;
+ }
+
+ /*
+ * Convert the URI to a URL...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname), &port,
+ rawresource, sizeof(rawresource));
+
+ if (!strcmp(scheme, "ipp") ||
+ !strcmp(scheme, "http") ||
+ !strcmp(scheme, "https"))
+ {
+ if (newresource)
+ {
+ /*
+ * Force the specified resource name instead of the one in the URL...
+ */
+
+ strlcpy(resource, newresource, sizeof(resource));
+ }
+ else
+ {
+ /*
+ * Rewrite the resource string so it doesn't contain any
+ * illegal chars...
+ */
+
+ for (rawptr = rawresource, resptr = resource; *rawptr; rawptr ++)
+ if ((*rawptr & 128) || *rawptr == '%' || *rawptr == ' ' ||
+ *rawptr == '#' || *rawptr == '?' ||
+ *rawptr == '.') /* For MSIE */
+ {
+ if (resptr < (resource + sizeof(resource) - 3))
+ {
+ *resptr++ = '%';
+ *resptr++ = hexchars[(*rawptr >> 4) & 15];
+ *resptr++ = hexchars[*rawptr & 15];
+ }
+ }
+ else if (resptr < (resource + sizeof(resource) - 1))
+ *resptr++ = *rawptr;
+
+ *resptr = '\0';
+ }
+
+ /*
+ * Map local access to a local URI...
+ */
+
+ 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...
+ */
+
+ strlcpy(url, resource, urlsize);
+ }
+ else
+ {
+ /*
+ * Rewrite URI with HTTP/HTTPS scheme...
+ */
+
+ if (userpass[0])
+ snprintf(url, urlsize, "%s://%s@%s:%d%s",
+ ishttps ? "https" : "http",
+ userpass, hostname, port, resource);
+ else
+ snprintf(url, urlsize, "%s://%s:%d%s",
+ ishttps ? "https" : "http",
+ hostname, port, resource);
+ }
+ }
+ else
+ strlcpy(url, uri, urlsize);
+
+ return (url);
+}
+
+
+/*
+ * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object.
+ */
+
+ipp_attribute_t * /* O - Next object */
+cgiSetIPPObjectVars(
+ ipp_attribute_t *obj, /* I - Response data to be copied... */
+ const char *prefix, /* I - Prefix for name or NULL */
+ int element) /* I - Parent element number */
+{
+ ipp_attribute_t *attr; /* Attribute in response... */
+ int i; /* Looping var */
+ char name[1024], /* Name of attribute */
+ *nameptr, /* Pointer into name */
+ value[16384], /* Value(s) */
+ *valptr; /* Pointer into value */
+ struct tm *date; /* Date information */
+
+
+ fprintf(stderr, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", "
+ "element=%d)\n",
+ obj, prefix ? prefix : "(null)", element);
+
+ /*
+ * Set common CGI template variables...
+ */
+
+ if (!prefix)
+ cgiSetServerVersion();
+
+ /*
+ * Loop through the attributes and set them for the template...
+ */
+
+ for (attr = obj; attr && attr->group_tag != IPP_TAG_ZERO; attr = attr->next)
+ {
+ /*
+ * Copy the attribute name, substituting "_" for "-"...
+ */
+
+ if (!attr->name)
+ continue;
+
+ if (prefix)
+ {
+ snprintf(name, sizeof(name), "%s.", prefix);
+ nameptr = name + strlen(name);
+ }
+ else
+ nameptr = name;
+
+ for (i = 0; attr->name[i] && nameptr < (name + sizeof(name) - 1); i ++)
+ if (attr->name[i] == '-')
+ *nameptr++ = '_';
+ else
+ *nameptr++ = attr->name[i];
+
+ *nameptr = '\0';
+
+ /*
+ * Add "job_printer_name" variable if we have a "job_printer_uri"
+ * attribute...
+ */
+
+ if (!strcmp(name, "job_printer_uri"))
+ {
+ if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL)
+ valptr = "unknown";
+ else
+ valptr ++;
+
+ 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...
+ */
+
+ if (!strcmp(name, "printer_uri_supported"))
+ {
+ cgiRewriteURL(attr->values[0].string.text, value, sizeof(value),
+ "/admin/");
+
+ cgiSetArray("admin_uri", element, value);
+ }
+
+ /*
+ * Copy values...
+ */
+
+ value[0] = '\0'; /* Initially an empty string */
+ valptr = value; /* Start at the beginning */
+
+ for (i = 0; i < attr->num_values; i ++)
+ {
+ if (i)
+ strlcat(valptr, ", ", sizeof(value) - (valptr - value));
+
+ valptr += strlen(valptr);
+
+ switch (attr->value_tag)
+ {
+ case IPP_TAG_INTEGER :
+ case IPP_TAG_ENUM :
+ if (strncmp(name, "time_at_", 8) == 0)
+ {
+ time_t t; /* Temporary time value */
+
+ t = (time_t)attr->values[i].integer;
+ date = localtime(&t);
+
+ strftime(valptr, sizeof(value) - (valptr - value), "%c", date);
+ }
+ else
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%d", attr->values[i].integer);
+ break;
+
+ case IPP_TAG_BOOLEAN :
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%d", attr->values[i].boolean);
+ break;
+
+ case IPP_TAG_NOVALUE :
+ strlcat(valptr, "novalue", sizeof(value) - (valptr - value));
+ break;
+
+ case IPP_TAG_RANGE :
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%d-%d", attr->values[i].range.lower,
+ attr->values[i].range.upper);
+ break;
+
+ case IPP_TAG_RESOLUTION :
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "%dx%d%s", attr->values[i].resolution.xres,
+ attr->values[i].resolution.yres,
+ attr->values[i].resolution.units == IPP_RES_PER_INCH ?
+ "dpi" : "dpc");
+ break;
+
+ case IPP_TAG_URI :
+ if (strchr(attr->values[i].string.text, ':') &&
+ strcmp(name, "device_uri"))
+ {
+ /*
+ * Rewrite URIs...
+ */
+
+ if (!strcmp(name, "member_uris"))
+ {
+ char url[1024]; /* URL for class member... */
+
+
+ cgiRewriteURL(attr->values[i].string.text, url,
+ sizeof(url), NULL);
+
+ snprintf(valptr, sizeof(value) - (valptr - value),
+ "<A HREF=\"%s\">%s</A>", url,
+ strrchr(attr->values[i].string.text, '/') + 1);
+ }
+ else
+ cgiRewriteURL(attr->values[i].string.text, valptr,
+ sizeof(value) - (valptr - value), NULL);
+ break;
+ }
+
+ case IPP_TAG_STRING :
+ case IPP_TAG_TEXT :
+ case IPP_TAG_NAME :
+ case IPP_TAG_KEYWORD :
+ case IPP_TAG_CHARSET :
+ case IPP_TAG_LANGUAGE :
+ case IPP_TAG_MIMETYPE :
+ strlcat(valptr, attr->values[i].string.text,
+ sizeof(value) - (valptr - value));
+ break;
+
+ case IPP_TAG_BEGIN_COLLECTION :
+ snprintf(value, sizeof(value), "%s%d", name, i + 1);
+ cgiSetIPPVars(attr->values[i].collection, NULL, NULL, value,
+ element);
+ break;
+
+ default :
+ break; /* anti-compiler-warning-code */
+ }
+ }
+
+ /*
+ * Add the element...
+ */
+
+ if (attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
+ {
+ cgiSetArray(name, element, value);
+
+ fprintf(stderr, "DEBUG2: %s[%d]=\"%s\"\n", name, element, value);
+ }
+ }
+
+ return (attr ? attr->next : NULL);
+}
+
+
+/*
+ * 'cgiSetIPPVars()' - Set CGI variables from an IPP response.
+ */
+
+int /* O - Maximum number of elements */
+cgiSetIPPVars(ipp_t *response, /* I - Response data to be copied... */
+ const char *filter_name, /* I - Filter name */
+ const char *filter_value, /* I - Filter value */
+ const char *prefix, /* I - Prefix for name or NULL */
+ int parent_el) /* I - Parent element number */
+{
+ int element; /* Element in CGI array */
+ ipp_attribute_t *attr, /* Attribute in response... */
+ *filter; /* Filtering attribute */
+
+
+ fprintf(stderr, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", "
+ "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n",
+ response, filter_name ? filter_name : "(null)",
+ filter_value ? filter_value : "(null)",
+ prefix ? prefix : "(null)", parent_el);
+
+ /*
+ * Set common CGI template variables...
+ */
+
+ if (!prefix)
+ cgiSetServerVersion();
+
+ /*
+ * Loop through the attributes and set them for the template...
+ */
+
+ attr = response->attrs;
+
+ if (!prefix)
+ while (attr && attr->group_tag == IPP_TAG_OPERATION)
+ attr = attr->next;
+
+ for (element = parent_el; attr; element ++)
+ {
+ /*
+ * Copy attributes to a separator...
+ */
+
+ while (attr && attr->group_tag == IPP_TAG_ZERO)
+ attr= attr->next;
+
+ if (!attr)
+ break;
+
+ if (filter_name)
+ {
+ for (filter = attr;
+ filter != NULL && filter->group_tag != IPP_TAG_ZERO;
+ filter = filter->next)
+ if (filter->name && !strcmp(filter->name, filter_name) &&
+ (filter->value_tag == IPP_TAG_STRING ||
+ (filter->value_tag >= IPP_TAG_TEXTLANG &&
+ filter->value_tag <= IPP_TAG_MIMETYPE)) &&
+ filter->values[0].string.text != NULL &&
+ !_cups_strcasecmp(filter->values[0].string.text, filter_value))
+ break;
+
+ if (!filter)
+ return (element + 1);
+
+ if (filter->group_tag == IPP_TAG_ZERO)
+ {
+ attr = filter;
+ element --;
+ continue;
+ }
+ }
+
+ attr = cgiSetIPPObjectVars(attr, prefix, element);
+ }
+
+ fprintf(stderr, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element);
+
+ return (element);
+}
+
+
+/*
+ * 'cgiShowIPPError()' - Show the last IPP error message.
+ *
+ * The caller must still call cgiStartHTML() and cgiEndHTML().
+ */
+
+void
+cgiShowIPPError(const char *message) /* I - Contextual message */
+{
+ cgiSetVariable("MESSAGE", cgiText(message));
+ cgiSetVariable("ERROR", cupsLastErrorString());
+ cgiCopyTemplateLang("error.tmpl");
+}
+
+
+/*
+ * 'cgiShowJobs()' - Show print jobs.
+ */
+
+void
+cgiShowJobs(http_t *http, /* I - Connection to server */
+ const char *dest) /* I - Destination name or NULL */
+{
+ int i; /* Looping var */
+ const char *which_jobs; /* Which jobs to show */
+ ipp_t *request, /* IPP request */
+ *response; /* IPP response */
+ cups_array_t *jobs; /* Array of job objects */
+ ipp_attribute_t *job; /* Job object */
+ int ascending, /* Order of jobs (0 = descending) */
+ first, /* First job to show */
+ count; /* Number of jobs */
+ const char *var, /* Form variable */
+ *query, /* Query string */
+ *section; /* Section in web interface */
+ void *search; /* Search data */
+ char url[1024], /* Printer URI */
+ val[1024]; /* Form variable */
+
+
+ /*
+ * Build an IPP_GET_JOBS request, which requires the following
+ * attributes:
+ *
+ * attributes-charset
+ * attributes-natural-language
+ * printer-uri
+ */
+
+ request = ippNewRequest(IPP_GET_JOBS);
+
+ if (dest)
+ {
+ httpAssembleURIf(HTTP_URI_CODING_ALL, url, sizeof(url), "ipp", NULL,
+ "localhost", ippPort(), "/printers/%s", dest);
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
+ NULL, url);
+ }
+ else
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
+ "ipp://localhost/");
+
+ if ((which_jobs = cgiGetVariable("which_jobs")) != NULL)
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
+ NULL, which_jobs);
+
+ cgiGetAttributes(request, "jobs.tmpl");
+
+ /*
+ * Do the request and get back a response...
+ */
+
+ if ((response = cupsDoRequest(http, request, "/")) != NULL)
+ {
+ /*
+ * Get a list of matching job objects.
+ */
+
+ if ((query = cgiGetVariable("QUERY")) != NULL &&
+ !cgiGetVariable("CLEAR"))
+ search = cgiCompileSearch(query);
+ else
+ {
+ query = NULL;
+ search = NULL;
+ }
+
+ jobs = cgiGetIPPObjects(response, search);
+ count = cupsArrayCount(jobs);
+
+ if (search)
+ cgiFreeSearch(search);
+
+ /*
+ * Figure out which jobs to display...
+ */
+
+ if ((var = cgiGetVariable("FIRST")) != NULL)
+ first = atoi(var);
+ else
+ first = 0;
+
+ if (first >= count)
+ first = count - CUPS_PAGE_MAX;
+
+ first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX;
+
+ if (first < 0)
+ first = 0;
+
+ if ((var = cgiGetVariable("ORDER")) != NULL)
+ ascending = !_cups_strcasecmp(var, "asc");
+ else
+ ascending = !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)
+ {
+ for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, first);
+ i < CUPS_PAGE_MAX && job;
+ i ++, job = (ipp_attribute_t *)cupsArrayNext(jobs))
+ cgiSetIPPObjectVars(job, NULL, i);
+ }
+ else
+ {
+ for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, count - first - 1);
+ i < CUPS_PAGE_MAX && job;
+ i ++, job = (ipp_attribute_t *)cupsArrayPrev(jobs))
+ cgiSetIPPObjectVars(job, NULL, i);
+ }
+
+ /*
+ * Save navigation URLs...
+ */
+
+ if (dest)
+ {
+ snprintf(val, sizeof(val), "/%s/%s", section, dest);
+ cgiSetVariable("PRINTER_NAME", dest);
+ cgiSetVariable("PRINTER_URI_SUPPORTED", val);
+ }
+ else
+ strlcpy(val, "/jobs/", sizeof(val));
+
+ cgiSetVariable("THISURL", val);
+
+ if (first > 0)
+ {
+ sprintf(val, "%d", first - CUPS_PAGE_MAX);
+ cgiSetVariable("PREV", val);
+ }
+
+ if ((first + CUPS_PAGE_MAX) < count)
+ {
+ sprintf(val, "%d", first + CUPS_PAGE_MAX);
+ cgiSetVariable("NEXT", val);
+ }
+
+ /*
+ * Then show everything...
+ */
+
+ if (dest)
+ cgiSetVariable("SEARCH_DEST", dest);
+
+ cgiCopyTemplateLang("search.tmpl");
+
+ cgiCopyTemplateLang("jobs-header.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ cgiCopyTemplateLang("jobs.tmpl");
+
+ if (count > CUPS_PAGE_MAX)
+ cgiCopyTemplateLang("pager.tmpl");
+
+ cupsArrayDelete(jobs);
+ ippDelete(response);
+ }
+}
+
+
+/*
+ * 'cgiText()' - Return localized text.
+ */
+
+const char * /* O - Localized message */
+cgiText(const char *message) /* I - Message */
+{
+ static cups_lang_t *language = NULL;
+ /* Language */
+
+
+ if (!language)
+ language = cupsLangDefault();
+
+ return (_cupsLangString(language, message));
+}
+
+
+/*
+ * End of "$Id: ipp-var.c 9793 2011-05-20 03:49:49Z mike $".
+ */