mirror of https://gitee.com/openkylin/cups.git
1526 lines
37 KiB
C
1526 lines
37 KiB
C
|
/*
|
||
|
* CGI <-> IPP variable routines for CUPS.
|
||
|
*
|
||
|
* Copyright 2007-2016 by Apple Inc.
|
||
|
* Copyright 1997-2007 by Easy Software Products.
|
||
|
*
|
||
|
* Licensed under Apache License v2.0. See the file "LICENSE" for more information.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* 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] = (char)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 < (int)(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++ = (char)ch;
|
||
|
}
|
||
|
|
||
|
*nameptr = '\0';
|
||
|
|
||
|
if (!strncmp(name, "printer_state_history", 21))
|
||
|
strlcpy(name, "printer_state_history", sizeof(name));
|
||
|
|
||
|
/*
|
||
|
* 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 :
|
||
|
if (!strncmp(ippGetName(attr), "time-at-", 8))
|
||
|
break; /* Ignore time-at-xxx */
|
||
|
|
||
|
for (i = 0; !add && i < attr->num_values; i ++)
|
||
|
{
|
||
|
char buf[255]; /* Number buffer */
|
||
|
|
||
|
|
||
|
snprintf(buf, sizeof(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)
|
||
|
user = "guest";
|
||
|
|
||
|
/*
|
||
|
* 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 */
|
||
|
|
||
|
|
||
|
snprintf(temp, sizeof(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, (size_t)urlsize);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* Rewrite URI with HTTP/HTTPS scheme...
|
||
|
*/
|
||
|
|
||
|
if (userpass[0])
|
||
|
snprintf(url, (size_t)urlsize, "%s://%s@%s:%d%s", ishttps ? "https" : "http", userpass, hostname, port, resource);
|
||
|
else
|
||
|
snprintf(url, (size_t)urlsize, "%s://%s:%d%s", ishttps ? "https" : "http", hostname, port, resource);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
strlcpy(url, uri, (size_t)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 */
|
||
|
|
||
|
|
||
|
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) - (size_t)(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) - (size_t)(valptr - value));
|
||
|
|
||
|
valptr += strlen(valptr);
|
||
|
|
||
|
switch (attr->value_tag)
|
||
|
{
|
||
|
case IPP_TAG_INTEGER :
|
||
|
case IPP_TAG_ENUM :
|
||
|
if (strncmp(name, "time_at_", 8) == 0)
|
||
|
_cupsStrDate(valptr, sizeof(value) - (size_t)(valptr - value), (time_t)ippGetInteger(attr, i));
|
||
|
else
|
||
|
snprintf(valptr, sizeof(value) - (size_t)(valptr - value), "%d", ippGetInteger(attr, i));
|
||
|
break;
|
||
|
|
||
|
case IPP_TAG_BOOLEAN :
|
||
|
snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
|
||
|
"%d", attr->values[i].boolean);
|
||
|
break;
|
||
|
|
||
|
case IPP_TAG_NOVALUE :
|
||
|
strlcat(valptr, "novalue", sizeof(value) - (size_t)(valptr - value));
|
||
|
break;
|
||
|
|
||
|
case IPP_TAG_RANGE :
|
||
|
snprintf(valptr, sizeof(value) - (size_t)(valptr - value),
|
||
|
"%d-%d", attr->values[i].range.lower,
|
||
|
attr->values[i].range.upper);
|
||
|
break;
|
||
|
|
||
|
case IPP_TAG_RESOLUTION :
|
||
|
snprintf(valptr, sizeof(value) - (size_t)(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" : "dpcm");
|
||
|
break;
|
||
|
|
||
|
case IPP_TAG_URI :
|
||
|
if (strchr(attr->values[i].string.text, ':') &&
|
||
|
strcmp(name, "device_uri"))
|
||
|
{
|
||
|
/*
|
||
|
* Rewrite URIs...
|
||
|
*/
|
||
|
|
||
|
cgiRewriteURL(attr->values[i].string.text, valptr, (int)(sizeof(value) - (size_t)(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) - (size_t)(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: Returning %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 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 && *which_jobs)
|
||
|
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs",
|
||
|
NULL, which_jobs);
|
||
|
|
||
|
if ((var = cgiGetVariable("FIRST")) != NULL)
|
||
|
{
|
||
|
if ((first = atoi(var)) < 0)
|
||
|
first = 0;
|
||
|
}
|
||
|
else
|
||
|
first = 0;
|
||
|
|
||
|
if (first > 0)
|
||
|
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "first-index", first + 1);
|
||
|
|
||
|
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) + first;
|
||
|
|
||
|
if (search)
|
||
|
cgiFreeSearch(search);
|
||
|
|
||
|
/*
|
||
|
* Figure out which jobs to display...
|
||
|
*/
|
||
|
|
||
|
section = cgiGetVariable("SECTION");
|
||
|
|
||
|
cgiClearVariables();
|
||
|
|
||
|
if (query)
|
||
|
cgiSetVariable("QUERY", query);
|
||
|
|
||
|
cgiSetVariable("SECTION", section);
|
||
|
|
||
|
snprintf(val, sizeof(val), "%d", count);
|
||
|
cgiSetVariable("TOTAL", val);
|
||
|
|
||
|
if (which_jobs)
|
||
|
cgiSetVariable("WHICH_JOBS", which_jobs);
|
||
|
|
||
|
for (i = 0, job = (ipp_attribute_t *)cupsArrayFirst(jobs);
|
||
|
i < CUPS_PAGE_MAX && job;
|
||
|
i ++, job = (ipp_attribute_t *)cupsArrayNext(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)
|
||
|
{
|
||
|
snprintf(val, sizeof(val), "%d", first - CUPS_PAGE_MAX);
|
||
|
cgiSetVariable("PREV", val);
|
||
|
}
|
||
|
|
||
|
if ((first + CUPS_PAGE_MAX) < count)
|
||
|
{
|
||
|
snprintf(val, sizeof(val), "%d", first + CUPS_PAGE_MAX);
|
||
|
cgiSetVariable("NEXT", val);
|
||
|
}
|
||
|
|
||
|
if (count > CUPS_PAGE_MAX)
|
||
|
{
|
||
|
snprintf(val, sizeof(val), "%d", CUPS_PAGE_MAX * (count / CUPS_PAGE_MAX));
|
||
|
cgiSetVariable("LAST", 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));
|
||
|
}
|