Index: doc/help/spec-ipp.html
===================================================================
--- doc/help/spec-ipp.html (revision 6878)
+++ doc/help/spec-ipp.html (revision 6879)
@@ -39,7 +39,7 @@
'fold',' trim', and 'bale' attribute values extension"
specifications.
-CUPS also provides 15 new operations and many new attributes
+
CUPS also provides 16 new operations and many new attributes
to support multiple IPP printers and printer classes on a single
host.
@@ -80,7 +80,7 @@
-CUPS provides 14 extension operations in addition to most of the
+
CUPS provides 16 extension operations in addition to most of the
standard IPP and registered extension operations:
0x400F
Get a PPD file. |
+
+ CUPS-Get-Document |
+ 1.4 |
+ 0x4027 |
+ Get a document file from a job. |
+
@@ -1786,7 +1792,91 @@
If the status code is successful-ok, the PPD file follows
the end of the IPP response.
+
+The CUPS-Get-Document operation (0x4027) gets a document file from a
+job on the server. The document file is specified using the
+document-number and either the job-uri or printer-uri
+and job-id identifying the job.
+
+If the document file is found, successful-ok is returned with
+the document file following the response data.
+
+If the document file does not exist, client-error-not-found is
+returned.
+
+If the requesting user does not have access to the document file,
+client-error-not-authorized is returned.
+
+
CUPS-Get-Document Request
+
+The following group of attributes is supplied as part of the
+CUPS-Get-Document request:
+
+
Group 1: Operation Attributes
+
+
+
+ - Natural Language and Character Set:
+
+
- The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.1 of the IPP Model and
+ Semantics document.
+
+
- "printer-uri" (uri) and "job-id" (integer)
+
OR
+
"job-uri" (uri):
+
+ - The client MUST supply a printer URI and job ID or job URI.
+
+
- "document-number" (integer(1:MAX)):
+
+
- The client MUST supply a document number to retrieve. The
+ document-count attribute for the job defines the maximum
+ document number that can be specified. In the case of jobs with
+ banners (job-sheets is not "none"), document number 1
+ will typically contain the start banner and document number N
+ will typically contain the end banner.
+
+
+
+CUPS-Get-Document Response
+
+The following group of attributes is sent as part of the
+CUPS-Get-Document Response:
+
+
Group 1: Operation Attributes
+
+
+
+ - Status Message:
+
+
- The standard response status message.
+
+
- Natural Language and Character Set:
+
+
- The "attributes-charset" and "attributes-natural-language"
+ attributes as described in section 3.1.4.2 of the IPP Model and
+ Semantics document.
+
+
- "document-format" (mimeType):
+
+
- The format of the document file.
+
+
- "document-number" (integer(1:MAX)):
+
+
- The requested document number.
+
+
- "document-name" (name(MAX)):
+
+
- The name that was supplied with the document, if any.
+
+
+
+If the status code is successful-ok, the document file follows
+the end of the IPP response.
+
+
CUPS provides many extension attributes to support multiple
@@ -1914,6 +2004,11 @@
printing text files. Only the values 10, 12, and 17 are currently
supported. The default value is 10.
+
+
+The document-count attribute specifies the number of documents that
+are present in the job.
+
The fitplot attribute specifies whether to scale HP-GL/2 plot files to
Index: cups/ipp.h
===================================================================
--- cups/ipp.h (revision 6878)
+++ cups/ipp.h (revision 6879)
@@ -246,7 +246,8 @@
CUPS_GET_PPDS, /* Get a list of supported drivers */
CUPS_MOVE_JOB, /* Move a job to a different printer */
CUPS_AUTHENTICATE_JOB, /* Authenticate a job @since CUPS 1.2@ */
- CUPS_GET_PPD /* Get a PPD file @since CUPS 1.3@ */
+ CUPS_GET_PPD, /* Get a PPD file @since CUPS 1.3@ */
+ CUPS_GET_DOCUMENT = 0x4027 /* Get a document file @since CUPS 1.4@ */
} ipp_op_t;
/* Old names for the operations */
Index: cups/ipp-support.c
===================================================================
--- cups/ipp-support.c (revision 6878)
+++ cups/ipp-support.c (revision 6879)
@@ -150,6 +150,10 @@
"CUPS-Move-Job",
"CUPS-Authenticate-Job",
"CUPS-Get-PPD"
+ },
+ * const ipp_cups_ops2[] =
+ {
+ "CUPS-Get-Document"
};
@@ -244,6 +248,8 @@
return ("windows-ext");
else if (op >= CUPS_GET_DEFAULT && op <= CUPS_GET_PPD)
return (ipp_cups_ops[op - CUPS_GET_DEFAULT]);
+ else if (op == CUPS_GET_DOCUMENT)
+ return (ipp_cups_ops2[0]);
/*
* No, build an "unknown-xxxx" operation string...
@@ -278,6 +284,10 @@
if (!strcasecmp(name, ipp_cups_ops[i]))
return ((ipp_op_t)(i + 0x4001));
+ for (i = 0; i < (sizeof(ipp_cups_ops2) / sizeof(ipp_cups_ops2[0])); i ++)
+ if (!strcasecmp(name, ipp_cups_ops2[i]))
+ return ((ipp_op_t)(i + 0x4027));
+
if (!strcasecmp(name, "CUPS-Add-Class"))
return (CUPS_ADD_MODIFY_CLASS);
Index: cups/request.c
===================================================================
--- cups/request.c (revision 6878)
+++ cups/request.c (revision 6879)
@@ -17,6 +17,7 @@
* Contents:
*
* cupsDoFileRequest() - Do an IPP request with a file.
+ * cupsDoIORequest() - Do an IPP request with file descriptors.
* cupsDoRequest() - Do an IPP request.
* _cupsSetError() - Set the last IPP status code and status-message.
* _cupsSetHTTPError() - Set the last error using the HTTP status.
Index: man/cupsfilter.man
===================================================================
--- man/cupsfilter.man (revision 6878)
+++ man/cupsfilter.man (revision 6879)
@@ -11,14 +11,16 @@
.\" 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/".
.\"
-.TH cupsfilter 8 "Common UNIX Printing System" "12 July 2007" "Apple Inc."
+.TH cupsfilter 8 "Common UNIX Printing System" "29 August 2007" "Apple Inc."
.SH NAME
cupsfilter \- convert a file to another format using cups filters
.SH SYNOPSIS
.B cupsfilter
[ -c
.I config-file
-] -m
+] -j
+.I job-id[,N]
+-m
.I mime/type
[ -n
.I copies
@@ -40,6 +42,11 @@
.br
Uses the named cupsd.conf configuration file.
.TP 5
+-j job-id[,N]
+.br
+Converts document N from the specified job. If N is omitted, document 1 is
+converted.
+.TP 5
-m mime/type
.br
Specifies the destination file type.
Index: CHANGES.txt
===================================================================
--- CHANGES.txt (revision 6878)
+++ CHANGES.txt (revision 6879)
@@ -1,8 +1,12 @@
-CHANGES.txt - 2007-08-27
+CHANGES.txt - 2007-08-29
------------------------
CHANGES IN CUPS V1.4b1
+ - The scheduler now supports a CUPS-Get-Document operation
+ that returns the specified print job document (STR #118)
+ - The cupsfilter utility now supports a "-J jobid" option
+ to filter the document from the specified job.
- The scheduler (cupsd) now supports a new option (-t) to
do a syntax check of the cupsd.conf file (STR #2003)
- Added new cupsGetPPD3() API to allow applications to
Index: scheduler/cupsfilter.c
===================================================================
--- scheduler/cupsfilter.c (revision 6878)
+++ scheduler/cupsfilter.c (revision 6879)
@@ -19,6 +19,7 @@
* escape_options() - Convert an options array to a string.
* exec_filter() - Execute a single filter.
* exec_filters() - Execute filters for the given file and options.
+ * get_job_file() - Get the specified job file.
* open_pipe() - Create a pipe which is closed on exec.
* read_cupsd_conf() - Read the cupsd.conf file to get the filter settings.
* set_string() - Copy and set a string.
@@ -35,8 +36,10 @@
#include
#include "mime.h"
#include
+#include
#include
#include
+#include
#include
#if defined(__APPLE__)
# include
@@ -64,6 +67,8 @@
/* CUPS_SERVERROOT environment variable */
static char *RIPCache = NULL;
/* RIP_CACHE environment variable */
+static char TempFile[1024] = "";
+ /* Temporary file */
/*
@@ -79,9 +84,11 @@
const char *printer, const char *user,
const char *title, int num_options,
cups_option_t *options);
+static void get_job_file(const char *job);
static int open_pipe(int *fds);
static int read_cupsd_conf(const char *filename);
static void set_string(char **s, const char *val);
+static void sighandler(int sig);
static void usage(const char *command, const char *opt);
@@ -214,7 +221,21 @@
usage(command, opt);
break;
- case 'j' : /* Specify destination MIME type... */
+ case 'j' : /* Get job file or specify destination MIME type... */
+ if (strcmp(command, "convert"))
+ {
+ i ++;
+ if (i < argc)
+ {
+ get_job_file(argv[i]);
+ infile = TempFile;
+ }
+ else
+ usage(command, opt);
+
+ break;
+ }
+
case 'm' : /* Specify destination MIME type... */
i ++;
if (i < argc)
@@ -405,6 +426,9 @@
* Remove files as needed, then exit...
*/
+ if (TempFile[0])
+ unlink(TempFile);
+
if (removeppd && ppdfile)
unlink(ppdfile);
@@ -811,10 +835,102 @@
/*
+ * 'get_job_file()' - Get the specified job file.
+ */
+
+static void
+get_job_file(const char *job) /* I - Job ID */
+{
+ long jobid, /* Job ID */
+ docnum; /* Document number */
+ const char *jobptr; /* Pointer into job ID string */
+ char uri[1024]; /* job-uri */
+ http_t *http; /* Connection to server */
+ ipp_t *request; /* Request data */
+ int tempfd; /* Temporary file */
+
+
+ /*
+ * Get the job ID and document number, if any...
+ */
+
+ if ((jobptr = strrchr(job, '-')) != NULL)
+ jobptr ++;
+ else
+ jobptr = job;
+
+ jobid = strtol(jobptr, (char **)&jobptr, 10);
+
+ if (*jobptr == ',')
+ docnum = strtol(jobptr + 1, NULL, 10);
+ else
+ docnum = 1;
+
+ if (jobid < 1 || jobid > INT_MAX)
+ {
+ _cupsLangPrintf(stderr, _("cupsfilter: Invalid job ID %d!\n"), (int)jobid);
+ exit(1);
+ }
+
+ if (docnum < 1 || docnum > INT_MAX)
+ {
+ _cupsLangPrintf(stderr, _("cupsfilter: Invalid document number %d!\n"),
+ (int)docnum);
+ exit(1);
+ }
+
+ /*
+ * Ask the server for the document file...
+ */
+
+ if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
+ cupsEncryption())) == NULL)
+ {
+ _cupsLangPrintf(stderr, _("%s: Unable to connect to server\n"),
+ "cupsfilter");
+ exit(1);
+ }
+
+ request = ippNewRequest(CUPS_GET_DOCUMENT);
+
+ snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", (int)jobid);
+
+ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
+ ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "document-number",
+ (int)docnum);
+
+ if ((tempfd = cupsTempFd(TempFile, sizeof(TempFile))) == -1)
+ {
+ _cupsLangPrintf(stderr,
+ _("cupsfilter: Unable to create temporary file: %s\n"),
+ strerror(errno));
+ httpClose(http);
+ exit(1);
+ }
+
+ signal(SIGTERM, sighandler);
+
+ ippDelete(cupsDoIORequest(http, request, "/", -1, tempfd));
+
+ close(tempfd);
+
+ httpClose(http);
+
+ if (cupsLastError() != IPP_OK)
+ {
+ _cupsLangPrintf(stderr, _("cupsfilter: Unable to get job file - %s\n"),
+ cupsLastErrorString());
+ unlink(TempFile);
+ exit(1);
+ }
+}
+
+
+/*
* 'open_pipe()' - Create a pipe which is closed on exec.
*/
-int /* O - 0 on success, -1 on error */
+static int /* O - 0 on success, -1 on error */
open_pipe(int *fds) /* O - Pipe file descriptors (2) */
{
/*
@@ -948,6 +1064,28 @@
/*
+ * 'sighandler()' - Signal catcher for when we print from stdin...
+ */
+
+static void
+sighandler(int s) /* I - Signal number */
+{
+ /*
+ * Remove the temporary file we're using to print a job file...
+ */
+
+ if (TempFile[0])
+ unlink(TempFile);
+
+ /*
+ * Exit...
+ */
+
+ exit(s);
+}
+
+
+/*
* 'usage()' - Show program usage...
*/
@@ -965,6 +1103,7 @@
"Options:\n"
"\n"
" -c cupsd.conf Set cupsd.conf file to use\n"
+ " -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
" -n copies Set number of copies\n"
" -o name=value Set option(s)\n"
" -p filename.ppd Set PPD file\n"
Index: scheduler/conf.c
===================================================================
--- scheduler/conf.c (revision 6878)
+++ scheduler/conf.c (revision 6879)
@@ -958,7 +958,7 @@
"Renew-Subscription Cancel-Subscription "
"Get-Notifications Reprocess-Job Cancel-Current-Job "
"Suspend-Current-Job Resume-Job CUPS-Move-Job "
- "CUPS-Authenticate-Job>");
+ "CUPS-Authenticate-Job CUPS-Get-Document>");
cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow");
po = cupsdAddPolicyOp(p, NULL, IPP_SEND_DOCUMENT);
@@ -986,6 +986,7 @@
cupsdAddPolicyOp(p, po, IPP_RESUME_JOB);
cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB);
cupsdAddPolicyOp(p, po, CUPS_AUTHENTICATE_JOB);
+ cupsdAddPolicyOp(p, po, CUPS_GET_DOCUMENT);
cupsdLogMessage(CUPSD_LOG_INFO, "");
@@ -3245,6 +3246,36 @@
"Missing before on line %d!",
linenum);
+ /*
+ * Verify that we have an explicit policy for CUPS-Get-Document
+ * (ensures that upgrades do not introduce new security issues...)
+ */
+
+ for (i = 0; i < pol->num_ops; i ++)
+ if (pol->ops[i]->op == CUPS_GET_DOCUMENT)
+ break;
+
+ if (i >= pol->num_ops)
+ {
+ for (i = 0; i < pol->num_ops; i ++)
+ if (pol->ops[i]->op == IPP_SEND_DOCUMENT)
+ break;
+
+ if (i < pol->num_ops)
+ {
+ /*
+ * Add a new limit for CUPS-Get-Document using the Send-Document
+ * limit as a template...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_WARN,
+ "No limit for CUPS-Get-Document defined in policy %s "
+ "- using Send-Document's policy", pol->name);
+
+ cupsdAddPolicyOp(pol, pol->ops[i], CUPS_GET_DOCUMENT);
+ }
+ }
+
return (linenum);
}
else if (!strcasecmp(line, "servername, con->serverport, "/jobs/%d",
job->id);
+ if (!ra || cupsArrayFind(ra, "document-count"))
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
+ "document-count", job->num_files);
+
if (!ra || cupsArrayFind(ra, "job-more-info"))
ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI,
"job-more-info", NULL, job_uri);
@@ -5608,6 +5618,150 @@
/*
+ * 'get_document()' - Get a copy of a job file.
+ */
+
+static void
+get_document(cupsd_client_t *con, /* I - Client connection */
+ ipp_attribute_t *uri) /* I - Job URI */
+{
+ http_status_t status; /* Policy status */
+ ipp_attribute_t *attr; /* Current attribute */
+ int jobid; /* Job ID */
+ int docnum; /* Document number */
+ cupsd_job_t *job; /* Current job */
+ char method[HTTP_MAX_URI], /* Method portion of URI */
+ username[HTTP_MAX_URI], /* Username portion of URI */
+ host[HTTP_MAX_URI], /* Host portion of URI */
+ resource[HTTP_MAX_URI]; /* Resource portion of URI */
+ int port; /* Port portion of URI */
+ char filename[1024], /* Filename for document */
+ format[1024]; /* Format for document */
+
+
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", con,
+ con->http.fd, uri->values[0].string.text);
+
+ /*
+ * See if we have a job URI or a printer URI...
+ */
+
+ if (!strcmp(uri->name, "printer-uri"))
+ {
+ /*
+ * Got a printer URI; see if we also have a job-id attribute...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "job-id",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Got a printer-uri attribute but no job-id!"));
+ return;
+ }
+
+ jobid = attr->values[0].integer;
+ }
+ else
+ {
+ /*
+ * Got a job URI; parse it to get the job ID...
+ */
+
+ httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method,
+ sizeof(method), username, sizeof(username), host,
+ sizeof(host), &port, resource, sizeof(resource));
+
+ if (strncmp(resource, "/jobs/", 6))
+ {
+ /*
+ * Not a valid URI!
+ */
+
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Bad job-uri attribute \"%s\"!"),
+ uri->values[0].string.text);
+ return;
+ }
+
+ jobid = atoi(resource + 6);
+ }
+
+ /*
+ * See if the job exists...
+ */
+
+ if ((job = cupsdFindJob(jobid)) == NULL)
+ {
+ /*
+ * Nope - return a "not found" error...
+ */
+
+ send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid);
+ return;
+ }
+
+ /*
+ * Check policy...
+ */
+
+ if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+ {
+ send_http_error(con, status, NULL);
+ return;
+ }
+
+ /*
+ * Get the document number...
+ */
+
+ if ((attr = ippFindAttribute(con->request, "document-number",
+ IPP_TAG_INTEGER)) == NULL)
+ {
+ send_ipp_status(con, IPP_BAD_REQUEST,
+ _("Missing document-number attribute!"));
+ return;
+ }
+
+ if ((docnum = attr->values[0].integer) < 1 || docnum > job->num_files ||
+ attr->num_values > 1)
+ {
+ send_ipp_status(con, IPP_NOT_FOUND, _("Document %d not found in job %d."),
+ docnum, jobid);
+ return;
+ }
+
+ snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, jobid,
+ docnum);
+ if ((con->file = open(filename, O_RDONLY)) == -1)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open document %d in job %d - %s", docnum, jobid,
+ strerror(errno));
+ send_ipp_status(con, IPP_NOT_FOUND,
+ _("Unable to open document %d in job %d!"), docnum, jobid);
+ return;
+ }
+
+ fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+ cupsdLoadJob(job);
+
+ snprintf(format, sizeof(format), "%s/%s", job->filetypes[docnum - 1]->super,
+ job->filetypes[docnum - 1]->type);
+
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
+ NULL, format);
+ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "document-number",
+ docnum);
+ if ((attr = ippFindAttribute(job->attrs, "document-name",
+ IPP_TAG_NAME)) != NULL)
+ ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "document-name",
+ NULL, attr->values[0].string.text);
+}
+
+
+/*
* 'get_job_attrs()' - Get job attributes.
*/
Index: scheduler/printers.c
===================================================================
--- scheduler/printers.c (revision 6878)
+++ scheduler/printers.c (revision 6879)
@@ -321,6 +321,8 @@
CUPS_GET_PPDS,
CUPS_MOVE_JOB,
CUPS_AUTHENTICATE_JOB,
+ CUPS_GET_PPD,
+ CUPS_GET_DOCUMENT,
IPP_RESTART_JOB
};
static const char * const charsets[] =/* charset-supported values */