summaryrefslogtreecommitdiff
path: root/test/ippserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/ippserver.c')
-rw-r--r--test/ippserver.c1285
1 files changed, 1171 insertions, 114 deletions
diff --git a/test/ippserver.c b/test/ippserver.c
index fc10d52b9..23880a14b 100644
--- a/test/ippserver.c
+++ b/test/ippserver.c
@@ -1,5 +1,5 @@
/*
- * "$Id: ippserver.c 9793 2011-05-20 03:49:49Z mike $"
+ * "$Id: ippserver.c 10031 2011-09-30 05:24:10Z mike $"
*
* Sample IPP/2.0 server for CUPS.
*
@@ -15,54 +15,62 @@
*
* Contents:
*
- * main() - Main entry to the sample server.
- * clean_jobs() - Clean out old (completed) jobs.
- * compare_jobs() - Compare two jobs.
- * copy_attribute() - Copy a single attribute.
- * copy_attributes() - Copy attributes from one request to another.
- * copy_job_attrs() - Copy job attributes to the response.
- * create_client() - Accept a new network connection and create a
- * client object.
- * create_job() - Create a new job object from a Print-Job or
- * Create-Job request.
- * create_listener() - Create a listener socket.
- * create_media_col() - Create a media-col value.
- * create_printer() - Create, register, and listen for connections
- * to a printer object.
- * create_requested_array() - Create an array for requested-attributes.
- * debug_attributes() - Print attributes in a request or response.
- * delete_client() - Close the socket and free all memory used by
- * a client object.
- * delete_job() - Remove from the printer and free all memory
- * used by a job object.
- * delete_printer() - Unregister, close listen sockets, and free
- * all memory used by a printer object.
- * dnssd_callback() - Handle Bonjour registration events.
- * find_job() - Find a job specified in a request.
- * html_escape() - Write a HTML-safe string.
- * html_printf() - Send formatted text to the client, quoting
- * as needed.
- * ipp_cancel_job() - Cancel a job.
- * ipp_create_job() - Create a job object.
- * ipp_get_job_attributes() - Get the attributes for a job object.
- * ipp_get_jobs() - Get a list of job objects.
+ * main() - Main entry to the sample server.
+ * clean_jobs() - Clean out old (completed) jobs.
+ * compare_jobs() - Compare two jobs.
+ * copy_attribute() - Copy a single attribute.
+ * copy_attributes() - Copy attributes from one request to
+ * another.
+ * copy_job_attrs() - Copy job attributes to the response.
+ * create_client() - Accept a new network connection and create
+ * a client object.
+ * create_job() - Create a new job object from a Print-Job or
+ * Create-Job request.
+ * create_listener() - Create a listener socket.
+ * create_media_col() - Create a media-col value.
+ * create_printer() - Create, register, and listen for
+ * connections to a printer object.
+ * create_requested_array() - Create an array for requested-attributes.
+ * debug_attributes() - Print attributes in a request or response.
+ * delete_client() - Close the socket and free all memory used
+ * by a client object.
+ * delete_job() - Remove from the printer and free all memory
+ * used by a job object.
+ * delete_printer() - Unregister, close listen sockets, and free
+ * all memory used by a printer object.
+ * dnssd_callback() - Handle Bonjour registration events.
+ * find_job() - Find a job specified in a request.
+ * html_escape() - Write a HTML-safe string.
+ * html_printf() - Send formatted text to the client, quoting
+ * as needed.
+ * ipp_cancel_job() - Cancel a job.
+ * ipp_create_job() - Create a job object.
+ * ipp_get_job_attributes() - Get the attributes for a job object.
+ * ipp_get_jobs() - Get a list of job objects.
* ipp_get_printer_attributes() - Get the attributes for a printer object.
- * ipp_print_job() - Create a job object with an attached
- * document.
- * ipp_send_document() - Add an attached document to a job object
- * created with Create-Job.
- * ipp_validate_job() - Validate job creation attributes.
- * process_client() - Process client requests on a thread.
- * process_http() - Process a HTTP request.
- * process_ipp() - Process an IPP request.
- * process_job() - Process a print job.
- * register_printer() - Register a printer object via Bonjour.
- * respond_http() - Send a HTTP response.
- * respond_ipp() - Send an IPP response.
- * run_printer() - Run the printer service.
- * usage() - Show program usage.
- * valid_job_attributes() - Determine whether the job attributes are
- * valid.
+ * ipp_print_job() - Create a job object with an attached
+ * document.
+ * ipp_print_uri() - Create a job object with a referenced
+ * document.
+ * ipp_send_document() - Add an attached document to a job object
+ * created with Create-Job.
+ * ipp_send_uri() - Add a referenced document to a job object
+ * created with Create-Job.
+ * ipp_validate_job() - Validate job creation attributes.
+ * process_client() - Process client requests on a thread.
+ * process_http() - Process a HTTP request.
+ * process_ipp() - Process an IPP request.
+ * process_job() - Process a print job.
+ * register_printer() - Register a printer object via Bonjour.
+ * respond_http() - Send a HTTP response.
+ * respond_ipp() - Send an IPP response.
+ * respond_unsupported() - Respond with an unsupported attribute.
+ * run_printer() - Run the printer service.
+ * usage() - Show program usage.
+ * valid_doc_attributes() - Determine whether the document attributes
+ * are valid.
+ * valid_job_attributes() - Determine whether the job attributes are
+ * valid.
*/
/*
@@ -140,7 +148,7 @@ static const char * const media_supported[] =
"na_index-3x5_3x5in", /* 3x5 */
"oe_photo-l_3.5x5in", /* L */
"na_index-4x6_4x6in", /* 4x6 */
- "na_5x7_5x7in" /* 5x7 */
+ "na_5x7_5x7in" /* 5x7 aka 2L */
};
static const int media_col_sizes[][3] =
{ /* media-col-database sizes */
@@ -154,7 +162,7 @@ static const int media_col_sizes[][3] =
{ 7630, 12700, _IPP_PHOTO_ONLY }, /* 3x5 */
{ 8890, 12700, _IPP_PHOTO_ONLY }, /* L */
{ 10160, 15240, _IPP_PHOTO_ONLY }, /* 4x6 */
- { 12700, 17780, _IPP_PHOTO_ONLY } /* 5x7 */
+ { 12700, 17780, _IPP_PHOTO_ONLY } /* 5x7 aka 2L */
};
static const char * const media_type_supported[] =
/* media-type-supported values */
@@ -257,6 +265,7 @@ static _ipp_job_t *create_job(_ipp_client_t *client);
static int create_listener(int family, int *port);
static ipp_t *create_media_col(const char *media, const char *type,
int width, int length, int margins);
+static ipp_t *create_media_size(int width, int length);
static _ipp_printer_t *create_printer(const char *servername,
const char *name, const char *location,
const char *make, const char *model,
@@ -268,7 +277,8 @@ static _ipp_printer_t *create_printer(const char *servername,
#endif /* HAVE_DNSSD */
const char *directory);
static cups_array_t *create_requested_array(_ipp_client_t *client);
-static void debug_attributes(const char *title, ipp_t *ipp);
+static void debug_attributes(const char *title, ipp_t *ipp,
+ int response);
static void delete_client(_ipp_client_t *client);
static void delete_job(_ipp_job_t *job);
static void delete_printer(_ipp_printer_t *printer);
@@ -285,22 +295,17 @@ static _ipp_job_t *find_job(_ipp_client_t *client);
static void html_escape(_ipp_client_t *client, const char *s,
size_t slen);
static void html_printf(_ipp_client_t *client, const char *format,
- ...)
-# ifdef __GNUC__
-__attribute__ ((__format__ (__printf__, 2, 3)))
-# endif /* __GNUC__ */
-;
+ ...) __attribute__((__format__(__printf__,
+ 2, 3)));
static void ipp_cancel_job(_ipp_client_t *client);
-#if 0
static void ipp_create_job(_ipp_client_t *client);
-#endif /* 0 */
static void ipp_get_job_attributes(_ipp_client_t *client);
static void ipp_get_jobs(_ipp_client_t *client);
static void ipp_get_printer_attributes(_ipp_client_t *client);
static void ipp_print_job(_ipp_client_t *client);
-#if 0
+static void ipp_print_uri(_ipp_client_t *client);
static void ipp_send_document(_ipp_client_t *client);
-#endif /* 0 */
+static void ipp_send_uri(_ipp_client_t *client);
static void ipp_validate_job(_ipp_client_t *client);
static void *process_client(_ipp_client_t *client);
static int process_http(_ipp_client_t *client);
@@ -317,12 +322,12 @@ static int respond_http(_ipp_client_t *client, http_status_t code,
const char *type, size_t length);
static void respond_ipp(_ipp_client_t *client, ipp_status_t status,
const char *message, ...)
-#ifdef __GNUC__
-__attribute__ ((__format__ (__printf__, 3, 4)))
-#endif /* __GNUC__ */
-;
+ __attribute__ ((__format__ (__printf__, 3, 4)));
+static void respond_unsupported(_ipp_client_t *client,
+ ipp_attribute_t *attr);
static void run_printer(_ipp_printer_t *printer);
-static void usage(int status);
+static void usage(int status) __attribute__((noreturn));
+static int valid_doc_attributes(_ipp_client_t *client);
static int valid_job_attributes(_ipp_client_t *client);
@@ -799,7 +804,7 @@ copy_job_attributes(
_ipp_job_t *job, /* I - Job */
cups_array_t *ra) /* I - requested-attributes */
{
- copy_attributes(client->response, job->attrs, ra, IPP_TAG_ZERO, 0);
+ copy_attributes(client->response, job->attrs, ra, IPP_TAG_JOB, 0);
if (!ra || cupsArrayFind(ra, "job-printer-up-time"))
ippAddInteger(client->response, IPP_TAG_JOB, IPP_TAG_INTEGER,
@@ -828,6 +833,10 @@ copy_job_attributes(
ippAddString(client->response, IPP_TAG_JOB,
IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
NULL, "job-hold-until-specified");
+ else
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ NULL, "job-data-insufficient");
break;
case IPP_JOB_PROCESSING :
@@ -899,10 +908,11 @@ create_client(_ipp_printer_t *printer, /* I - Printer */
return (NULL);
}
- client->printer = printer;
- client->http.activity = time(NULL);
- client->http.hostaddr = &(client->addr);
- client->http.blocking = 1;
+ client->printer = printer;
+ client->http.activity = time(NULL);
+ client->http.hostaddr = &(client->addr);
+ client->http.blocking = 1;
+ client->http.wait_value = 60000;
/*
* Accept the client and get the remote address...
@@ -1115,15 +1125,11 @@ create_media_col(const char *media, /* I - Media name */
int margins) /* I - Value for margins */
{
ipp_t *media_col = ippNew(), /* media-col value */
- *media_size = ippNew(); /* media-size value */
+ *media_size = create_media_size(width, length);
+ /* media-size value */
char media_key[256]; /* media-key value */
- ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension",
- width);
- ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension",
- length);
-
snprintf(media_key, sizeof(media_key), "%s_%s%s", media, type,
margins == 0 ? "_borderless" : "");
@@ -1148,6 +1154,26 @@ create_media_col(const char *media, /* I - Media name */
/*
+ * 'create_media_size()' - Create a media-size value.
+ */
+
+static ipp_t * /* O - media-col collection */
+create_media_size(int width, /* I - x-dimension in 2540ths */
+ int length) /* I - y-dimension in 2540ths */
+{
+ ipp_t *media_size = ippNew(); /* media-size value */
+
+
+ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension",
+ width);
+ ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension",
+ length);
+
+ return (media_size);
+}
+
+
+/*
* 'create_printer()' - Create, register, and listen for connections to a
* printer object.
*/
@@ -1183,8 +1209,10 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
*ptr; /* Pointer into string */
const char *prefix; /* Prefix string */
int num_database; /* Number of database values */
- ipp_attribute_t *media_col_database;
+ ipp_attribute_t *media_col_database,
/* media-col-database value */
+ *media_size_supported;
+ /* media-size-supported value */
ipp_t *media_col_default;
/* media-col-default value */
ipp_value_t *media_col_value;
@@ -1213,9 +1241,11 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
static const int ops[] = /* operations-supported values */
{
IPP_PRINT_JOB,
+ IPP_PRINT_URI,
IPP_VALIDATE_JOB,
IPP_CREATE_JOB,
IPP_SEND_DOCUMENT,
+ IPP_SEND_URI,
IPP_CANCEL_JOB,
IPP_GET_JOB_ATTRIBUTES,
IPP_GET_JOBS,
@@ -1264,6 +1294,15 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
IPP_QUALITY_NORMAL,
IPP_QUALITY_HIGH
};
+ static const char * const reference_uri_schemes_supported[] =
+ { /* reference-uri-schemes-supported */
+ "file",
+ "ftp",
+ "http"
+#ifdef HAVE_SSL
+ , "https"
+#endif /* HAVE_SSL */
+ };
static const char * const sides_supported[] =
{ /* sides-supported values */
"one-sided",
@@ -1605,6 +1644,18 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
(int)(sizeof(media_supported) / sizeof(media_supported[0])),
NULL, media_supported);
+ /* media-size-supported */
+ media_size_supported = ippAddCollections(printer->attrs, IPP_TAG_PRINTER,
+ "media-size-supported",
+ (int)(sizeof(media_col_sizes) /
+ sizeof(media_col_sizes[0])),
+ NULL);
+ for (i = 0;
+ i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0]));
+ i ++)
+ media_size_supported->values[i].collection =
+ create_media_size(media_col_sizes[i][0], media_col_sizes[i][1]);
+
/* media-top-margin-supported */
ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"media-top-margin-supported",
@@ -1612,6 +1663,13 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
sizeof(media_xxx_margin_supported[0])),
media_xxx_margin_supported);
+ /* media-type-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ "media-type-supported",
+ (int)(sizeof(media_type_supported) /
+ sizeof(media_type_supported[0])),
+ NULL, media_type_supported);
+
/* multiple-document-handling-supported */
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"multiple-document-handling-supported",
@@ -1723,6 +1781,14 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
"printer-uri-supported", NULL, uri);
+ /* reference-uri-scheme-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_TAG_URISCHEME | IPP_TAG_COPY,
+ "reference-uri-schemes-supported",
+ (int)(sizeof(reference_uri_schemes_supported) /
+ sizeof(reference_uri_schemes_supported[0])),
+ NULL, reference_uri_schemes_supported);
+
/* sides-default */
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
"sides-default", NULL, "one-sided");
@@ -1746,7 +1812,7 @@ create_printer(const char *servername, /* I - Server hostname (NULL for default)
free(formats[0]);
- debug_attributes("Printer", printer->attrs);
+ debug_attributes("Printer", printer->attrs, 0);
#ifdef HAVE_DNSSD
/*
@@ -1984,7 +2050,8 @@ create_requested_array(
static void
debug_attributes(const char *title, /* I - Title */
- ipp_t *ipp) /* I - Request/response */
+ ipp_t *ipp, /* I - Request/response */
+ int type) /* I - 0 = object, 1 = request, 2 = response */
{
ipp_tag_t group_tag; /* Current group */
ipp_attribute_t *attr; /* Current attribute */
@@ -1995,6 +2062,18 @@ debug_attributes(const char *title, /* I - Title */
return;
fprintf(stderr, "%s:\n", title);
+ fprintf(stderr, " version=%d.%d\n", ipp->request.any.version[0],
+ ipp->request.any.version[1]);
+ if (type == 1)
+ fprintf(stderr, " operation-id=%s(%04x)\n",
+ ippOpString(ipp->request.op.operation_id),
+ ipp->request.op.operation_id);
+ else if (type == 2)
+ fprintf(stderr, " status-code=%s(%04x)\n",
+ ippErrorString(ipp->request.status.status_code),
+ ipp->request.status.status_code);
+ fprintf(stderr, " request-id=%d\n\n", ipp->request.any.request_id);
+
for (attr = ipp->attrs, group_tag = IPP_TAG_ZERO; attr; attr = attr->next)
{
if (attr->group_tag != group_tag)
@@ -2467,7 +2546,10 @@ ipp_cancel_job(_ipp_client_t *client) /* I - Client */
*/
if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "Job does not exist.");
return;
+ }
/*
* See if the job is already completed, canceled, or aborted; if so,
@@ -2515,7 +2597,6 @@ ipp_cancel_job(_ipp_client_t *client) /* I - Client */
}
-#if 0
/*
* 'ipp_create_job()' - Create a job object.
*/
@@ -2523,8 +2604,56 @@ ipp_cancel_job(_ipp_client_t *client) /* I - Client */
static void
ipp_create_job(_ipp_client_t *client) /* I - Client */
{
+ _ipp_job_t *job; /* New job */
+ cups_array_t *ra; /* Attributes to send in response */
+
+
+ /*
+ * Validate print job attributes...
+ */
+
+ if (!valid_job_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (client->http.state == HTTP_POST_RECV)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Unexpected document data following request.");
+ return;
+ }
+
+ /*
+ * Create the job...
+ */
+
+ if ((job = create_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_PRINTER_BUSY, "Currently printing another job.");
+ return;
+ }
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
}
-#endif /* 0 */
/*
@@ -2966,6 +3095,7 @@ ipp_print_job(_ipp_client_t *client) /* I - Client */
* Process the job...
*/
+#if 0
if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
{
job->state = IPP_JOB_ABORTED;
@@ -2973,6 +3103,10 @@ ipp_print_job(_ipp_client_t *client) /* I - Client */
return;
}
+#else
+ process_job(job);
+#endif /* 0 */
+
/*
* Return the job info...
*/
@@ -2990,7 +3124,314 @@ ipp_print_job(_ipp_client_t *client) /* I - Client */
}
+/*
+ * 'ipp_print_uri()' - Create a job object with a referenced document.
+ */
+
+static void
+ipp_print_uri(_ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* New job */
+ ipp_attribute_t *uri; /* document-uri */
+ char scheme[256], /* URI scheme */
+ userpass[256], /* Username and password info */
+ hostname[256], /* Hostname */
+ resource[1024]; /* Resource path */
+ int port; /* Port number */
+ http_uri_status_t uri_status; /* URI decode status */
+ http_encryption_t encryption; /* Encryption to use, if any */
+ http_t *http; /* Connection for http/https URIs */
+ http_status_t status; /* Access status for http/https URIs */
+ int infile; /* Input file for local file URIs */
+ char filename[1024], /* Filename buffer */
+ buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read */
+ cups_array_t *ra; /* Attributes to send in response */
+ static const char * const uri_status_strings[] =
+ { /* URI decode errors */
+ "URI too large.",
+ "Bad arguments to function.",
+ "Bad resource in URI.",
+ "Bad port number in URI.",
+ "Bad hostname in URI.",
+ "Bad username in URI.",
+ "Bad scheme in URI.",
+ "Bad/empty URI."
+ };
+
+
+ /*
+ * Validate print job attributes...
+ */
+
+ if (!valid_job_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (client->http.state == HTTP_POST_RECV)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Unexpected document data following request.");
+ return;
+ }
+
+ /*
+ * Do we have a document URI?
+ */
+
+ if ((uri = ippFindAttribute(client->request, "document-uri",
+ IPP_TAG_URI)) == NULL)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Missing document-uri.");
+ return;
+ }
+
+ if (uri->num_values != 1)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Too many document-uri values.");
+ return;
+ }
+
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text,
+ scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+ if (uri_status < HTTP_URI_OK)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Bad document-uri: %s",
+ uri_status_strings[uri_status - HTTP_URI_OVERFLOW]);
+ return;
+ }
+
+ if (strcmp(scheme, "file") &&
+#ifdef HAVE_SSL
+ strcmp(scheme, "https") &&
+#endif /* HAVE_SSL */
+ strcmp(scheme, "http"))
+ {
+ respond_ipp(client, IPP_URI_SCHEME, "URI scheme \"%s\" not supported.",
+ scheme);
+ return;
+ }
+
+ if (!strcmp(scheme, "file") && access(resource, R_OK))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
+
+ /*
+ * Print the job...
+ */
+
+ if ((job = create_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_PRINTER_BUSY, "Currently printing another job.");
+ return;
+ }
+
+ /*
+ * Create a file for the request data...
+ */
+
+ if (!_cups_strcasecmp(job->format, "image/jpeg"))
+ snprintf(filename, sizeof(filename), "%s/%d.jpg",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "image/png"))
+ snprintf(filename, sizeof(filename), "%s/%d.png",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/pdf"))
+ snprintf(filename, sizeof(filename), "%s/%d.pdf",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/postscript"))
+ snprintf(filename, sizeof(filename), "%s/%d.ps",
+ client->printer->directory, job->id);
+ else
+ snprintf(filename, sizeof(filename), "%s/%d.prn",
+ client->printer->directory, job->id);
+
+ if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
+ {
+ job->state = IPP_JOB_ABORTED;
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ if (!strcmp(scheme, "file"))
+ {
+ if ((infile = open(resource, O_RDONLY)) < 0)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
+
+ do
+ {
+ if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 &&
+ (errno == EAGAIN || errno == EINTR))
+ bytes = 1;
+ else if (bytes > 0 && write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ close(infile);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+ while (bytes > 0);
+
+ close(infile);
+ }
+ else
+ {
+#ifdef HAVE_SSL
+ if (port == 443 || !strcmp(scheme, "https"))
+ encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+#endif /* HAVE_SSL */
+ encryption = HTTP_ENCRYPT_IF_REQUESTED;
+
+ if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR,
+ "Unable to connect to %s: %s", hostname,
+ cupsLastErrorString());
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ return;
+ }
+
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
+ if (httpGet(http, resource))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to GET URI: %s",
+ strerror(errno));
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status != HTTP_OK)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to GET URI: %s",
+ httpStatus(status));
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ httpClose(http);
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
+ strerror(error));
+ return;
+ }
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JOB_PENDING;
+
+ /*
+ * Process the job...
+ */
+
#if 0
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JOB_ABORTED;
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to process job.");
+ return;
+ }
+
+#else
+ process_job(job);
+#endif /* 0 */
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
+}
+
+
/*
* 'ipp_send_document()' - Add an attached document to a job object created with
* Create-Job.
@@ -2999,9 +3440,571 @@ ipp_print_job(_ipp_client_t *client) /* I - Client */
static void
ipp_send_document(_ipp_client_t *client)/* I - Client */
{
+ _ipp_job_t *job; /* Job information */
+ char filename[1024], /* Filename buffer */
+ buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_array_t *ra; /* Attributes to send in response */
+
+
+ /*
+ * Get the job...
+ */
+
+ if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "Job does not exist.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * See if we already have a document for this job or the job has already
+ * in a non-pending state...
+ */
+
+ if (job->state > IPP_JOB_HELD)
+ {
+ respond_ipp(client, IPP_NOT_POSSIBLE, "Job is not in a pending state.");
+ httpFlush(&(client->http));
+ return;
+ }
+ else if (job->filename || job->fd >= 0)
+ {
+ respond_ipp(client, IPP_MULTIPLE_JOBS_NOT_SUPPORTED,
+ "Multiple document jobs are not supported.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ if ((attr = ippFindAttribute(client->request, "last-document",
+ IPP_TAG_ZERO)) == NULL)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Missing required last-document attribute.");
+ httpFlush(&(client->http));
+ return;
+ }
+ else if (attr->value_tag != IPP_TAG_BOOLEAN || attr->num_values != 1 ||
+ !attr->values[0].boolean)
+ {
+ respond_unsupported(client, attr);
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Validate document attributes...
+ */
+
+ if (!valid_doc_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Get the document format for the job...
+ */
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ if ((attr = ippFindAttribute(job->attrs, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ job->format = attr->values[0].string.text;
+ else
+ job->format = "application/octet-stream";
+
+ /*
+ * Create a file for the request data...
+ */
+
+ if (!_cups_strcasecmp(job->format, "image/jpeg"))
+ snprintf(filename, sizeof(filename), "%s/%d.jpg",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "image/png"))
+ snprintf(filename, sizeof(filename), "%s/%d.png",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/pdf"))
+ snprintf(filename, sizeof(filename), "%s/%d.pdf",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/postscript"))
+ snprintf(filename, sizeof(filename), "%s/%d.ps",
+ client->printer->directory, job->id);
+ else
+ snprintf(filename, sizeof(filename), "%s/%d.prn",
+ client->printer->directory, job->id);
+
+ job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ if (job->fd < 0)
+ {
+ job->state = IPP_JOB_ABORTED;
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ while ((bytes = httpRead2(&(client->http), buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ if (bytes < 0)
+ {
+ /*
+ * Got an error while reading the print data, so abort this job.
+ */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to read print file.");
+ return;
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
+ strerror(error));
+ return;
+ }
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JOB_PENDING;
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ /*
+ * Process the job...
+ */
+
+#if 0
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JOB_ABORTED;
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to process job.");
+ return;
+ }
+
+#else
+ process_job(job);
+#endif /* 0 */
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
}
+
+
+/*
+ * 'ipp_send_uri()' - Add a referenced document to a job object created with
+ * Create-Job.
+ */
+
+static void
+ipp_send_uri(_ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* Job information */
+ ipp_attribute_t *uri; /* document-uri */
+ char scheme[256], /* URI scheme */
+ userpass[256], /* Username and password info */
+ hostname[256], /* Hostname */
+ resource[1024]; /* Resource path */
+ int port; /* Port number */
+ http_uri_status_t uri_status; /* URI decode status */
+ http_encryption_t encryption; /* Encryption to use, if any */
+ http_t *http; /* Connection for http/https URIs */
+ http_status_t status; /* Access status for http/https URIs */
+ int infile; /* Input file for local file URIs */
+ char filename[1024], /* Filename buffer */
+ buffer[4096]; /* Copy buffer */
+ ssize_t bytes; /* Bytes read */
+ ipp_attribute_t *attr; /* Current attribute */
+ cups_array_t *ra; /* Attributes to send in response */
+ static const char * const uri_status_strings[] =
+ { /* URI decode errors */
+ "URI too large.",
+ "Bad arguments to function.",
+ "Bad resource in URI.",
+ "Bad port number in URI.",
+ "Bad hostname in URI.",
+ "Bad username in URI.",
+ "Bad scheme in URI.",
+ "Bad/empty URI."
+ };
+
+
+ /*
+ * Get the job...
+ */
+
+ if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_NOT_FOUND, "Job does not exist.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * See if we already have a document for this job or the job has already
+ * in a non-pending state...
+ */
+
+ if (job->state > IPP_JOB_HELD)
+ {
+ respond_ipp(client, IPP_NOT_POSSIBLE, "Job is not in a pending state.");
+ httpFlush(&(client->http));
+ return;
+ }
+ else if (job->filename || job->fd >= 0)
+ {
+ respond_ipp(client, IPP_MULTIPLE_JOBS_NOT_SUPPORTED,
+ "Multiple document jobs are not supported.");
+ httpFlush(&(client->http));
+ return;
+ }
+
+ if ((attr = ippFindAttribute(client->request, "last-document",
+ IPP_TAG_ZERO)) == NULL)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Missing required last-document attribute.");
+ httpFlush(&(client->http));
+ return;
+ }
+ else if (attr->value_tag != IPP_TAG_BOOLEAN || attr->num_values != 1 ||
+ !attr->values[0].boolean)
+ {
+ respond_unsupported(client, attr);
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Validate document attributes...
+ */
+
+ if (!valid_doc_attributes(client))
+ {
+ httpFlush(&(client->http));
+ return;
+ }
+
+ /*
+ * Do we have a file to print?
+ */
+
+ if (client->http.state == HTTP_POST_RECV)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST,
+ "Unexpected document data following request.");
+ return;
+ }
+
+ /*
+ * Do we have a document URI?
+ */
+
+ if ((uri = ippFindAttribute(client->request, "document-uri",
+ IPP_TAG_URI)) == NULL)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Missing document-uri.");
+ return;
+ }
+
+ if (uri->num_values != 1)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Too many document-uri values.");
+ return;
+ }
+
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text,
+ scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+ if (uri_status < HTTP_URI_OK)
+ {
+ respond_ipp(client, IPP_BAD_REQUEST, "Bad document-uri: %s",
+ uri_status_strings[uri_status - HTTP_URI_OVERFLOW]);
+ return;
+ }
+
+ if (strcmp(scheme, "file") &&
+#ifdef HAVE_SSL
+ strcmp(scheme, "https") &&
+#endif /* HAVE_SSL */
+ strcmp(scheme, "http"))
+ {
+ respond_ipp(client, IPP_URI_SCHEME, "URI scheme \"%s\" not supported.",
+ scheme);
+ return;
+ }
+
+ if (!strcmp(scheme, "file") && access(resource, R_OK))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
+
+ /*
+ * Get the document format for the job...
+ */
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ if ((attr = ippFindAttribute(job->attrs, "document-format",
+ IPP_TAG_MIMETYPE)) != NULL)
+ job->format = attr->values[0].string.text;
+ else
+ job->format = "application/octet-stream";
+
+ /*
+ * Create a file for the request data...
+ */
+
+ if (!_cups_strcasecmp(job->format, "image/jpeg"))
+ snprintf(filename, sizeof(filename), "%s/%d.jpg",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "image/png"))
+ snprintf(filename, sizeof(filename), "%s/%d.png",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/pdf"))
+ snprintf(filename, sizeof(filename), "%s/%d.pdf",
+ client->printer->directory, job->id);
+ else if (!_cups_strcasecmp(job->format, "application/postscript"))
+ snprintf(filename, sizeof(filename), "%s/%d.ps",
+ client->printer->directory, job->id);
+ else
+ snprintf(filename, sizeof(filename), "%s/%d.prn",
+ client->printer->directory, job->id);
+
+ job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ if (job->fd < 0)
+ {
+ job->state = IPP_JOB_ABORTED;
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ if (!strcmp(scheme, "file"))
+ {
+ if ((infile = open(resource, O_RDONLY)) < 0)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to access URI: %s",
+ strerror(errno));
+ return;
+ }
+
+ do
+ {
+ if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 &&
+ (errno == EAGAIN || errno == EINTR))
+ bytes = 1;
+ else if (bytes > 0 && write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ close(infile);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+ while (bytes > 0);
+
+ close(infile);
+ }
+ else
+ {
+#ifdef HAVE_SSL
+ if (port == 443 || !strcmp(scheme, "https"))
+ encryption = HTTP_ENCRYPT_ALWAYS;
+ else
+#endif /* HAVE_SSL */
+ encryption = HTTP_ENCRYPT_IF_REQUESTED;
+
+ if ((http = httpConnectEncrypt(hostname, port, encryption)) == NULL)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR,
+ "Unable to connect to %s: %s", hostname,
+ cupsLastErrorString());
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ return;
+ }
+
+ httpClearFields(http);
+ httpSetField(http, HTTP_FIELD_ACCEPT_LANGUAGE, "en");
+ if (httpGet(http, resource))
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to GET URI: %s",
+ strerror(errno));
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((status = httpUpdate(http)) == HTTP_CONTINUE);
+
+ if (status != HTTP_OK)
+ {
+ respond_ipp(client, IPP_DOCUMENT_ACCESS_ERROR, "Unable to GET URI: %s",
+ httpStatus(status));
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((bytes = httpRead2(http, buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ httpClose(http);
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JOB_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
+ strerror(error));
+ return;
+ }
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JOB_PENDING;
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ /*
+ * Process the job...
+ */
+
+#if 0
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JOB_ABORTED;
+ respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to process job.");
+ return;
+ }
+
+#else
+ process_job(job);
#endif /* 0 */
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_OK, NULL);
+
+ ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+ cupsArrayAdd(ra, "job-id");
+ cupsArrayAdd(ra, "job-state");
+ cupsArrayAdd(ra, "job-state-reasons");
+ cupsArrayAdd(ra, "job-uri");
+
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
+}
+
/*
* 'ipp_validate_job()' - Validate job creation attributes.
@@ -3010,6 +4013,8 @@ ipp_send_document(_ipp_client_t *client)/* I - Client */
static void
ipp_validate_job(_ipp_client_t *client) /* I - Client */
{
+ if (valid_job_attributes(client))
+ respond_ipp(client, IPP_OK, NULL);
}
@@ -3381,7 +4386,7 @@ process_http(_ipp_client_t *client) /* I - Client connection */
if (state == IPP_ERROR)
{
fprintf(stderr, "%s IPP read error (%s).\n", client->http.hostname,
- ippOpString(client->request->request.op.operation_id));
+ cupsLastErrorString());
respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
return (0);
}
@@ -3414,7 +4419,7 @@ process_ipp(_ipp_client_t *client) /* I - Client */
ipp_attribute_t *uri; /* Printer URI attribute */
- debug_attributes("Request", client->request);
+ debug_attributes("Request", client->request, 1);
/*
* First build an empty response message for this request...
@@ -3571,10 +4576,26 @@ process_ipp(_ipp_client_t *client) /* I - Client */
ipp_print_job(client);
break;
+ case IPP_PRINT_URI :
+ ipp_print_uri(client);
+ break;
+
case IPP_VALIDATE_JOB :
ipp_validate_job(client);
break;
+ case IPP_CREATE_JOB :
+ ipp_create_job(client);
+ break;
+
+ case IPP_SEND_DOCUMENT :
+ ipp_send_document(client);
+ break;
+
+ case IPP_SEND_URI :
+ ipp_send_uri(client);
+ break;
+
case IPP_CANCEL_JOB :
ipp_cancel_job(client);
break;
@@ -3885,7 +4906,7 @@ respond_http(_ipp_client_t *client, /* I - Client */
* Send an IPP response...
*/
- debug_attributes("Response", client->response);
+ debug_attributes("Response", client->response, 2);
client->http.data_encoding = HTTP_ENCODE_LENGTH;
client->http.data_remaining = (off_t)ippLength(client->response);
@@ -3949,6 +4970,24 @@ respond_ipp(_ipp_client_t *client, /* I - Client */
/*
+ * 'respond_unsupported()' - Respond with an unsupported attribute.
+ */
+
+static void
+respond_unsupported(
+ _ipp_client_t *client, /* I - Client */
+ ipp_attribute_t *attr) /* I - Atribute */
+{
+ if (!client->response->attrs)
+ respond_ipp(client, IPP_ATTRIBUTES, "Unsupported %s %s%s value.",
+ attr->name, attr->num_values > 1 ? "1setOf " : "",
+ ippTagString(attr->value_tag));
+
+ copy_attribute(client->response, attr, IPP_TAG_UNSUPPORTED_GROUP, 0);
+}
+
+
+/*
* 'run_printer()' - Run the printer service.
*/
@@ -4070,37 +5109,27 @@ usage(int status) /* O - Exit status */
/*
- * 'valid_job_attributes()' - Determine whether the job attributes are valid.
+ * 'valid_doc_attributes()' - Determine whether the document attributes are
+ * valid.
*
- * When one or more job attributes are invalid, this function adds a suitable
- * response and attributes to the unsupported group.
+ * When one or more document attributes are invalid, this function adds a
+ * suitable response and attributes to the unsupported group.
*/
static int /* O - 1 if valid, 0 if not */
-valid_job_attributes(
+valid_doc_attributes(
_ipp_client_t *client) /* I - Client */
{
int i; /* Looping var */
ipp_attribute_t *attr, /* Current attribute */
*supported; /* document-format-supported */
const char *format = NULL; /* document-format value */
- int valid = 1; /* Valid attributes? */
/*
* Check operation attributes...
*/
-#define respond_unsupported(client, attr) \
- if (valid) \
- { \
- respond_ipp(client, IPP_ATTRIBUTES, "Unsupported %s %s%s value.", \
- attr->name, attr->num_values > 1 ? "1setOf " : "", \
- ippTagString(attr->value_tag)); \
- valid = 0; \
- } \
- copy_attribute(client->response, attr, IPP_TAG_UNSUPPORTED_GROUP, 0)
-
if ((attr = ippFindAttribute(client->request, "compression",
IPP_TAG_ZERO)) != NULL)
{
@@ -4110,12 +5139,12 @@ valid_job_attributes(
if (attr->num_values != 1 || attr->value_tag != IPP_TAG_KEYWORD ||
strcmp(attr->values[0].string.text, "none"))
- {
respond_unsupported(client, attr);
- }
else
- fprintf(stderr, "%s Print-Job compression=\"%s\"\n",
- client->http.hostname, attr->values[0].string.text);
+ fprintf(stderr, "%s %s compression=\"%s\"\n",
+ client->http.hostname,
+ ippOpString(client->request->request.op.operation_id),
+ attr->values[0].string.text);
}
/*
@@ -4126,9 +5155,7 @@ valid_job_attributes(
IPP_TAG_ZERO)) != NULL)
{
if (attr->num_values != 1 || attr->value_tag != IPP_TAG_MIMETYPE)
- {
respond_unsupported(client, attr);
- }
else
{
format = attr->values[0].string.text;
@@ -4142,7 +5169,8 @@ valid_job_attributes(
format = "application/octet-stream";
if (!strcmp(format, "application/octet-stream") &&
- client->request->request.op.operation_id != IPP_VALIDATE_JOB)
+ (client->request->request.op.operation_id == IPP_PRINT_JOB ||
+ client->request->request.op.operation_id == IPP_SEND_DOCUMENT))
{
/*
* Auto-type the file using the first 4 bytes of the file...
@@ -4169,8 +5197,8 @@ valid_job_attributes(
ippOpString(client->request->request.op.operation_id), format);
if (!attr)
- ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
- "document-format", NULL, format);
+ attr = ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format);
else
{
_cupsStrFree(attr->values[0].string.text);
@@ -4178,7 +5206,8 @@ valid_job_attributes(
}
}
- if ((supported = ippFindAttribute(client->printer->attrs,
+ if (client->request->request.op.operation_id != IPP_CREATE_JOB &&
+ (supported = ippFindAttribute(client->printer->attrs,
"document-format-supported",
IPP_TAG_MIMETYPE)) != NULL)
{
@@ -4186,12 +5215,38 @@ valid_job_attributes(
if (!_cups_strcasecmp(format, supported->values[i].string.text))
break;
- if (i >= supported->num_values)
- {
+ if (i >= supported->num_values && attr)
respond_unsupported(client, attr);
- }
}
+ return (!client->response->attrs ||
+ !client->response->attrs->next ||
+ !client->response->attrs->next->next);
+}
+
+
+/*
+ * 'valid_job_attributes()' - Determine whether the job attributes are valid.
+ *
+ * When one or more job attributes are invalid, this function adds a suitable
+ * response and attributes to the unsupported group.
+ */
+
+static int /* O - 1 if valid, 0 if not */
+valid_job_attributes(
+ _ipp_client_t *client) /* I - Client */
+{
+ int i; /* Looping var */
+ ipp_attribute_t *attr, /* Current attribute */
+ *supported; /* xxx-supported attribute */
+
+
+ /*
+ * Check operation attributes...
+ */
+
+ valid_doc_attributes(client);
+
/*
* Check the various job template attributes...
*/
@@ -4371,10 +5426,12 @@ valid_job_attributes(
}
}
- return (valid);
+ return (!client->response->attrs ||
+ !client->response->attrs->next ||
+ !client->response->attrs->next->next);
}
/*
- * End of "$Id: ippserver.c 9793 2011-05-20 03:49:49Z mike $".
+ * End of "$Id: ippserver.c 10031 2011-09-30 05:24:10Z mike $".
*/