/* * CGI <-> IPP variable routines for CUPS. * * Copyright 2007-2016 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 * missing or damaged, see the license at "http://www.cups.org/". */ /* * 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 */ 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, (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); sprintf(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) { 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); } 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)); }