/*
- * "$Id$"
+ * "$Id: ippserver.c 11986 2014-07-02 15:52:01Z msweet $"
*
- * Sample IPP/2.0 server for CUPS.
+ * Sample IPP/2.0 server for CUPS.
*
- * Copyright 2010-2011 by Apple Inc.
+ * Copyright 2010-2014 by Apple Inc.
*
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "LICENSE.txt"
- * which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file. If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
*
- * This file is subject to the Apple OS-Developed Software exception.
- *
- * 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.
- * 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.
+ * This file is subject to the Apple OS-Developed Software exception.
+ */
+
+/*
+ * Disable private and deprecated stuff so we can verify that the public API
+ * is sufficient to implement a server.
*/
+#define _IPP_PRIVATE_STRUCTURES 0 /* Disable private IPP stuff */
+#define _CUPS_NO_DEPRECATED 1 /* Disable deprecated stuff */
+
+
/*
* Include necessary headers...
*/
-#include <cups/cups-private.h>
+#include <cups/cups.h> /* Public API */
+#include <config.h> /* CUPS configuration header */
+#include <cups/string-private.h> /* For string functions */
+#include <cups/thread-private.h> /* For multithreading functions */
+
+#include <sys/wait.h>
+
#ifdef HAVE_DNSSD
# include <dns_sd.h>
#endif /* HAVE_DNSSD */
+#include <limits.h>
#include <sys/stat.h>
+#include <sys/fcntl.h>
#include <poll.h>
#ifdef HAVE_SYS_MOUNT_H
# include <sys/mount.h>
enum _ipp_preasons_e /* printer-state-reasons bit values */
{
- _IPP_PRINTER_NONE = 0x0000, /* none */
- _IPP_PRINTER_OTHER = 0x0001, /* other */
- _IPP_PRINTER_COVER_OPEN = 0x0002, /* cover-open */
- _IPP_PRINTER_INPUT_TRAY_MISSING = 0x0004,
+ _IPP_PSTATE_NONE = 0x0000, /* none */
+ _IPP_PSTATE_OTHER = 0x0001, /* other */
+ _IPP_PSTATE_COVER_OPEN = 0x0002, /* cover-open */
+ _IPP_PSTATE_INPUT_TRAY_MISSING = 0x0004,
/* input-tray-missing */
- _IPP_PRINTER_MARKER_SUPPLY_EMPTY = 0x0008,
+ _IPP_PSTATE_MARKER_SUPPLY_EMPTY = 0x0008,
/* marker-supply-empty */
- _IPP_PRINTER_MARKER_SUPPLY_LOW = 0x0010,
+ _IPP_PSTATE_MARKER_SUPPLY_LOW = 0x0010,
/* marker-suply-low */
- _IPP_PRINTER_MARKER_WASTE_ALMOST_FULL = 0x0020,
+ _IPP_PSTATE_MARKER_WASTE_ALMOST_FULL = 0x0020,
/* marker-waste-almost-full */
- _IPP_PRINTER_MARKER_WASTE_FULL = 0x0040,
+ _IPP_PSTATE_MARKER_WASTE_FULL = 0x0040,
/* marker-waste-full */
- _IPP_PRINTER_MEDIA_EMPTY = 0x0080, /* media-empty */
- _IPP_PRINTER_MEDIA_JAM = 0x0100, /* media-jam */
- _IPP_PRINTER_MEDIA_LOW = 0x0200, /* media-low */
- _IPP_PRINTER_MEDIA_NEEDED = 0x0400, /* media-needed */
- _IPP_PRINTER_MOVING_TO_PAUSED = 0x0800,
+ _IPP_PSTATE_MEDIA_EMPTY = 0x0080, /* media-empty */
+ _IPP_PSTATE_MEDIA_JAM = 0x0100, /* media-jam */
+ _IPP_PSTATE_MEDIA_LOW = 0x0200, /* media-low */
+ _IPP_PSTATE_MEDIA_NEEDED = 0x0400, /* media-needed */
+ _IPP_PSTATE_MOVING_TO_PAUSED = 0x0800,
/* moving-to-paused */
- _IPP_PRINTER_PAUSED = 0x1000, /* paused */
- _IPP_PRINTER_SPOOL_AREA_FULL = 0x2000,/* spool-area-full */
- _IPP_PRINTER_TONER_EMPTY = 0x4000, /* toner-empty */
- _IPP_PRINTER_TONER_LOW = 0x8000 /* toner-low */
+ _IPP_PSTATE_PAUSED = 0x1000, /* paused */
+ _IPP_PSTATE_SPOOL_AREA_FULL = 0x2000,/* spool-area-full */
+ _IPP_PSTATE_TONER_EMPTY = 0x4000, /* toner-empty */
+ _IPP_PSTATE_TONER_LOW = 0x8000 /* toner-low */
};
typedef unsigned int _ipp_preasons_t; /* Bitfield for printer-state-reasons */
"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 */
{ 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 */
#ifdef HAVE_DNSSD
DNSServiceRef common_ref, /* Shared service connection */
ipp_ref, /* Bonjour IPP service */
+# ifdef HAVE_SSL
+ ipps_ref, /* Bonjour IPPS service */
+# endif /* HAVE_SSL */
http_ref, /* Bonjour HTTP service */
printer_ref; /* Bonjour LPD service */
TXTRecordRef ipp_txt; /* Bonjour IPP TXT record */
*icon, /* Icon filename */
*directory, /* Spool directory */
*hostname, /* Hostname */
- *uri; /* printer-uri-supported */
+ *uri, /* printer-uri-supported */
+ *command; /* Command to run with job file */
int port; /* Port */
size_t urilen; /* Length of printer URI */
ipp_t *attrs; /* Static attributes */
struct _ipp_job_s /**** Job data ****/
{
int id; /* Job ID */
- char *name, /* job-name */
+ const char *name, /* job-name */
*username, /* job-originating-user-name */
*format; /* document-format */
ipp_jstate_t state; /* job-state value */
typedef struct _ipp_client_s /**** Client data ****/
{
- http_t http; /* HTTP connection */
+ http_t *http; /* HTTP connection */
ipp_t *request, /* IPP request */
*response; /* IPP response */
time_t start; /* Request start time */
ipp_op_t operation_id; /* IPP operation-id */
char uri[1024]; /* Request URI */
http_addr_t addr; /* Client address */
+ char hostname[256]; /* Client hostname */
_ipp_printer_t *printer; /* Printer */
_ipp_job_t *job; /* Current job, if any */
} _ipp_client_t;
static void clean_jobs(_ipp_printer_t *printer);
static int compare_jobs(_ipp_job_t *a, _ipp_job_t *b);
-static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr,
- ipp_tag_t group_tag, int quickcopy);
static void copy_attributes(ipp_t *to, ipp_t *from, cups_array_t *ra,
ipp_tag_t group_tag, int quickcopy);
static void copy_job_attributes(_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,
const char *icon,
const char *docformats, int ppm,
int ppm_color, int duplex, int port,
+ int pin,
#ifdef HAVE_DNSSD
- const char *regtype,
+ const char *subtype,
#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);
+ const char *directory,
+ const char *command);
+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);
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);
int duplex, const char *regtype);
#endif /* HAVE_DNSSD */
static int respond_http(_ipp_client_t *client, http_status_t code,
+ const char *content_coding,
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);
{
int i; /* Looping var */
const char *opt, /* Current option character */
+ *command = NULL, /* Command to run with job files */
*servername = NULL, /* Server host name */
*name = NULL, /* Printer name */
*location = "", /* Location of printer */
*make = "Test", /* Manufacturer */
*model = "Printer", /* Model */
*icon = "printer.png", /* Icon file */
- *formats = "application/pdf,image/jpeg";
+ *formats = "application/pdf,image/jpeg,image/pwg-raster";
/* Supported formats */
+#ifdef HAVE_SSL
+ const char *keypath = NULL; /* Keychain path */
+#endif /* HAVE_SSL */
#ifdef HAVE_DNSSD
- const char *regtype = "_ipp._tcp"; /* Bonjour service type */
+ const char *subtype = "_print"; /* Bonjour service subtype */
#endif /* HAVE_DNSSD */
- int port = 8631, /* Port number (0 = auto) TODO: FIX */
+ int port = 8631, /* Port number (0 = auto) */
duplex = 0, /* Duplex mode */
ppm = 10, /* Pages per minute for mono */
- ppm_color = 0; /* Pages per minute for color */
+ ppm_color = 0, /* Pages per minute for color */
+ pin = 0; /* PIN printing mode? */
char directory[1024] = ""; /* Spool directory */
_ipp_printer_t *printer; /* Printer object */
if (argv[i][0] == '-')
{
for (opt = argv[i] + 1; *opt; opt ++)
+ {
switch (*opt)
{
case '2' : /* -2 (enable 2-sided printing) */
duplex = 1;
break;
+#ifdef HAVE_SSL
+ case 'K' : /* -K keypath */
+ i ++;
+ if (i >= argc)
+ usage(1);
+ keypath = argv[i];
+ break;
+#endif /* HAVE_SSL */
+
case 'M' : /* -M manufacturer */
i ++;
if (i >= argc)
make = argv[i];
break;
+ case 'P' : /* -P (PIN printing mode) */
+ pin = 1;
+ break;
+
+ case 'c' : /* -c command */
+ i ++;
+ if (i >= argc)
+ usage(1);
+
+ command = argv[i];
+ break;
+
case 'd' : /* -d spool-directory */
i ++;
if (i >= argc)
case 'h' : /* -h (show help) */
usage(0);
- break;
case 'i' : /* -i icon.png */
i ++;
break;
#ifdef HAVE_DNSSD
- case 'r' : /* -r regtype */
+ case 'r' : /* -r subtype */
i ++;
if (i >= argc)
usage(1);
- regtype = argv[i];
+ subtype = argv[i];
break;
#endif /* HAVE_DNSSD */
default : /* Unknown */
fprintf(stderr, "Unknown option \"-%c\".\n", *opt);
usage(1);
- break;
}
+ }
}
else if (!name)
{
fprintf(stderr, "Using spool directory \"%s\".\n", directory);
}
+#ifdef HAVE_SSL
+ cupsSetServerCredentials(keypath, servername, 1);
+#endif /* HAVE_SSL */
+
/*
* Create the printer...
*/
if ((printer = create_printer(servername, name, location, make, model, icon,
- formats, ppm, ppm_color, duplex, port,
+ formats, ppm, ppm_color, duplex, port, pin,
#ifdef HAVE_DNSSD
- regtype,
+ subtype,
#endif /* HAVE_DNSSD */
- directory)) == NULL)
+ directory, command)) == NULL)
return (1);
/*
}
-/*
- * 'copy_attribute()' - Copy a single attribute.
- */
-
-static ipp_attribute_t * /* O - New attribute */
-copy_attribute(
- ipp_t *to, /* O - Destination request/response */
- ipp_attribute_t *attr, /* I - Attribute to copy */
- ipp_tag_t group_tag, /* I - Group to put the copy in */
- int quickcopy) /* I - Do a quick copy? */
-{
- int i; /* Looping var */
- ipp_attribute_t *toattr; /* Destination attribute */
-
-
- if (Verbosity && attr->name)
- {
- char buffer[2048]; /* Attribute value */
-
- _ippAttrString(attr, buffer, sizeof(buffer));
-
- fprintf(stderr, "Copying %s (%s%s) %s\n", attr->name,
- attr->num_values > 1 ? "1setOf " : "",
- ippTagString(attr->value_tag & ~IPP_TAG_COPY), buffer);
- }
-
- switch (attr->value_tag & ~IPP_TAG_COPY)
- {
- case IPP_TAG_ZERO :
- toattr = ippAddSeparator(to);
- break;
-
- case IPP_TAG_INTEGER :
- case IPP_TAG_ENUM :
- toattr = ippAddIntegers(to, group_tag, attr->value_tag,
- attr->name, attr->num_values, NULL);
-
- for (i = 0; i < attr->num_values; i ++)
- toattr->values[i].integer = attr->values[i].integer;
- break;
-
- case IPP_TAG_BOOLEAN :
- toattr = ippAddBooleans(to, group_tag, attr->name,
- attr->num_values, NULL);
-
- for (i = 0; i < attr->num_values; i ++)
- toattr->values[i].boolean = attr->values[i].boolean;
- break;
-
- case IPP_TAG_TEXT :
- case IPP_TAG_NAME :
- case IPP_TAG_KEYWORD :
- case IPP_TAG_URI :
- case IPP_TAG_URISCHEME :
- case IPP_TAG_CHARSET :
- case IPP_TAG_LANGUAGE :
- case IPP_TAG_MIMETYPE :
- toattr = ippAddStrings(to, group_tag,
- (ipp_tag_t)(attr->value_tag | quickcopy),
- attr->name, attr->num_values, NULL, NULL);
-
- if (quickcopy)
- {
- for (i = 0; i < attr->num_values; i ++)
- toattr->values[i].string.text = attr->values[i].string.text;
- }
- else
- {
- for (i = 0; i < attr->num_values; i ++)
- toattr->values[i].string.text =
- _cupsStrAlloc(attr->values[i].string.text);
- }
- break;
-
- case IPP_TAG_DATE :
- toattr = ippAddDate(to, group_tag, attr->name,
- attr->values[0].date);
- break;
-
- case IPP_TAG_RESOLUTION :
- toattr = ippAddResolutions(to, group_tag, attr->name,
- attr->num_values, IPP_RES_PER_INCH,
- NULL, NULL);
-
- for (i = 0; i < attr->num_values; i ++)
- {
- toattr->values[i].resolution.xres = attr->values[i].resolution.xres;
- toattr->values[i].resolution.yres = attr->values[i].resolution.yres;
- toattr->values[i].resolution.units = attr->values[i].resolution.units;
- }
- break;
-
- case IPP_TAG_RANGE :
- toattr = ippAddRanges(to, group_tag, attr->name,
- attr->num_values, NULL, NULL);
-
- for (i = 0; i < attr->num_values; i ++)
- {
- toattr->values[i].range.lower = attr->values[i].range.lower;
- toattr->values[i].range.upper = attr->values[i].range.upper;
- }
- break;
-
- case IPP_TAG_TEXTLANG :
- case IPP_TAG_NAMELANG :
- toattr = ippAddStrings(to, group_tag,
- (ipp_tag_t)(attr->value_tag | quickcopy),
- attr->name, attr->num_values, NULL, NULL);
-
- if (quickcopy)
- {
- for (i = 0; i < attr->num_values; i ++)
- {
- toattr->values[i].string.charset = attr->values[i].string.charset;
- toattr->values[i].string.text = attr->values[i].string.text;
- }
- }
- else
- {
- for (i = 0; i < attr->num_values; i ++)
- {
- if (!i)
- toattr->values[i].string.charset =
- _cupsStrAlloc(attr->values[i].string.charset);
- else
- toattr->values[i].string.charset =
- toattr->values[0].string.charset;
-
- toattr->values[i].string.text =
- _cupsStrAlloc(attr->values[i].string.text);
- }
- }
- break;
-
- case IPP_TAG_BEGIN_COLLECTION :
- toattr = ippAddCollections(to, group_tag, attr->name,
- attr->num_values, NULL);
-
- for (i = 0; i < attr->num_values; i ++)
- {
- toattr->values[i].collection = attr->values[i].collection;
- attr->values[i].collection->use ++;
- }
- break;
-
- case IPP_TAG_STRING :
- if (quickcopy)
- {
- toattr = ippAddOctetString(to, group_tag, attr->name, NULL, 0);
- toattr->value_tag |= quickcopy;
- toattr->values[0].unknown.data = attr->values[0].unknown.data;
- toattr->values[0].unknown.length = attr->values[0].unknown.length;
- }
- else
- toattr = ippAddOctetString(to, attr->group_tag, attr->name,
- attr->values[0].unknown.data,
- attr->values[0].unknown.length);
- break;
-
- default :
- toattr = ippAddIntegers(to, group_tag, attr->value_tag,
- attr->name, attr->num_values, NULL);
-
- for (i = 0; i < attr->num_values; i ++)
- {
- toattr->values[i].unknown.length = attr->values[i].unknown.length;
-
- if (toattr->values[i].unknown.length > 0)
- {
- if ((toattr->values[i].unknown.data =
- malloc(toattr->values[i].unknown.length)) == NULL)
- toattr->values[i].unknown.length = 0;
- else
- memcpy(toattr->values[i].unknown.data,
- attr->values[i].unknown.data,
- toattr->values[i].unknown.length);
- }
- }
- break; /* anti-compiler-warning-code */
- }
-
- return (toattr);
-}
-
-
/*
* 'copy_attributes()' - Copy attributes from one request to another.
*/
if (!to || !from)
return;
- for (fromattr = from->attrs; fromattr; fromattr = fromattr->next)
+ for (fromattr = ippFirstAttribute(from);
+ fromattr;
+ fromattr = ippNextAttribute(from))
{
/*
* Filter attributes as needed...
*/
- if ((group_tag != IPP_TAG_ZERO && fromattr->group_tag != group_tag &&
- fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name)
+ ipp_tag_t fromgroup = ippGetGroupTag(fromattr);
+ const char *fromname = ippGetName(fromattr);
+
+ if ((group_tag != IPP_TAG_ZERO && fromgroup != group_tag &&
+ fromgroup != IPP_TAG_ZERO) || !fromname)
continue;
- if (!ra || cupsArrayFind(ra, fromattr->name))
- copy_attribute(to, fromattr, fromattr->group_tag, quickcopy);
+ if (!ra || cupsArrayFind(ra, (void *)fromname))
+ ippCopyAttribute(to, fromattr, quickcopy);
}
}
_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,
{
switch (job->state)
{
- case IPP_JOB_PENDING :
+ case IPP_JSTATE_PENDING :
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons",
NULL, "none");
break;
- case IPP_JOB_HELD :
+ case IPP_JSTATE_HELD :
if (job->fd >= 0)
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
- NULL, "job-incoming");
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "job-state-reasons", NULL, "job-incoming");
else if (ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_ZERO))
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
- NULL, "job-hold-until-specified");
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "job-state-reasons", NULL, "job-hold-until-specified");
+ else
+ ippAddString(client->response, IPP_TAG_JOB,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "job-state-reasons", NULL, "job-data-insufficient");
break;
- case IPP_JOB_PROCESSING :
+ case IPP_JSTATE_PROCESSING :
if (job->cancel)
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
- NULL, "processing-to-stop-point");
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "job-state-reasons", NULL, "processing-to-stop-point");
else
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
- NULL, "job-printing");
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "job-state-reasons", NULL, "job-printing");
break;
- case IPP_JOB_STOPPED :
+ case IPP_JSTATE_STOPPED :
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons",
NULL, "job-stopped");
break;
- case IPP_JOB_CANCELED :
+ case IPP_JSTATE_CANCELED :
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons",
NULL, "job-canceled-by-user");
break;
- case IPP_JOB_ABORTED :
+ case IPP_JSTATE_ABORTED :
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons",
NULL, "aborted-by-system");
break;
- case IPP_JOB_COMPLETED :
+ case IPP_JSTATE_COMPLETED :
ippAddString(client->response, IPP_TAG_JOB,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "job-state-reasons",
+ IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-state-reasons",
NULL, "job-completed-successfully");
break;
}
if (!ra || cupsArrayFind(ra, "time-at-completed"))
ippAddInteger(client->response, IPP_TAG_JOB,
job->completed ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE,
- "time-at-completed", job->completed);
+ "time-at-completed", (int)job->completed);
if (!ra || cupsArrayFind(ra, "time-at-processing"))
ippAddInteger(client->response, IPP_TAG_JOB,
job->processing ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE,
- "time-at-processing", job->processing);
+ "time-at-processing", (int)job->processing);
}
int sock) /* I - Listen socket */
{
_ipp_client_t *client; /* Client */
- int val; /* Parameter value */
- socklen_t addrlen; /* Length of address */
if ((client = calloc(1, sizeof(_ipp_client_t))) == NULL)
return (NULL);
}
- client->printer = printer;
- client->http.activity = time(NULL);
- client->http.hostaddr = &(client->addr);
- client->http.blocking = 1;
+ client->printer = printer;
/*
* Accept the client and get the remote address...
*/
- addrlen = sizeof(http_addr_t);
-
- if ((client->http.fd = accept(sock, (struct sockaddr *)&(client->addr),
- &addrlen)) < 0)
+ if ((client->http = httpAcceptConnection(sock, 1)) == NULL)
{
perror("Unable to accept client connection");
return (NULL);
}
- httpAddrString(&(client->addr), client->http.hostname,
- sizeof(client->http.hostname));
+ httpGetHostname(client->http, client->hostname, sizeof(client->hostname));
if (Verbosity)
- fprintf(stderr, "Accepted connection from %s (%s)\n", client->http.hostname,
- client->http.hostaddr->addr.sa_family == AF_INET ? "IPv4" : "IPv6");
-
- /*
- * Using TCP_NODELAY improves responsiveness, especially on systems
- * with a slow loopback interface. Since we write large buffers
- * when sending print files and requests, there shouldn't be any
- * performance penalty for this...
- */
-
- val = 1;
- setsockopt(client->http.fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val,
- sizeof(val));
+ fprintf(stderr, "Accepted connection from %s\n", client->hostname);
return (client);
}
_cupsRWLockWrite(&(client->printer->rwlock));
if (client->printer->active_job &&
- client->printer->active_job->state < IPP_JOB_CANCELED)
+ client->printer->active_job->state < IPP_JSTATE_CANCELED)
{
/*
* Only accept a single job at a time...
job->printer = client->printer;
job->attrs = client->request;
- job->state = IPP_JOB_HELD;
+ job->state = IPP_JSTATE_HELD;
job->fd = -1;
client->request = NULL;
* Set all but the first two attributes to the job attributes group...
*/
- for (attr = job->attrs->attrs->next->next; attr; attr = attr->next)
- attr->group_tag = IPP_TAG_JOB;
+ for (ippFirstAttribute(job->attrs),
+ ippNextAttribute(job->attrs),
+ attr = ippNextAttribute(job->attrs);
+ attr;
+ attr = ippNextAttribute(job->attrs))
+ ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
/*
* Get the requesting-user-name, document format, and priority...
if ((attr = ippFindAttribute(job->attrs, "requesting-user-name",
IPP_TAG_NAME)) != NULL)
- {
- _cupsStrFree(attr->name);
- attr->name = _cupsStrAlloc("job-originating-user-name");
- }
+ ippSetName(job->attrs, &attr, "job-originating-user-name");
else
- attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME | IPP_TAG_COPY,
+ attr = ippAddString(job->attrs, IPP_TAG_JOB,
+ IPP_CONST_TAG(IPP_TAG_NAME),
"job-originating-user-name", NULL, "anonymous");
if (attr)
- job->username = attr->values[0].string.text;
+ job->username = ippGetString(attr, 0, NULL);
else
job->username = "anonymous";
if ((attr = ippFindAttribute(job->attrs, "document-format",
IPP_TAG_MIMETYPE)) != NULL)
- job->format = attr->values[0].string.text;
+ job->format = ippGetString(attr, 0, NULL);
else
job->format = "application/octet-stream";
create_listener(int family, /* I - Address family */
int *port) /* IO - Port number */
{
- int sock, /* Listener socket */
- val; /* Socket value */
- http_addr_t address; /* Listen address */
- socklen_t addrlen; /* Length of listen address */
-
-
- if ((sock = socket(family, SOCK_STREAM, 0)) < 0)
- return (-1);
+ int sock; /* Listener socket */
+ http_addrlist_t *addrlist; /* Listen address */
+ char service[255]; /* Service port */
- val = 1;
- setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
-
-#ifdef IPV6_V6ONLY
- if (family == AF_INET6)
- setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val));
-#endif /* IPV6_V6ONLY */
if (!*port)
{
- /*
- * Get the auto-assigned port number for the IPv4 socket...
- */
-
- /* TODO: This code does not appear to work - port is always 0... */
- addrlen = sizeof(address);
- if (getsockname(sock, (struct sockaddr *)&address, &addrlen))
- {
- perror("getsockname() failed");
- *port = 8631;
- }
- else
- *port = _httpAddrPort(&address);
-
+ *port = 8000 + (getuid() % 1000);
fprintf(stderr, "Listening on port %d.\n", *port);
}
- memset(&address, 0, sizeof(address));
- address.addr.sa_family = family;
- _httpAddrSetPort(&address, *port);
-
- if (bind(sock, (struct sockaddr *)&address, httpAddrLength(&address)))
- {
- close(sock);
+ snprintf(service, sizeof(service), "%d", *port);
+ if ((addrlist = httpAddrGetList(NULL, family, service)) == NULL)
return (-1);
- }
- if (listen(sock, 5))
- {
- close(sock);
- return (-1);
- }
+ sock = httpAddrListen(&(addrlist->addr), *port);
+
+ httpAddrFreeList(addrlist);
return (sock);
}
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" : "");
}
+/*
+ * '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.
int ppm_color, /* I - Pages per minute in color (0 for gray) */
int duplex, /* I - 1 = duplex, 0 = simplex */
int port, /* I - Port for listeners or 0 for auto */
+ int pin, /* I - Require PIN printing */
#ifdef HAVE_DNSSD
- const char *regtype, /* I - Bonjour service type */
+ const char *subtype, /* I - Bonjour service subtype */
#endif /* HAVE_DNSSD */
- const char *directory) /* I - Spool directory */
+ const char *directory, /* I - Spool directory */
+ const char *command) /* I - Command to run on job files */
{
int i, j; /* Looping vars */
_ipp_printer_t *printer; /* Printer */
*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;
- /* Current media-col-database value */
+ int media_col_index;/* Current media-col-database value */
int k_supported; /* Maximum file size supported */
#ifdef HAVE_STATVFS
struct statvfs spoolinfo; /* FS info for spool directory */
#endif /* HAVE_STATVFS */
static const int orients[4] = /* orientation-requested-supported values */
{
- IPP_PORTRAIT,
- IPP_LANDSCAPE,
- IPP_REVERSE_LANDSCAPE,
- IPP_REVERSE_PORTRAIT
+ IPP_ORIENT_PORTRAIT,
+ IPP_ORIENT_LANDSCAPE,
+ IPP_ORIENT_REVERSE_LANDSCAPE,
+ IPP_ORIENT_REVERSE_PORTRAIT
};
static const char * const versions[] =/* ipp-versions-supported values */
{
};
static const int ops[] = /* operations-supported values */
{
- IPP_PRINT_JOB,
- IPP_VALIDATE_JOB,
- IPP_CREATE_JOB,
- IPP_SEND_DOCUMENT,
- IPP_CANCEL_JOB,
- IPP_GET_JOB_ATTRIBUTES,
- IPP_GET_JOBS,
- IPP_GET_PRINTER_ATTRIBUTES
+ IPP_OP_PRINT_JOB,
+ IPP_OP_PRINT_URI,
+ IPP_OP_VALIDATE_JOB,
+ IPP_OP_CREATE_JOB,
+ IPP_OP_SEND_DOCUMENT,
+ IPP_OP_SEND_URI,
+ IPP_OP_CANCEL_JOB,
+ IPP_OP_GET_JOB_ATTRIBUTES,
+ IPP_OP_GET_JOBS,
+ IPP_OP_GET_PRINTER_ATTRIBUTES
};
static const char * const charsets[] =/* charset-supported values */
{
"us-ascii",
"utf-8"
};
+ static const char * const compressions[] =/* compression-supported values */
+ {
+#ifdef HAVE_LIBZ
+ "deflate",
+ "gzip",
+#endif /* HAVE_LIBZ */
+ "none"
+ };
static const char * const job_creation[] =
{ /* job-creation-attributes-supported values */
"copies",
"ipp-attribute-fidelity",
+ "job-account-id",
+ "job-accounting-user-id",
"job-name",
+ "job-password",
"job-priority",
"media",
"media-col",
IPP_QUALITY_NORMAL,
IPP_QUALITY_HIGH
};
+ static const int pwg_raster_document_resolution_supported[] =
+ {
+ 150,
+ 300,
+ 600
+ };
+ static const char * const pwg_raster_document_type_supported[] =
+ {
+ "black-1",
+ "cmyk-8",
+ "sgray-8",
+ "srgb-8",
+ "srgb-16"
+ };
+ 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",
printer->ipv4 = -1;
printer->ipv6 = -1;
- printer->name = _cupsStrAlloc(name);
+ printer->name = strdup(name);
#ifdef HAVE_DNSSD
- printer->dnssd_name = _cupsStrRetain(printer->name);
+ printer->dnssd_name = strdup(printer->name);
#endif /* HAVE_DNSSD */
- printer->directory = _cupsStrAlloc(directory);
- printer->hostname = _cupsStrAlloc(servername ? servername :
+ printer->command = command ? strdup(command) : NULL;
+ printer->directory = strdup(directory);
+ printer->hostname = strdup(servername ? servername :
httpGetHostname(NULL, hostname,
sizeof(hostname)));
printer->port = port;
- printer->state = IPP_PRINTER_IDLE;
- printer->state_reasons = _IPP_PRINTER_NONE;
+ printer->state = IPP_PSTATE_IDLE;
+ printer->state_reasons = _IPP_PSTATE_NONE;
printer->jobs = cupsArrayNew((cups_array_func_t)compare_jobs, NULL);
printer->next_job_id = 1;
httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
- printer->hostname, printer->port, "/ipp");
- printer->uri = _cupsStrAlloc(uri);
+ printer->hostname, printer->port, "/ipp/print");
+ printer->uri = strdup(uri);
printer->urilen = strlen(uri);
+ if (icon)
+ printer->icon = strdup(icon);
+
_cupsRWInit(&(printer->rwlock));
/*
for (i = 0; i < num_formats; i ++)
{
if (!_cups_strcasecmp(formats[i], "application/pdf"))
- snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPDF", prefix);
+ snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPDF", prefix);
else if (!_cups_strcasecmp(formats[i], "application/postscript"))
- snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPS", prefix);
+ snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPS", prefix);
else if (!_cups_strcasecmp(formats[i], "application/vnd.hp-PCL"))
- snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPCL", prefix);
+ snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPCL", prefix);
else if (!_cups_strcasecmp(formats[i], "image/jpeg"))
- snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sJPEG", prefix);
+ snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sJPEG", prefix);
else if (!_cups_strcasecmp(formats[i], "image/png"))
- snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%sPNG", prefix);
+ snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%sPNG", prefix);
else if (_cups_strcasecmp(formats[i], "application/octet-stream"))
- snprintf(ptr, sizeof(device_id) - (ptr - device_id), "%s%s", prefix,
- formats[i]);
+ snprintf(ptr, sizeof(device_id) - (size_t)(ptr - device_id), "%s%s", prefix, formats[i]);
ptr += strlen(ptr);
prefix = ",";
printer->attrs = ippNew();
/* charset-configured */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_CHARSET),
"charset-configured", NULL, "utf-8");
/* charset-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_CHARSET | IPP_TAG_COPY,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_CHARSET),
"charset-supported", sizeof(charsets) / sizeof(charsets[0]),
NULL, charsets);
ppm_color > 0);
/* compression-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
- "compression-supported", NULL, "none");
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "compression-supported",
+ (int)(sizeof(compressions) / sizeof(compressions[0])), NULL,
+ compressions);
/* copies-default */
ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"finishings-supported", IPP_FINISHINGS_NONE);
/* generated-natural-language-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_LANGUAGE),
"generated-natural-language-supported", NULL, "en");
/* ipp-versions-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"ipp-versions-supported",
sizeof(versions) / sizeof(versions[0]), NULL, versions);
+ /* job-account-id-supported */
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-account-id-supported", 1);
+
+ /* job-accounting-user-id-supported */
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER,
+ "job-accounting-user-id-supported", 1);
+
/* job-creation-attributes-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"job-creation-attributes-supported",
sizeof(job_creation) / sizeof(job_creation[0]),
NULL, job_creation);
ippAddRange(printer->attrs, IPP_TAG_PRINTER, "job-k-octets-supported", 0,
k_supported);
+ /* job-password-supported */
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "job-password-supported", 4);
+
/* job-priority-default */
ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"job-priority-default", 50);
"job-priority-supported", 100);
/* job-sheets-default */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_NAME),
"job-sheets-default", NULL, "none");
/* job-sheets-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_NAME),
"job-sheets-supported", NULL, "none");
/* media-bottom-margin-supported */
media_col_database = ippAddCollections(printer->attrs, IPP_TAG_PRINTER,
"media-col-database", num_database,
NULL);
- for (media_col_value = media_col_database->values, i = 0;
+ for (media_col_index = 0, i = 0;
i < (int)(sizeof(media_col_sizes) / sizeof(media_col_sizes[0]));
i ++)
{
strncmp(media_type_supported[j], "photographic-", 13))
continue;
- media_col_value->collection =
- create_media_col(media_supported[i], media_type_supported[j],
- media_col_sizes[i][0], media_col_sizes[i][1],
- media_xxx_margin_supported[1]);
- media_col_value ++;
+ ippSetCollection(printer->attrs, &media_col_database, media_col_index,
+ create_media_col(media_supported[i],
+ media_type_supported[j],
+ media_col_sizes[i][0],
+ media_col_sizes[i][1],
+ media_xxx_margin_supported[1]));
+ media_col_index ++;
if (media_col_sizes[i][2] != _IPP_ENV_ONLY &&
(!strcmp(media_type_supported[j], "auto") ||
* Add borderless version for this combination...
*/
- media_col_value->collection =
- create_media_col(media_supported[i], media_type_supported[j],
- media_col_sizes[i][0], media_col_sizes[i][1],
- media_xxx_margin_supported[0]);
- media_col_value ++;
+ ippSetCollection(printer->attrs, &media_col_database, media_col_index,
+ create_media_col(media_supported[i],
+ media_type_supported[j],
+ media_col_sizes[i][0],
+ media_col_sizes[i][1],
+ media_xxx_margin_supported[0]));
+ media_col_index ++;
}
}
}
ippDelete(media_col_default);
/* media-col-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"media-col-supported",
(int)(sizeof(media_col_supported) /
sizeof(media_col_supported[0])), NULL,
media_col_supported);
/* media-default */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"media-default", NULL, media_supported[0]);
/* media-left-margin-supported */
media_xxx_margin_supported);
/* media-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"media-supported",
(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 ++)
+ ippSetCollection(printer->attrs, &media_size_supported, i,
+ 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",
sizeof(media_xxx_margin_supported[0])),
media_xxx_margin_supported);
+ /* media-type-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "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,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"multiple-document-handling-supported",
sizeof(multiple_document_handling) /
sizeof(multiple_document_handling[0]), NULL,
"multiple-document-jobs-supported", 0);
/* natural-language-configured */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_LANGUAGE),
"natural-language-configured", NULL, "en");
/* number-up-default */
"orientation-requested-supported", 4, orients);
/* output-bin-default */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"output-bin-default", NULL, "face-down");
/* output-bin-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"output-bin-supported", NULL, "face-down");
/* pages-per-minute */
"pages-per-minute-color", ppm_color);
/* pdl-override-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"pdl-override-supported", NULL, "attempted");
/* print-quality-default */
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
"printer-make-and-model", NULL, make_model);
+ /* printer-mandatory-job-attributes */
+ if (pin)
+ {
+ static const char * const names[] =
+ {
+ "job-accounting-user-id",
+ "job-password"
+ };
+
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "printer-mandatory-job-attributes",
+ (int)(sizeof(names) / sizeof(names[0])), NULL, names);
+ }
+
/* printer-more-info */
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
"printer-more-info", NULL, adminurl);
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
"printer-uri-supported", NULL, uri);
+ /* pwg-raster-document-xxx-supported */
+ for (i = 0; i < num_formats; i ++)
+ if (!_cups_strcasecmp(formats[i], "image/pwg-raster"))
+ break;
+
+ if (i < num_formats)
+ {
+ ippAddResolutions(printer->attrs, IPP_TAG_PRINTER,
+ "pwg-raster-document-resolution-supported",
+ (int)(sizeof(pwg_raster_document_resolution_supported) /
+ sizeof(pwg_raster_document_resolution_supported[0])),
+ IPP_RES_PER_INCH,
+ pwg_raster_document_resolution_supported,
+ pwg_raster_document_resolution_supported);
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "pwg-raster-document-sheet-back", NULL, "normal");
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "pwg-raster-document-type-supported",
+ (int)(sizeof(pwg_raster_document_type_supported) /
+ sizeof(pwg_raster_document_type_supported[0])), NULL,
+ pwg_raster_document_type_supported);
+ }
+
+ /* reference-uri-scheme-supported */
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_URISCHEME),
+ "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,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"sides-default", NULL, "one-sided");
/* sides-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"sides-supported", duplex ? 3 : 1, NULL, sides_supported);
/* uri-authentication-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"uri-authentication-supported", NULL, "none");
/* uri-security-supported */
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddString(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"uri-security-supported", NULL, "none");
/* which-jobs-supported */
- ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER,
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
"which-jobs-supported",
sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs);
free(formats[0]);
- debug_attributes("Printer", printer->attrs);
+ debug_attributes("Printer", printer->attrs, 0);
#ifdef HAVE_DNSSD
/*
*/
if (!register_printer(printer, location, make, model, docformats, adminurl,
- ppm_color > 0, duplex, regtype))
+ ppm_color > 0, duplex, subtype))
goto bad_printer;
#endif /* HAVE_DNSSD */
}
-/*
- * 'create_requested_array()' - Create an array for requested-attributes.
- */
-
-static cups_array_t * /* O - requested-attributes array */
-create_requested_array(
- _ipp_client_t *client) /* I - Client */
-{
- int i; /* Looping var */
- ipp_attribute_t *requested; /* requested-attributes attribute */
- cups_array_t *ra; /* Requested attributes array */
- char *value; /* Current value */
-
-
- /*
- * Get the requested-attributes attribute, and return NULL if we don't
- * have one...
- */
-
- if ((requested = ippFindAttribute(client->request, "requested-attributes",
- IPP_TAG_KEYWORD)) == NULL)
- return (NULL);
-
- /*
- * If the attribute contains a single "all" keyword, return NULL...
- */
-
- if (requested->num_values == 1 &&
- !strcmp(requested->values[0].string.text, "all"))
- return (NULL);
-
- /*
- * Create an array using "strcmp" as the comparison function...
- */
-
- ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
-
- for (i = 0; i < requested->num_values; i ++)
- {
- value = requested->values[i].string.text;
-
- if (!strcmp(value, "job-template"))
- {
- cupsArrayAdd(ra, "copies");
- cupsArrayAdd(ra, "copies-default");
- cupsArrayAdd(ra, "copies-supported");
- cupsArrayAdd(ra, "finishings");
- cupsArrayAdd(ra, "finishings-default");
- cupsArrayAdd(ra, "finishings-supported");
- cupsArrayAdd(ra, "job-hold-until");
- cupsArrayAdd(ra, "job-hold-until-default");
- cupsArrayAdd(ra, "job-hold-until-supported");
- cupsArrayAdd(ra, "job-priority");
- cupsArrayAdd(ra, "job-priority-default");
- cupsArrayAdd(ra, "job-priority-supported");
- cupsArrayAdd(ra, "job-sheets");
- cupsArrayAdd(ra, "job-sheets-default");
- cupsArrayAdd(ra, "job-sheets-supported");
- cupsArrayAdd(ra, "media");
- cupsArrayAdd(ra, "media-col");
- cupsArrayAdd(ra, "media-col-default");
- cupsArrayAdd(ra, "media-col-supported");
- cupsArrayAdd(ra, "media-default");
- cupsArrayAdd(ra, "media-source-supported");
- cupsArrayAdd(ra, "media-supported");
- cupsArrayAdd(ra, "media-type-supported");
- cupsArrayAdd(ra, "multiple-document-handling");
- cupsArrayAdd(ra, "multiple-document-handling-default");
- cupsArrayAdd(ra, "multiple-document-handling-supported");
- cupsArrayAdd(ra, "number-up");
- cupsArrayAdd(ra, "number-up-default");
- cupsArrayAdd(ra, "number-up-supported");
- cupsArrayAdd(ra, "orientation-requested");
- cupsArrayAdd(ra, "orientation-requested-default");
- cupsArrayAdd(ra, "orientation-requested-supported");
- cupsArrayAdd(ra, "page-ranges");
- cupsArrayAdd(ra, "page-ranges-supported");
- cupsArrayAdd(ra, "printer-resolution");
- cupsArrayAdd(ra, "printer-resolution-default");
- cupsArrayAdd(ra, "printer-resolution-supported");
- cupsArrayAdd(ra, "print-quality");
- cupsArrayAdd(ra, "print-quality-default");
- cupsArrayAdd(ra, "print-quality-supported");
- cupsArrayAdd(ra, "sides");
- cupsArrayAdd(ra, "sides-default");
- cupsArrayAdd(ra, "sides-supported");
- }
- else if (!strcmp(value, "job-description"))
- {
- cupsArrayAdd(ra, "date-time-at-completed");
- cupsArrayAdd(ra, "date-time-at-creation");
- cupsArrayAdd(ra, "date-time-at-processing");
- cupsArrayAdd(ra, "job-detailed-status-message");
- cupsArrayAdd(ra, "job-document-access-errors");
- cupsArrayAdd(ra, "job-id");
- cupsArrayAdd(ra, "job-impressions");
- cupsArrayAdd(ra, "job-impressions-completed");
- cupsArrayAdd(ra, "job-k-octets");
- cupsArrayAdd(ra, "job-k-octets-processed");
- cupsArrayAdd(ra, "job-media-sheets");
- cupsArrayAdd(ra, "job-media-sheets-completed");
- cupsArrayAdd(ra, "job-message-from-operator");
- cupsArrayAdd(ra, "job-more-info");
- cupsArrayAdd(ra, "job-name");
- cupsArrayAdd(ra, "job-originating-user-name");
- cupsArrayAdd(ra, "job-printer-up-time");
- cupsArrayAdd(ra, "job-printer-uri");
- cupsArrayAdd(ra, "job-state");
- cupsArrayAdd(ra, "job-state-message");
- cupsArrayAdd(ra, "job-state-reasons");
- cupsArrayAdd(ra, "job-uri");
- cupsArrayAdd(ra, "number-of-documents");
- cupsArrayAdd(ra, "number-of-intervening-jobs");
- cupsArrayAdd(ra, "output-device-assigned");
- cupsArrayAdd(ra, "time-at-completed");
- cupsArrayAdd(ra, "time-at-creation");
- cupsArrayAdd(ra, "time-at-processing");
- }
- else if (!strcmp(value, "printer-description"))
- {
- cupsArrayAdd(ra, "charset-configured");
- cupsArrayAdd(ra, "charset-supported");
- cupsArrayAdd(ra, "color-supported");
- cupsArrayAdd(ra, "compression-supported");
- cupsArrayAdd(ra, "document-format-default");
- cupsArrayAdd(ra, "document-format-supported");
- cupsArrayAdd(ra, "generated-natural-language-supported");
- cupsArrayAdd(ra, "ipp-versions-supported");
- cupsArrayAdd(ra, "job-impressions-supported");
- cupsArrayAdd(ra, "job-k-octets-supported");
- cupsArrayAdd(ra, "job-media-sheets-supported");
- cupsArrayAdd(ra, "multiple-document-jobs-supported");
- cupsArrayAdd(ra, "multiple-operation-time-out");
- cupsArrayAdd(ra, "natural-language-configured");
- cupsArrayAdd(ra, "notify-attributes-supported");
- cupsArrayAdd(ra, "notify-lease-duration-default");
- cupsArrayAdd(ra, "notify-lease-duration-supported");
- cupsArrayAdd(ra, "notify-max-events-supported");
- cupsArrayAdd(ra, "notify-events-default");
- cupsArrayAdd(ra, "notify-events-supported");
- cupsArrayAdd(ra, "notify-pull-method-supported");
- cupsArrayAdd(ra, "notify-schemes-supported");
- cupsArrayAdd(ra, "operations-supported");
- cupsArrayAdd(ra, "pages-per-minute");
- cupsArrayAdd(ra, "pages-per-minute-color");
- cupsArrayAdd(ra, "pdl-override-supported");
- cupsArrayAdd(ra, "printer-alert");
- cupsArrayAdd(ra, "printer-alert-description");
- cupsArrayAdd(ra, "printer-current-time");
- cupsArrayAdd(ra, "printer-driver-installer");
- cupsArrayAdd(ra, "printer-info");
- cupsArrayAdd(ra, "printer-is-accepting-jobs");
- cupsArrayAdd(ra, "printer-location");
- cupsArrayAdd(ra, "printer-make-and-model");
- cupsArrayAdd(ra, "printer-message-from-operator");
- cupsArrayAdd(ra, "printer-more-info");
- cupsArrayAdd(ra, "printer-more-info-manufacturer");
- cupsArrayAdd(ra, "printer-name");
- cupsArrayAdd(ra, "printer-state");
- cupsArrayAdd(ra, "printer-state-message");
- cupsArrayAdd(ra, "printer-state-reasons");
- cupsArrayAdd(ra, "printer-up-time");
- cupsArrayAdd(ra, "printer-uri-supported");
- cupsArrayAdd(ra, "queued-job-count");
- cupsArrayAdd(ra, "reference-uri-schemes-supported");
- cupsArrayAdd(ra, "uri-authentication-supported");
- cupsArrayAdd(ra, "uri-security-supported");
- }
- else if (!strcmp(value, "printer-defaults"))
- {
- cupsArrayAdd(ra, "copies-default");
- cupsArrayAdd(ra, "document-format-default");
- cupsArrayAdd(ra, "finishings-default");
- cupsArrayAdd(ra, "job-hold-until-default");
- cupsArrayAdd(ra, "job-priority-default");
- cupsArrayAdd(ra, "job-sheets-default");
- cupsArrayAdd(ra, "media-default");
- cupsArrayAdd(ra, "media-col-default");
- cupsArrayAdd(ra, "number-up-default");
- cupsArrayAdd(ra, "orientation-requested-default");
- cupsArrayAdd(ra, "sides-default");
- }
- else if (!strcmp(value, "subscription-template"))
- {
- cupsArrayAdd(ra, "notify-attributes");
- cupsArrayAdd(ra, "notify-charset");
- cupsArrayAdd(ra, "notify-events");
- cupsArrayAdd(ra, "notify-lease-duration");
- cupsArrayAdd(ra, "notify-natural-language");
- cupsArrayAdd(ra, "notify-pull-method");
- cupsArrayAdd(ra, "notify-recipient-uri");
- cupsArrayAdd(ra, "notify-time-interval");
- cupsArrayAdd(ra, "notify-user-data");
- }
- else
- cupsArrayAdd(ra, value);
- }
-
- return (ra);
-}
-
-
/*
* 'debug_attributes()' - Print attributes in a request or response.
*/
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 */
char buffer[2048]; /* String buffer for value */
+ int major, minor; /* Version */
if (Verbosity <= 1)
return;
fprintf(stderr, "%s:\n", title);
- for (attr = ipp->attrs, group_tag = IPP_TAG_ZERO; attr; attr = attr->next)
+ major = ippGetVersion(ipp, &minor);
+ fprintf(stderr, " version=%d.%d\n", major, minor);
+ if (type == 1)
+ fprintf(stderr, " operation-id=%s(%04x)\n",
+ ippOpString(ippGetOperation(ipp)), ippGetOperation(ipp));
+ else if (type == 2)
+ fprintf(stderr, " status-code=%s(%04x)\n",
+ ippErrorString(ippGetStatusCode(ipp)), ippGetStatusCode(ipp));
+ fprintf(stderr, " request-id=%d\n\n", ippGetRequestId(ipp));
+
+ for (attr = ippFirstAttribute(ipp), group_tag = IPP_TAG_ZERO;
+ attr;
+ attr = ippNextAttribute(ipp))
{
- if (attr->group_tag != group_tag)
+ if (ippGetGroupTag(attr) != group_tag)
{
- group_tag = attr->group_tag;
+ group_tag = ippGetGroupTag(attr);
fprintf(stderr, " %s\n", ippTagString(group_tag));
}
- if (attr->name)
+ if (ippGetName(attr))
{
- _ippAttrString(attr, buffer, sizeof(buffer));
- fprintf(stderr, " %s (%s%s) %s\n", attr->name,
- attr->num_values > 1 ? "1setOf " : "",
- ippTagString(attr->value_tag), buffer);
+ ippAttributeString(attr, buffer, sizeof(buffer));
+ fprintf(stderr, " %s (%s%s) %s\n", ippGetName(attr),
+ ippGetCount(attr) > 1 ? "1setOf " : "",
+ ippTagString(ippGetValueTag(attr)), buffer);
}
}
}
delete_client(_ipp_client_t *client) /* I - Client */
{
if (Verbosity)
- fprintf(stderr, "Closing connection from %s (%s)\n", client->http.hostname,
- client->http.hostaddr->addr.sa_family == AF_INET ? "IPv4" : "IPv6");
+ fprintf(stderr, "Closing connection from %s\n", client->hostname);
/*
* Flush pending writes before closing...
*/
- httpFlushWrite(&(client->http));
-
- if (client->http.fd >= 0)
- close(client->http.fd);
+ httpFlushWrite(client->http);
/*
* Free memory...
*/
- httpClearCookie(&(client->http));
- httpClearFields(&(client->http));
+ httpClose(client->http);
ippDelete(client->request);
-
ippDelete(client->response);
free(client);
if (printer->ipp_ref)
DNSServiceRefDeallocate(printer->ipp_ref);
+# ifdef HAVE_SSL
+ if (printer->ipps_ref)
+ DNSServiceRefDeallocate(printer->ipps_ref);
+# endif /* HAVE_SSL */
if (printer->http_ref)
DNSServiceRefDeallocate(printer->http_ref);
TXTRecordDeallocate(&(printer->ipp_txt));
if (printer->dnssd_name)
- _cupsStrFree(printer->dnssd_name);
+ free(printer->dnssd_name);
#endif /* HAVE_DNSSD */
if (printer->name)
- _cupsStrFree(printer->name);
+ free(printer->name);
if (printer->icon)
- _cupsStrFree(printer->icon);
+ free(printer->icon);
+ if (printer->command)
+ free(printer->command);
if (printer->directory)
- _cupsStrFree(printer->directory);
+ free(printer->directory);
if (printer->hostname)
- _cupsStrFree(printer->hostname);
+ free(printer->hostname);
if (printer->uri)
- _cupsStrFree(printer->uri);
+ free(printer->uri);
ippDelete(printer->attrs);
cupsArrayDelete(printer->jobs);
const char *domain, /* I - Domain for service */
_ipp_printer_t *printer) /* I - Printer */
{
+ (void)sdRef;
+ (void)flags;
+ (void)domain;
+
if (errorCode)
{
fprintf(stderr, "DNSServiceRegister for %s failed with error %d.\n",
fprintf(stderr, "Now using DNS-SD service name \"%s\".\n", name);
/* No lock needed since only the main thread accesses/changes this */
- _cupsStrFree(printer->dnssd_name);
- printer->dnssd_name = _cupsStrAlloc(name);
+ free(printer->dnssd_name);
+ printer->dnssd_name = strdup(name);
}
}
#endif /* HAVE_DNSSD */
if ((attr = ippFindAttribute(client->request, "job-uri",
IPP_TAG_URI)) != NULL)
{
- if (!strncmp(attr->values[0].string.text, client->printer->uri,
- client->printer->urilen) &&
- attr->values[0].string.text[client->printer->urilen] == '/')
- key.id = atoi(attr->values[0].string.text + client->printer->urilen + 1);
+ const char *uri = ippGetString(attr, 0, NULL);
+
+ if (!strncmp(uri, client->printer->uri, client->printer->urilen) &&
+ uri[client->printer->urilen] == '/')
+ key.id = atoi(uri + client->printer->urilen + 1);
}
else if ((attr = ippFindAttribute(client->request, "job-id",
IPP_TAG_INTEGER)) != NULL)
- key.id = attr->values[0].integer;
+ key.id = ippGetInteger(attr, 0);
_cupsRWLockRead(&(client->printer->rwlock));
job = (_ipp_job_t *)cupsArrayFind(client->printer->jobs, &key);
if (*s == '&' || *s == '<')
{
if (s > start)
- httpWrite2(&(client->http), start, s - start);
+ httpWrite2(client->http, start, (size_t)(s - start));
if (*s == '&')
- httpWrite2(&(client->http), "&", 5);
+ httpWrite2(client->http, "&", 5);
else
- httpWrite2(&(client->http), "<", 4);
+ httpWrite2(client->http, "<", 4);
start = s + 1;
}
}
if (s > start)
- httpWrite2(&(client->http), start, s - start);
+ httpWrite2(client->http, start, (size_t)(s - start));
}
if (*format == '%')
{
if (format > start)
- httpWrite2(&(client->http), start, format - start);
+ httpWrite2(client->http, start, (size_t)(format - start));
tptr = tformat;
*tptr++ = *format++;
if (*format == '%')
{
- httpWrite2(&(client->http), "%", 1);
+ httpWrite2(client->http, "%", 1);
format ++;
continue;
}
format ++;
width = va_arg(ap, int);
- snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width);
+ snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", width);
tptr += strlen(tptr);
}
else
format ++;
prec = va_arg(ap, int);
- snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec);
+ snprintf(tptr, sizeof(tformat) - (size_t)(tptr - tformat), "%d", prec);
tptr += strlen(tptr);
}
else
case 'e' :
case 'f' :
case 'g' :
- if ((width + 2) > sizeof(temp))
+ if ((size_t)(width + 2) > sizeof(temp))
break;
sprintf(temp, tformat, va_arg(ap, double));
- httpWrite2(&(client->http), temp, strlen(temp));
+ httpWrite2(client->http, temp, strlen(temp));
break;
case 'B' : /* Integer formats */
case 'o' :
case 'u' :
case 'x' :
- if ((width + 2) > sizeof(temp))
+ if ((size_t)(width + 2) > sizeof(temp))
break;
# ifdef HAVE_LONG_LONG
else
sprintf(temp, tformat, va_arg(ap, int));
- httpWrite2(&(client->http), temp, strlen(temp));
+ httpWrite2(client->http, temp, strlen(temp));
break;
case 'p' : /* Pointer value */
- if ((width + 2) > sizeof(temp))
+ if ((size_t)(width + 2) > sizeof(temp))
break;
sprintf(temp, tformat, va_arg(ap, void *));
- httpWrite2(&(client->http), temp, strlen(temp));
+ httpWrite2(client->http, temp, strlen(temp));
break;
case 'c' : /* Character or character array */
if (width <= 1)
{
- temp[0] = va_arg(ap, int);
+ temp[0] = (char)va_arg(ap, int);
temp[1] = '\0';
html_escape(client, temp, 1);
}
}
if (format > start)
- httpWrite2(&(client->http), start, format - start);
+ httpWrite2(client->http, start, (size_t)(format - start));
va_end(ap);
}
*/
if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job does not exist.");
return;
+ }
/*
* See if the job is already completed, canceled, or aborted; if so,
switch (job->state)
{
- case IPP_JOB_CANCELED :
- respond_ipp(client, IPP_NOT_POSSIBLE,
+ case IPP_JSTATE_CANCELED :
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE,
"Job #%d is already canceled - can\'t cancel.", job->id);
break;
- case IPP_JOB_ABORTED :
- respond_ipp(client, IPP_NOT_POSSIBLE,
+ case IPP_JSTATE_ABORTED :
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE,
"Job #%d is already aborted - can\'t cancel.", job->id);
break;
- case IPP_JOB_COMPLETED :
- respond_ipp(client, IPP_NOT_POSSIBLE,
+ case IPP_JSTATE_COMPLETED :
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE,
"Job #%d is already completed - can\'t cancel.", job->id);
break;
_cupsRWLockWrite(&(client->printer->rwlock));
- if (job->state == IPP_JOB_PROCESSING ||
- (job->state == IPP_JOB_HELD && job->fd >= 0))
+ if (job->state == IPP_JSTATE_PROCESSING ||
+ (job->state == IPP_JSTATE_HELD && job->fd >= 0))
job->cancel = 1;
else
{
- job->state = IPP_JOB_CANCELED;
+ job->state = IPP_JSTATE_CANCELED;
job->completed = time(NULL);
}
_cupsRWUnlock(&(client->printer->rwlock));
- respond_ipp(client, IPP_OK, NULL);
+ respond_ipp(client, IPP_STATUS_OK, NULL);
break;
}
}
-#if 0
/*
* 'ipp_create_job()' - Create a job object.
*/
static void
ipp_create_job(_ipp_client_t *client) /* I - Client */
{
-}
-#endif /* 0 */
+ _ipp_job_t *job; /* New job */
+ cups_array_t *ra; /* Attributes to send in response */
-/*
- * 'ipp_get_job_attributes()' - Get the attributes for a job object.
- */
+ /*
+ * Validate print job attributes...
+ */
-static void
-ipp_get_job_attributes(
- _ipp_client_t *client) /* I - Client */
-{
- _ipp_job_t *job; /* Job */
- cups_array_t *ra; /* requested-attributes */
+ if (!valid_job_attributes(client))
+ {
+ httpFlush(client->http);
+ return;
+ }
+ /*
+ * Do we have a file to print?
+ */
- if ((job = find_job(client)) == NULL)
+ if (httpGetState(client->http) == HTTP_STATE_POST_RECV)
{
- respond_ipp(client, IPP_NOT_FOUND, "Job not found.");
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
+ "Unexpected document data following request.");
return;
}
- respond_ipp(client, IPP_OK, NULL);
+ /*
+ * Create the job...
+ */
- ra = create_requested_array(client);
- copy_job_attributes(client, job, ra);
- cupsArrayDelete(ra);
+ if ((job = create_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_BUSY,
+ "Currently printing another job.");
+ return;
+ }
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_STATUS_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_get_job_attributes()' - Get the attributes for a job object.
+ */
+
+static void
+ipp_get_job_attributes(
+ _ipp_client_t *client) /* I - Client */
+{
+ _ipp_job_t *job; /* Job */
+ cups_array_t *ra; /* requested-attributes */
+
+
+ if ((job = find_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "Job not found.");
+ return;
+ }
+
+ respond_ipp(client, IPP_STATUS_OK, NULL);
+
+ ra = ippCreateRequestedArray(client->request);
+ copy_job_attributes(client, job, ra);
+ cupsArrayDelete(ra);
}
ipp_get_jobs(_ipp_client_t *client) /* I - Client */
{
ipp_attribute_t *attr; /* Current attribute */
+ const char *which_jobs = NULL;
+ /* which-jobs values */
int job_comparison; /* Job comparison */
ipp_jstate_t job_state; /* job-state value */
int first_job_id, /* First job ID */
if ((attr = ippFindAttribute(client->request, "which-jobs",
IPP_TAG_KEYWORD)) != NULL)
- fprintf(stderr, "%s Get-Jobs which-jobs=%s", client->http.hostname,
- attr->values[0].string.text);
+ {
+ which_jobs = ippGetString(attr, 0, NULL);
+ fprintf(stderr, "%s Get-Jobs which-jobs=%s", client->hostname, which_jobs);
+ }
- if (!attr || !strcmp(attr->values[0].string.text, "not-completed"))
+ if (!which_jobs || !strcmp(which_jobs, "not-completed"))
{
job_comparison = -1;
- job_state = IPP_JOB_STOPPED;
+ job_state = IPP_JSTATE_STOPPED;
}
- else if (!strcmp(attr->values[0].string.text, "completed"))
+ else if (!strcmp(which_jobs, "completed"))
{
job_comparison = 1;
- job_state = IPP_JOB_CANCELED;
+ job_state = IPP_JSTATE_CANCELED;
}
- else if (!strcmp(attr->values[0].string.text, "aborted"))
+ else if (!strcmp(which_jobs, "aborted"))
{
job_comparison = 0;
- job_state = IPP_JOB_ABORTED;
+ job_state = IPP_JSTATE_ABORTED;
}
- else if (!strcmp(attr->values[0].string.text, "all"))
+ else if (!strcmp(which_jobs, "all"))
{
job_comparison = 1;
- job_state = IPP_JOB_PENDING;
+ job_state = IPP_JSTATE_PENDING;
}
- else if (!strcmp(attr->values[0].string.text, "canceled"))
+ else if (!strcmp(which_jobs, "canceled"))
{
job_comparison = 0;
- job_state = IPP_JOB_CANCELED;
+ job_state = IPP_JSTATE_CANCELED;
}
- else if (!strcmp(attr->values[0].string.text, "pending"))
+ else if (!strcmp(which_jobs, "pending"))
{
job_comparison = 0;
- job_state = IPP_JOB_PENDING;
+ job_state = IPP_JSTATE_PENDING;
}
- else if (!strcmp(attr->values[0].string.text, "pending-held"))
+ else if (!strcmp(which_jobs, "pending-held"))
{
job_comparison = 0;
- job_state = IPP_JOB_HELD;
+ job_state = IPP_JSTATE_HELD;
}
- else if (!strcmp(attr->values[0].string.text, "processing"))
+ else if (!strcmp(which_jobs, "processing"))
{
job_comparison = 0;
- job_state = IPP_JOB_PROCESSING;
+ job_state = IPP_JSTATE_PROCESSING;
}
- else if (!strcmp(attr->values[0].string.text, "processing-stopped"))
+ else if (!strcmp(which_jobs, "processing-stopped"))
{
job_comparison = 0;
- job_state = IPP_JOB_STOPPED;
+ job_state = IPP_JSTATE_STOPPED;
}
else
{
- respond_ipp(client, IPP_ATTRIBUTES,
- "The which-jobs value \"%s\" is not supported.",
- attr->values[0].string.text);
+ respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES,
+ "The which-jobs value \"%s\" is not supported.", which_jobs);
ippAddString(client->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD,
- "which-jobs", NULL, attr->values[0].string.text);
+ "which-jobs", NULL, which_jobs);
return;
}
if ((attr = ippFindAttribute(client->request, "limit",
IPP_TAG_INTEGER)) != NULL)
{
- limit = attr->values[0].integer;
+ limit = ippGetInteger(attr, 0);
- fprintf(stderr, "%s Get-Jobs limit=%d", client->http.hostname, limit);
+ fprintf(stderr, "%s Get-Jobs limit=%d", client->hostname, limit);
}
else
limit = 0;
if ((attr = ippFindAttribute(client->request, "first-job-id",
IPP_TAG_INTEGER)) != NULL)
{
- first_job_id = attr->values[0].integer;
+ first_job_id = ippGetInteger(attr, 0);
- fprintf(stderr, "%s Get-Jobs first-job-id=%d", client->http.hostname,
+ fprintf(stderr, "%s Get-Jobs first-job-id=%d", client->hostname,
first_job_id);
}
else
if ((attr = ippFindAttribute(client->request, "my-jobs",
IPP_TAG_BOOLEAN)) != NULL)
{
- fprintf(stderr, "%s Get-Jobs my-jobs=%s\n", client->http.hostname,
- attr->values[0].boolean ? "true" : "false");
+ int my_jobs = ippGetBoolean(attr, 0);
+
+ fprintf(stderr, "%s Get-Jobs my-jobs=%s\n", client->hostname,
+ my_jobs ? "true" : "false");
- if (attr->values[0].boolean)
+ if (my_jobs)
{
if ((attr = ippFindAttribute(client->request, "requesting-user-name",
IPP_TAG_NAME)) == NULL)
{
- respond_ipp(client, IPP_BAD_REQUEST,
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
"Need requesting-user-name with my-jobs.");
return;
}
- username = attr->values[0].string.text;
+ username = ippGetString(attr, 0, NULL);
fprintf(stderr, "%s Get-Jobs requesting-user-name=\"%s\"\n",
- client->http.hostname, username);
+ client->hostname, username);
}
}
* OK, build a list of jobs for this printer...
*/
- if ((ra = create_requested_array(client)) == NULL &&
- !ippFindAttribute(client->request, "requested-attributes",
- IPP_TAG_KEYWORD))
- {
- /*
- * IPP conformance - Get-Jobs has a default requested-attributes value of
- * "job-id" and "job-uri".
- */
-
- ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
- cupsArrayAdd(ra, "job-id");
- cupsArrayAdd(ra, "job-uri");
- }
+ ra = ippCreateRequestedArray(client->request);
- respond_ipp(client, IPP_OK, NULL);
+ respond_ipp(client, IPP_STATUS_OK, NULL);
_cupsRWLockRead(&(client->printer->rwlock));
(job_comparison == 0 && job->state != job_state) ||
(job_comparison > 0 && job->state < job_state) ||
job->id < first_job_id ||
- (username && job->username && _cups_strcasecmp(username, job->username)))
+ (username && job->username &&
+ _cups_strcasecmp(username, job->username)))
continue;
if (count > 0)
* Send the attributes...
*/
- ra = create_requested_array(client);
+ ra = ippCreateRequestedArray(client->request);
printer = client->printer;
- respond_ipp(client, IPP_OK, NULL);
+ respond_ipp(client, IPP_STATUS_OK, NULL);
_cupsRWLockRead(&(printer->rwlock));
copy_attributes(client->response, printer->attrs, ra, IPP_TAG_ZERO,
- IPP_TAG_COPY);
+ IPP_TAG_CUPS_CONST);
if (!ra || cupsArrayFind(ra, "printer-state"))
ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_ENUM,
if (!ra || cupsArrayFind(ra, "printer-state-reasons"))
{
- if (printer->state_reasons == _IPP_PRINTER_NONE)
+ if (printer->state_reasons == _IPP_PSTATE_NONE)
ippAddString(client->response, IPP_TAG_PRINTER,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "printer-state-reasons",
- NULL, "none");
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "printer-state-reasons", NULL, "none");
else
{
int num_reasons = 0;/* Number of reasons */
const char *reasons[32]; /* Reason strings */
- if (printer->state_reasons & _IPP_PRINTER_OTHER)
+ if (printer->state_reasons & _IPP_PSTATE_OTHER)
reasons[num_reasons ++] = "other";
- if (printer->state_reasons & _IPP_PRINTER_COVER_OPEN)
+ if (printer->state_reasons & _IPP_PSTATE_COVER_OPEN)
reasons[num_reasons ++] = "cover-open";
- if (printer->state_reasons & _IPP_PRINTER_INPUT_TRAY_MISSING)
+ if (printer->state_reasons & _IPP_PSTATE_INPUT_TRAY_MISSING)
reasons[num_reasons ++] = "input-tray-missing";
- if (printer->state_reasons & _IPP_PRINTER_MARKER_SUPPLY_EMPTY)
+ if (printer->state_reasons & _IPP_PSTATE_MARKER_SUPPLY_EMPTY)
reasons[num_reasons ++] = "marker-supply-empty-warning";
- if (printer->state_reasons & _IPP_PRINTER_MARKER_SUPPLY_LOW)
+ if (printer->state_reasons & _IPP_PSTATE_MARKER_SUPPLY_LOW)
reasons[num_reasons ++] = "marker-supply-low-report";
- if (printer->state_reasons & _IPP_PRINTER_MARKER_WASTE_ALMOST_FULL)
+ if (printer->state_reasons & _IPP_PSTATE_MARKER_WASTE_ALMOST_FULL)
reasons[num_reasons ++] = "marker-waste-almost-full-report";
- if (printer->state_reasons & _IPP_PRINTER_MARKER_WASTE_FULL)
+ if (printer->state_reasons & _IPP_PSTATE_MARKER_WASTE_FULL)
reasons[num_reasons ++] = "marker-waste-full-warning";
- if (printer->state_reasons & _IPP_PRINTER_MEDIA_EMPTY)
+ if (printer->state_reasons & _IPP_PSTATE_MEDIA_EMPTY)
reasons[num_reasons ++] = "media-empty-warning";
- if (printer->state_reasons & _IPP_PRINTER_MEDIA_JAM)
+ if (printer->state_reasons & _IPP_PSTATE_MEDIA_JAM)
reasons[num_reasons ++] = "media-jam-warning";
- if (printer->state_reasons & _IPP_PRINTER_MEDIA_LOW)
+ if (printer->state_reasons & _IPP_PSTATE_MEDIA_LOW)
reasons[num_reasons ++] = "media-low-report";
- if (printer->state_reasons & _IPP_PRINTER_MEDIA_NEEDED)
+ if (printer->state_reasons & _IPP_PSTATE_MEDIA_NEEDED)
reasons[num_reasons ++] = "media-needed-report";
- if (printer->state_reasons & _IPP_PRINTER_MOVING_TO_PAUSED)
+ if (printer->state_reasons & _IPP_PSTATE_MOVING_TO_PAUSED)
reasons[num_reasons ++] = "moving-to-paused";
- if (printer->state_reasons & _IPP_PRINTER_PAUSED)
+ if (printer->state_reasons & _IPP_PSTATE_PAUSED)
reasons[num_reasons ++] = "paused";
- if (printer->state_reasons & _IPP_PRINTER_SPOOL_AREA_FULL)
+ if (printer->state_reasons & _IPP_PSTATE_SPOOL_AREA_FULL)
reasons[num_reasons ++] = "spool-area-full";
- if (printer->state_reasons & _IPP_PRINTER_TONER_EMPTY)
+ if (printer->state_reasons & _IPP_PSTATE_TONER_EMPTY)
reasons[num_reasons ++] = "toner-empty-warning";
- if (printer->state_reasons & _IPP_PRINTER_TONER_LOW)
+ if (printer->state_reasons & _IPP_PSTATE_TONER_LOW)
reasons[num_reasons ++] = "toner-low-report";
ippAddStrings(client->response, IPP_TAG_PRINTER,
- IPP_TAG_KEYWORD | IPP_TAG_COPY, "printer-state-reasons",
- num_reasons, NULL, reasons);
+ IPP_CONST_TAG(IPP_TAG_KEYWORD),
+ "printer-state-reasons", num_reasons, NULL, reasons);
}
}
ippAddInteger(client->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
"queued-job-count",
printer->active_job &&
- printer->active_job->state < IPP_JOB_CANCELED);
+ printer->active_job->state < IPP_JSTATE_CANCELED);
_cupsRWUnlock(&(printer->rwlock));
if (!valid_job_attributes(client))
{
- httpFlush(&(client->http));
+ httpFlush(client->http);
return;
}
* Do we have a file to print?
*/
- if (client->http.state == HTTP_POST_SEND)
+ if (httpGetState(client->http) == HTTP_STATE_POST_SEND)
{
- respond_ipp(client, IPP_BAD_REQUEST, "No file in request.");
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "No file in request.");
return;
}
if ((job = create_job(client)) == NULL)
{
- respond_ipp(client, IPP_PRINTER_BUSY, "Currently printing another job.");
+ respond_ipp(client, IPP_STATUS_ERROR_BUSY,
+ "Currently printing another job.");
return;
}
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, "image/pwg-raster"))
+ snprintf(filename, sizeof(filename), "%s/%d.ras",
+ 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);
snprintf(filename, sizeof(filename), "%s/%d.prn",
client->printer->directory, job->id);
+ if (Verbosity)
+ fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format);
+
if ((job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
{
- job->state = IPP_JOB_ABORTED;
+ job->state = IPP_JSTATE_ABORTED;
- respond_ipp(client, IPP_INTERNAL_ERROR,
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
"Unable to create print file: %s", strerror(errno));
return;
}
- while ((bytes = httpRead2(&(client->http), buffer, sizeof(buffer))) > 0)
+ while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0)
{
- if (write(job->fd, buffer, bytes) < bytes)
+ if (write(job->fd, buffer, (size_t)bytes) < bytes)
{
int error = errno; /* Write error */
- job->state = IPP_JOB_ABORTED;
+ job->state = IPP_JSTATE_ABORTED;
close(job->fd);
job->fd = -1;
unlink(filename);
- respond_ipp(client, IPP_INTERNAL_ERROR,
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
"Unable to write print file: %s", strerror(error));
return;
}
* Got an error while reading the print data, so abort this job.
*/
- job->state = IPP_JOB_ABORTED;
+ job->state = IPP_JSTATE_ABORTED;
close(job->fd);
job->fd = -1;
unlink(filename);
- respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to read print file.");
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to read print file.");
return;
}
{
int error = errno; /* Write error */
- job->state = IPP_JOB_ABORTED;
+ job->state = IPP_JSTATE_ABORTED;
job->fd = -1;
unlink(filename);
- respond_ipp(client, IPP_INTERNAL_ERROR, "Unable to write print file: %s",
- strerror(error));
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to write print file: %s", strerror(error));
return;
}
job->fd = -1;
job->filename = strdup(filename);
- job->state = IPP_JOB_PENDING;
+ job->state = IPP_JSTATE_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.");
+ job->state = IPP_JSTATE_ABORTED;
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to process job.");
return;
}
+#else
+ process_job(job);
+#endif /* 0 */
+
/*
* Return the job info...
*/
- respond_ipp(client, IPP_OK, NULL);
+ respond_ipp(client, IPP_STATUS_OK, NULL);
ra = cupsArrayNew((cups_array_func_t)strcmp, NULL);
cupsArrayAdd(ra, "job-id");
}
-#if 0
/*
- * 'ipp_send_document()' - Add an attached document to a job object created with
- * Create-Job.
+ * 'ipp_print_uri()' - Create a job object with a referenced document.
*/
static void
-ipp_send_document(_ipp_client_t *client)/* I - Client */
+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 (httpGetState(client->http) == HTTP_STATE_POST_RECV)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_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_STATUS_ERROR_BAD_REQUEST, "Missing document-uri.");
+ return;
+ }
+
+ if (ippGetCount(uri) != 1)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
+ "Too many document-uri values.");
+ return;
+ }
+
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL),
+ scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+ if (uri_status < HTTP_URI_STATUS_OK)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s",
+ uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]);
+ return;
+ }
+
+ if (strcmp(scheme, "file") &&
+#ifdef HAVE_SSL
+ strcmp(scheme, "https") &&
+#endif /* HAVE_SSL */
+ strcmp(scheme, "http"))
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME,
+ "URI scheme \"%s\" not supported.", scheme);
+ return;
+ }
+
+ if (!strcmp(scheme, "file") && access(resource, R_OK))
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "Unable to access URI: %s", strerror(errno));
+ return;
+ }
+
+ /*
+ * Print the job...
+ */
+
+ if ((job = create_job(client)) == NULL)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_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_JSTATE_ABORTED;
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ if (!strcmp(scheme, "file"))
+ {
+ if ((infile = open(resource, O_RDONLY)) < 0)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "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, (size_t)bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ close(infile);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "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_ENCRYPTION_ALWAYS;
+ else
+#endif /* HAVE_SSL */
+ encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+ if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption,
+ 1, 30000, NULL)) == NULL)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "Unable to connect to %s: %s", hostname,
+ cupsLastErrorString());
+ job->state = IPP_JSTATE_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_STATUS_ERROR_DOCUMENT_ACCESS,
+ "Unable to GET URI: %s", strerror(errno));
+
+ job->state = IPP_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
+
+ if (status != HTTP_STATUS_OK)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "Unable to GET URI: %s", httpStatus(status));
+
+ job->state = IPP_JSTATE_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, (size_t)bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ httpClose(http);
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JSTATE_PENDING;
+
+ /*
+ * Process the job...
+ */
+
+#if 0
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JSTATE_ABORTED;
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to process job.");
+ return;
+ }
+
+#else
+ process_job(job);
#endif /* 0 */
+ /*
+ * Return the job info...
+ */
-/*
- * 'ipp_validate_job()' - Validate job creation attributes.
- */
+ respond_ipp(client, IPP_STATUS_OK, NULL);
-static void
-ipp_validate_job(_ipp_client_t *client) /* I - Client */
-{
+ 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);
}
/*
- * 'process_client()' - Process client requests on a thread.
+ * 'ipp_send_document()' - Add an attached document to a job object created with
+ * Create-Job.
*/
-static void * /* O - Exit status */
-process_client(_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_STATUS_ERROR_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_JSTATE_HELD)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE,
+ "Job is not in a pending state.");
+ httpFlush(client->http);
+ return;
+ }
+ else if (job->filename || job->fd >= 0)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_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_STATUS_ERROR_BAD_REQUEST,
+ "Missing required last-document attribute.");
+ httpFlush(client->http);
+ return;
+ }
+ else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 ||
+ !ippGetBoolean(attr, 0))
+ {
+ 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(client->request, "document-format", IPP_TAG_MIMETYPE)) != NULL)
+ job->format = ippGetString(attr, 0, NULL);
+ 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);
+
+ if (Verbosity)
+ fprintf(stderr, "Creating job file \"%s\", format \"%s\".\n", filename, job->format);
+
+ job->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ if (job->fd < 0)
+ {
+ job->state = IPP_JSTATE_ABORTED;
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ while ((bytes = httpRead2(client->http, buffer, sizeof(buffer))) > 0)
+ {
+ if (write(job->fd, buffer, (size_t)bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "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_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to read print file.");
+ return;
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JSTATE_PENDING;
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ /*
+ * Process the job...
+ */
+
+#if 0
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JSTATE_ABORTED;
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to process job.");
+ return;
+ }
+
+#else
+ process_job(job);
+#endif /* 0 */
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_STATUS_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_STATUS_ERROR_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_JSTATE_HELD)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_POSSIBLE,
+ "Job is not in a pending state.");
+ httpFlush(client->http);
+ return;
+ }
+ else if (job->filename || job->fd >= 0)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_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_STATUS_ERROR_BAD_REQUEST,
+ "Missing required last-document attribute.");
+ httpFlush(client->http);
+ return;
+ }
+ else if (ippGetValueTag(attr) != IPP_TAG_BOOLEAN || ippGetCount(attr) != 1 ||
+ !ippGetBoolean(attr, 0))
+ {
+ 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 (httpGetState(client->http) == HTTP_STATE_POST_RECV)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_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_STATUS_ERROR_BAD_REQUEST, "Missing document-uri.");
+ return;
+ }
+
+ if (ippGetCount(uri) != 1)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
+ "Too many document-uri values.");
+ return;
+ }
+
+ uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL),
+ scheme, sizeof(scheme), userpass,
+ sizeof(userpass), hostname, sizeof(hostname),
+ &port, resource, sizeof(resource));
+ if (uri_status < HTTP_URI_STATUS_OK)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s",
+ uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]);
+ return;
+ }
+
+ if (strcmp(scheme, "file") &&
+#ifdef HAVE_SSL
+ strcmp(scheme, "https") &&
+#endif /* HAVE_SSL */
+ strcmp(scheme, "http"))
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME,
+ "URI scheme \"%s\" not supported.", scheme);
+ return;
+ }
+
+ if (!strcmp(scheme, "file") && access(resource, R_OK))
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "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 = ippGetString(attr, 0, NULL);
+ 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_JSTATE_ABORTED;
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to create print file: %s", strerror(errno));
+ return;
+ }
+
+ if (!strcmp(scheme, "file"))
+ {
+ if ((infile = open(resource, O_RDONLY)) < 0)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "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, (size_t)bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ close(infile);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "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_ENCRYPTION_ALWAYS;
+ else
+#endif /* HAVE_SSL */
+ encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+ if ((http = httpConnect2(hostname, port, NULL, AF_UNSPEC, encryption,
+ 1, 30000, NULL)) == NULL)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "Unable to connect to %s: %s", hostname,
+ cupsLastErrorString());
+ job->state = IPP_JSTATE_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_STATUS_ERROR_DOCUMENT_ACCESS,
+ "Unable to GET URI: %s", strerror(errno));
+
+ job->state = IPP_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+ return;
+ }
+
+ while ((status = httpUpdate(http)) == HTTP_STATUS_CONTINUE);
+
+ if (status != HTTP_STATUS_OK)
+ {
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS,
+ "Unable to GET URI: %s", httpStatus(status));
+
+ job->state = IPP_JSTATE_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, (size_t)bytes) < bytes)
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+
+ close(job->fd);
+ job->fd = -1;
+
+ unlink(filename);
+ httpClose(http);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+ }
+
+ httpClose(http);
+ }
+
+ if (close(job->fd))
+ {
+ int error = errno; /* Write error */
+
+ job->state = IPP_JSTATE_ABORTED;
+ job->fd = -1;
+
+ unlink(filename);
+
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
+ "Unable to write print file: %s", strerror(error));
+ return;
+ }
+
+ _cupsRWLockWrite(&(client->printer->rwlock));
+
+ job->fd = -1;
+ job->filename = strdup(filename);
+ job->state = IPP_JSTATE_PENDING;
+
+ _cupsRWUnlock(&(client->printer->rwlock));
+
+ /*
+ * Process the job...
+ */
+
+#if 0
+ if (!_cupsThreadCreate((_cups_thread_func_t)process_job, job))
+ {
+ job->state = IPP_JSTATE_ABORTED;
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to process job.");
+ return;
+ }
+
+#else
+ process_job(job);
+#endif /* 0 */
+
+ /*
+ * Return the job info...
+ */
+
+ respond_ipp(client, IPP_STATUS_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.
+ */
+
+static void
+ipp_validate_job(_ipp_client_t *client) /* I - Client */
+{
+ if (valid_job_attributes(client))
+ respond_ipp(client, IPP_STATUS_OK, NULL);
+}
+
+
+/*
+ * 'process_client()' - Process client requests on a thread.
+ */
+
+static void * /* O - Exit status */
+process_client(_ipp_client_t *client) /* I - Client */
{
/*
* Loop until we are out of requests or timeout (30 seconds)...
*/
- while (httpWait(&(client->http), 30000))
+#ifdef HAVE_SSL
+ int first_time = 1; /* First time request? */
+#endif /* HAVE_SSL */
+
+ while (httpWait(client->http, 30000))
+ {
+#ifdef HAVE_SSL
+ if (first_time)
+ {
+ /*
+ * See if we need to negotiate a TLS connection...
+ */
+
+ char buf[1]; /* First byte from client */
+
+ if (recv(httpGetFd(client->http), buf, 1, MSG_PEEK) == 1 && (!buf[0] || !strchr("DGHOPT", buf[0])))
+ {
+ fprintf(stderr, "%s Negotiating TLS session.\n", client->hostname);
+
+ if (httpEncryption(client->http, HTTP_ENCRYPTION_ALWAYS))
+ {
+ fprintf(stderr, "%s Unable to encrypt connection: %s\n", client->hostname, cupsLastErrorString());
+ break;
+ }
+ }
+
+ first_time = 0;
+ }
+#endif /* HAVE_SSL */
+
if (!process_http(client))
break;
+ }
/*
* Close the conection to the client and return...
int /* O - 1 on success, 0 on failure */
process_http(_ipp_client_t *client) /* I - Client connection */
{
- char line[4096], /* Line from client... */
- operation[64], /* Operation code from socket */
- uri[1024], /* URI */
- version[64], /* HTTP version number string */
- *ptr; /* Pointer into strings */
- int major, minor; /* HTTP version numbers */
- http_status_t status; /* Transfer status */
- ipp_state_t state; /* State of IPP transfer */
-
-
- /*
- * Abort if we have an error on the connection...
- */
+ char uri[1024]; /* URI */
+ http_state_t http_state; /* HTTP state */
+ http_status_t http_status; /* HTTP status */
+ ipp_state_t ipp_state; /* State of IPP transfer */
+ char scheme[32], /* Method/scheme */
+ userpass[128], /* Username:password */
+ hostname[HTTP_MAX_HOST];
+ /* Hostname */
+ int port; /* Port number */
+ const char *encoding; /* Content-Encoding value */
+ static const char * const http_states[] =
+ { /* Strings for logging HTTP method */
+ "WAITING",
+ "OPTIONS",
+ "GET",
+ "GET_SEND",
+ "HEAD",
+ "POST",
+ "POST_RECV",
+ "POST_SEND",
+ "PUT",
+ "PUT_RECV",
+ "DELETE",
+ "TRACE",
+ "CONNECT",
+ "STATUS",
+ "UNKNOWN_METHOD",
+ "UNKNOWN_VERSION"
+ };
- if (client->http.error)
- return (0);
/*
* Clear state variables...
*/
- httpClearFields(&(client->http));
ippDelete(client->request);
ippDelete(client->response);
- client->http.activity = time(NULL);
- client->http.version = HTTP_1_1;
- client->http.keep_alive = HTTP_KEEPALIVE_OFF;
- client->http.data_encoding = HTTP_ENCODE_LENGTH;
- client->http.data_remaining = 0;
- client->request = NULL;
- client->response = NULL;
- client->operation = HTTP_WAITING;
+ client->request = NULL;
+ client->response = NULL;
+ client->operation = HTTP_STATE_WAITING;
/*
* Read a request from the connection...
*/
- while ((ptr = httpGets(line, sizeof(line) - 1, &(client->http))) != NULL)
- if (*ptr)
- break;
-
- if (!ptr)
- return (0);
+ while ((http_state = httpReadRequest(client->http, uri,
+ sizeof(uri))) == HTTP_STATE_WAITING)
+ usleep(1);
/*
* Parse the request line...
*/
- fprintf(stderr, "%s %s\n", client->http.hostname, line);
-
- switch (sscanf(line, "%63s%1023s%63s", operation, uri, version))
+ if (http_state == HTTP_STATE_ERROR)
{
- case 1 :
- fprintf(stderr, "%s Bad request line.\n", client->http.hostname);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
-
- case 2 :
- client->http.version = HTTP_0_9;
- break;
-
- case 3 :
- if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2)
- {
- fprintf(stderr, "%s Bad HTTP version.\n", client->http.hostname);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
- }
+ if (httpError(client->http) == EPIPE)
+ fprintf(stderr, "%s Client closed connection.\n", client->hostname);
+ else
+ fprintf(stderr, "%s Bad request line (%s).\n", client->hostname,
+ strerror(httpError(client->http)));
- if (major < 2)
- {
- client->http.version = (http_version_t)(major * 100 + minor);
- if (client->http.version == HTTP_1_1)
- client->http.keep_alive = HTTP_KEEPALIVE_ON;
- else
- client->http.keep_alive = HTTP_KEEPALIVE_OFF;
- }
- else
- {
- respond_http(client, HTTP_NOT_SUPPORTED, NULL, 0);
- return (0);
- }
- break;
+ return (0);
}
-
- /*
- * Handle full URLs in the request line...
- */
-
- if (!strncmp(client->uri, "http:", 5) || !strncmp(client->uri, "ipp:", 4))
+ else if (http_state == HTTP_STATE_UNKNOWN_METHOD)
{
- char scheme[32], /* Method/scheme */
- userpass[128], /* Username:password */
- hostname[HTTP_MAX_HOST];/* Hostname */
- int port; /* Port number */
-
- /*
- * Separate the URI into its components...
- */
-
- if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme),
- userpass, sizeof(userpass),
- hostname, sizeof(hostname), &port,
- client->uri, sizeof(client->uri)) < HTTP_URI_OK)
- {
- fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
- }
+ fprintf(stderr, "%s Bad/unknown operation.\n", client->hostname);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
+ return (0);
}
- else
+ else if (http_state == HTTP_STATE_UNKNOWN_VERSION)
{
- /*
- * Decode URI
- */
-
- if (!_httpDecodeURI(client->uri, uri, sizeof(client->uri)))
- {
- fprintf(stderr, "%s Bad URI \"%s\".\n", client->http.hostname, uri);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
- return (0);
- }
+ fprintf(stderr, "%s Bad HTTP version.\n", client->hostname);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
+ return (0);
}
+ fprintf(stderr, "%s %s %s\n", client->hostname, http_states[http_state],
+ uri);
+
/*
- * Process the request...
+ * Separate the URI into its components...
*/
- if (!strcmp(operation, "GET"))
- client->http.state = HTTP_GET;
- else if (!strcmp(operation, "POST"))
- client->http.state = HTTP_POST;
- else if (!strcmp(operation, "OPTIONS"))
- client->http.state = HTTP_OPTIONS;
- else if (!strcmp(operation, "HEAD"))
- client->http.state = HTTP_HEAD;
- else
+ if (httpSeparateURI(HTTP_URI_CODING_MOST, uri, scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ hostname, sizeof(hostname), &port,
+ client->uri, sizeof(client->uri)) < HTTP_URI_STATUS_OK)
{
- fprintf(stderr, "%s Bad operation \"%s\".\n", client->http.hostname,
- operation);
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ fprintf(stderr, "%s Bad URI \"%s\".\n", client->hostname, uri);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
- client->start = time(NULL);
- client->operation = client->http.state;
- client->http.status = HTTP_OK;
+ /*
+ * Process the request...
+ */
+
+ client->start = time(NULL);
+ client->operation = httpGetState(client->http);
/*
* Parse incoming parameters until the status changes...
*/
- while ((status = httpUpdate(&(client->http))) == HTTP_CONTINUE);
+ while ((http_status = httpUpdate(client->http)) == HTTP_STATUS_CONTINUE);
- if (status != HTTP_OK)
+ if (http_status != HTTP_STATUS_OK)
{
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
- if (!client->http.fields[HTTP_FIELD_HOST][0] &&
- client->http.version >= HTTP_1_1)
+ if (!httpGetField(client->http, HTTP_FIELD_HOST)[0] &&
+ httpGetVersion(client->http) >= HTTP_VERSION_1_1)
{
/*
* HTTP/1.1 and higher require the "Host:" field...
*/
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
* Handle HTTP Upgrade...
*/
- if (!_cups_strcasecmp(client->http.fields[HTTP_FIELD_CONNECTION], "Upgrade"))
+ if (!_cups_strcasecmp(httpGetField(client->http, HTTP_FIELD_CONNECTION),
+ "Upgrade"))
{
- if (!respond_http(client, HTTP_NOT_IMPLEMENTED, NULL, 0))
+ if (!respond_http(client, HTTP_STATUS_NOT_IMPLEMENTED, NULL, NULL, 0))
return (0);
}
* Handle HTTP Expect...
*/
- if (client->http.expect &&
- (client->operation == HTTP_POST || client->operation == HTTP_PUT))
+ if (httpGetExpect(client->http) &&
+ (client->operation == HTTP_STATE_POST ||
+ client->operation == HTTP_STATE_PUT))
{
- if (client->http.expect == HTTP_CONTINUE)
+ if (httpGetExpect(client->http) == HTTP_STATUS_CONTINUE)
{
/*
* Send 100-continue header...
*/
- if (!respond_http(client, HTTP_CONTINUE, NULL, 0))
+ if (!respond_http(client, HTTP_STATUS_CONTINUE, NULL, NULL, 0))
return (0);
}
else
* Send 417-expectation-failed header...
*/
- if (!respond_http(client, HTTP_EXPECTATION_FAILED, NULL, 0))
+ if (!respond_http(client, HTTP_STATUS_EXPECTATION_FAILED, NULL, NULL, 0))
return (0);
-
- httpPrintf(&(client->http), "Content-Length: 0\r\n");
- httpPrintf(&(client->http), "\r\n");
- httpFlushWrite(&(client->http));
- client->http.data_encoding = HTTP_ENCODE_LENGTH;
}
}
* Handle new transfers...
*/
+ encoding = httpGetContentEncoding(client->http);
+
switch (client->operation)
{
- case HTTP_OPTIONS :
+ case HTTP_STATE_OPTIONS :
/*
* Do HEAD/OPTIONS command...
*/
- return (respond_http(client, HTTP_OK, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_OK, NULL, NULL, 0));
- case HTTP_HEAD :
+ case HTTP_STATE_HEAD :
if (!strcmp(client->uri, "/icon.png"))
- return (respond_http(client, HTTP_OK, "image/png", 0));
+ return (respond_http(client, HTTP_STATUS_OK, NULL, "image/png", 0));
else if (!strcmp(client->uri, "/"))
- return (respond_http(client, HTTP_OK, "text/html", 0));
+ return (respond_http(client, HTTP_STATUS_OK, NULL, "text/html", 0));
else
- return (respond_http(client, HTTP_NOT_FOUND, NULL, 0));
- break;
+ return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
- case HTTP_GET :
+ case HTTP_STATE_GET :
if (!strcmp(client->uri, "/icon.png"))
{
/*
char buffer[4096]; /* Copy buffer */
ssize_t bytes; /* Bytes */
+ fprintf(stderr, "Icon file is \"%s\".\n", client->printer->icon);
+
if (!stat(client->printer->icon, &fileinfo) &&
(fd = open(client->printer->icon, O_RDONLY)) >= 0)
{
- if (!respond_http(client, HTTP_OK, "image/png", fileinfo.st_size))
+ if (!respond_http(client, HTTP_STATUS_OK, NULL, "image/png",
+ (size_t)fileinfo.st_size))
{
close(fd);
return (0);
}
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
- httpWrite2(&(client->http), buffer, bytes);
+ httpWrite2(client->http, buffer, (size_t)bytes);
- httpFlushWrite(&(client->http));
+ httpFlushWrite(client->http);
close(fd);
}
else
- return (respond_http(client, HTTP_NOT_FOUND, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
}
else if (!strcmp(client->uri, "/"))
{
* Show web status page...
*/
- if (!respond_http(client, HTTP_OK, "text/html", 0))
+ if (!respond_http(client, HTTP_STATUS_OK, encoding, "text/html", 0))
return (0);
html_printf(client,
"</head>\n"
"<body>\n"
"</body>\n"
- "<h1>%s</h1>\n"
+ "<h1><img align=\"right\" src=\"/icon.png\">%s</h1>\n"
"<p>%s, %d job(s).</p>\n"
"</body>\n"
"</html>\n",
client->printer->name, client->printer->name,
- client->printer->state == IPP_PRINTER_IDLE ? "Idle" :
- client->printer->state == IPP_PRINTER_PROCESSING ?
+ client->printer->state == IPP_PSTATE_IDLE ? "Idle" :
+ client->printer->state == IPP_PSTATE_PROCESSING ?
"Printing" : "Stopped",
cupsArrayCount(client->printer->jobs));
- httpWrite2(&(client->http), "", 0);
+ httpWrite2(client->http, "", 0);
return (1);
}
else
- return (respond_http(client, HTTP_NOT_FOUND, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_NOT_FOUND, NULL, NULL, 0));
break;
- case HTTP_POST :
- if (client->http.data_remaining < 0 ||
- (!client->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] &&
- client->http.data_encoding == HTTP_ENCODE_LENGTH))
- {
- /*
- * Negative content lengths are invalid...
- */
-
- return (respond_http(client, HTTP_BAD_REQUEST, NULL, 0));
- }
-
- if (strcmp(client->http.fields[HTTP_FIELD_CONTENT_TYPE],
+ case HTTP_STATE_POST :
+ if (strcmp(httpGetField(client->http, HTTP_FIELD_CONTENT_TYPE),
"application/ipp"))
{
/*
* Not an IPP request...
*/
- return (respond_http(client, HTTP_BAD_REQUEST, NULL, 0));
+ return (respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0));
}
/*
client->request = ippNew();
- while ((state = ippRead(&(client->http), client->request)) != IPP_DATA)
- if (state == IPP_ERROR)
+ while ((ipp_state = ippRead(client->http,
+ client->request)) != IPP_STATE_DATA)
+ {
+ if (ipp_state == IPP_STATE_ERROR)
{
- fprintf(stderr, "%s IPP read error (%s).\n", client->http.hostname,
- ippOpString(client->request->request.op.operation_id));
- respond_http(client, HTTP_BAD_REQUEST, NULL, 0);
+ fprintf(stderr, "%s IPP read error (%s).\n", client->hostname,
+ cupsLastErrorString());
+ respond_http(client, HTTP_STATUS_BAD_REQUEST, NULL, NULL, 0);
return (0);
}
+ }
/*
* Now that we have the IPP request, process the request...
ipp_attribute_t *charset; /* Character set attribute */
ipp_attribute_t *language; /* Language attribute */
ipp_attribute_t *uri; /* Printer URI attribute */
+ int major, minor; /* Version number */
+ const char *name; /* Name of attribute */
- debug_attributes("Request", client->request);
+ debug_attributes("Request", client->request, 1);
/*
* First build an empty response message for this request...
*/
- client->operation_id = client->request->request.op.operation_id;
- client->response = ippNew();
-
- client->response->request.status.version[0] =
- client->request->request.op.version[0];
- client->response->request.status.version[1] =
- client->request->request.op.version[1];
- client->response->request.status.request_id =
- client->request->request.op.request_id;
+ client->operation_id = ippGetOperation(client->request);
+ client->response = ippNewResponse(client->request);
/*
* Then validate the request header and required attributes...
*/
- if (client->request->request.any.version[0] < 1 ||
- client->request->request.any.version[0] > 2)
+ major = ippGetVersion(client->request, &minor);
+
+ if (major < 1 || major > 2)
{
/*
* Return an error, since we only support IPP 1.x and 2.x.
*/
- respond_ipp(client, IPP_VERSION_NOT_SUPPORTED,
- "Bad request version number %d.%d.",
- client->request->request.any.version[0],
- client->request->request.any.version[1]);
+ respond_ipp(client, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED,
+ "Bad request version number %d.%d.", major, minor);
}
- else if (client->request->request.any.request_id <= 0)
- respond_ipp(client, IPP_BAD_REQUEST, "Bad request-id %d.",
- client->request->request.any.request_id);
- else if (!client->request->attrs)
- respond_ipp(client, IPP_BAD_REQUEST, "No attributes in request.");
+ else if (ippGetRequestId(client->request) <= 0)
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad request-id %d.",
+ ippGetRequestId(client->request));
+ else if (!ippFirstAttribute(client->request))
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
+ "No attributes in request.");
else
{
/*
* don't repeat groups...
*/
- for (attr = client->request->attrs, group = attr->group_tag;
+ for (attr = ippFirstAttribute(client->request),
+ group = ippGetGroupTag(attr);
attr;
- attr = attr->next)
- if (attr->group_tag < group && attr->group_tag != IPP_TAG_ZERO)
+ attr = ippNextAttribute(client->request))
+ {
+ if (ippGetGroupTag(attr) < group && ippGetGroupTag(attr) != IPP_TAG_ZERO)
{
/*
* Out of order; return an error...
*/
- respond_ipp(client, IPP_BAD_REQUEST,
- "Attribute groups are out of order (%x < %x).",
- attr->group_tag, group);
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
+ "Attribute groups are out of order (%x < %x).",
+ ippGetGroupTag(attr), group);
break;
}
else
- group = attr->group_tag;
+ group = ippGetGroupTag(attr);
+ }
if (!attr)
{
* printer-uri/job-uri
*/
- attr = client->request->attrs;
- if (attr && attr->name &&
- !strcmp(attr->name, "attributes-charset") &&
- (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET)
+ attr = ippFirstAttribute(client->request);
+ name = ippGetName(attr);
+ if (attr && name && !strcmp(name, "attributes-charset") &&
+ ippGetValueTag(attr) == IPP_TAG_CHARSET)
charset = attr;
else
charset = NULL;
- if (attr)
- attr = attr->next;
+ attr = ippNextAttribute(client->request);
+ name = ippGetName(attr);
- if (attr && attr->name &&
- !strcmp(attr->name, "attributes-natural-language") &&
- (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE)
+ if (attr && name && !strcmp(name, "attributes-natural-language") &&
+ ippGetValueTag(attr) == IPP_TAG_LANGUAGE)
language = attr;
else
language = NULL;
else
uri = NULL;
- ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
- "attributes-charset", NULL,
- charset ? charset->values[0].string.text : "utf-8");
-
- ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
- "attributes-natural-language", NULL,
- language ? language->values[0].string.text : "en");
-
if (charset &&
- _cups_strcasecmp(charset->values[0].string.text, "us-ascii") &&
- _cups_strcasecmp(charset->values[0].string.text, "utf-8"))
+ _cups_strcasecmp(ippGetString(charset, 0, NULL), "us-ascii") &&
+ _cups_strcasecmp(ippGetString(charset, 0, NULL), "utf-8"))
{
/*
* Bad character set...
*/
- respond_ipp(client, IPP_BAD_REQUEST,
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
"Unsupported character set \"%s\".",
- charset->values[0].string.text);
+ ippGetString(charset, 0, NULL));
}
else if (!charset || !language || !uri)
{
* for all operations.
*/
- respond_ipp(client, IPP_BAD_REQUEST, "Missing required attributes.");
- }
- else if (strcmp(uri->values[0].string.text, client->printer->uri) &&
- strncmp(uri->values[0].string.text, client->printer->uri,
- client->printer->urilen))
- {
- respond_ipp(client, IPP_NOT_FOUND, "%s %s not found.", uri->name,
- uri->values[0].string.text);
+ respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST,
+ "Missing required attributes.");
}
else
{
- /*
- * Try processing the operation...
- */
-
- if (client->http.expect == HTTP_CONTINUE)
+ char scheme[32], /* URI scheme */
+ userpass[32], /* Username/password in URI */
+ host[256], /* Host name in URI */
+ resource[256]; /* Resource path in URI */
+ int port; /* Port number in URI */
+
+ name = ippGetName(uri);
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL),
+ scheme, sizeof(scheme),
+ userpass, sizeof(userpass),
+ host, sizeof(host), &port,
+ resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+ respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES,
+ "Bad %s value '%s'.", name, ippGetString(uri, 0, NULL));
+ else if ((!strcmp(name, "job-uri") &&
+ strncmp(resource, "/ipp/print/", 11)) ||
+ (!strcmp(name, "printer-uri") &&
+ strcmp(resource, "/ipp/print")))
+ respond_ipp(client, IPP_STATUS_ERROR_NOT_FOUND, "%s %s not found.",
+ name, ippGetString(uri, 0, NULL));
+ else
{
/*
- * Send 100-continue header...
+ * Try processing the operation...
*/
- if (!respond_http(client, HTTP_CONTINUE, NULL, 0))
- return (0);
- }
-
- switch (client->request->request.op.operation_id)
- {
- case IPP_PRINT_JOB :
- ipp_print_job(client);
- break;
-
- case IPP_VALIDATE_JOB :
- ipp_validate_job(client);
- break;
-
- case IPP_CANCEL_JOB :
- ipp_cancel_job(client);
- break;
-
- case IPP_GET_JOB_ATTRIBUTES :
- ipp_get_job_attributes(client);
- break;
-
- case IPP_GET_JOBS :
- ipp_get_jobs(client);
- break;
-
- case IPP_GET_PRINTER_ATTRIBUTES :
- ipp_get_printer_attributes(client);
- break;
-
- default :
- respond_ipp(client, IPP_OPERATION_NOT_SUPPORTED,
- "Operation not supported.");
- break;
+ switch (ippGetOperation(client->request))
+ {
+ case IPP_OP_PRINT_JOB :
+ ipp_print_job(client);
+ break;
+
+ case IPP_OP_PRINT_URI :
+ ipp_print_uri(client);
+ break;
+
+ case IPP_OP_VALIDATE_JOB :
+ ipp_validate_job(client);
+ break;
+
+ case IPP_OP_CREATE_JOB :
+ ipp_create_job(client);
+ break;
+
+ case IPP_OP_SEND_DOCUMENT :
+ ipp_send_document(client);
+ break;
+
+ case IPP_OP_SEND_URI :
+ ipp_send_uri(client);
+ break;
+
+ case IPP_OP_CANCEL_JOB :
+ ipp_cancel_job(client);
+ break;
+
+ case IPP_OP_GET_JOB_ATTRIBUTES :
+ ipp_get_job_attributes(client);
+ break;
+
+ case IPP_OP_GET_JOBS :
+ ipp_get_jobs(client);
+ break;
+
+ case IPP_OP_GET_PRINTER_ATTRIBUTES :
+ ipp_get_printer_attributes(client);
+ break;
+
+ default :
+ respond_ipp(client, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED,
+ "Operation not supported.");
+ break;
+ }
}
}
}
* Send the HTTP header and return...
*/
- if (client->http.state != HTTP_POST_SEND)
- httpFlush(&(client->http)); /* Flush trailing (junk) data */
+ if (httpGetState(client->http) != HTTP_STATE_POST_SEND)
+ httpFlush(client->http); /* Flush trailing (junk) data */
- return (respond_http(client, HTTP_OK, "application/ipp",
+ return (respond_http(client, HTTP_STATUS_OK, NULL, "application/ipp",
ippLength(client->response)));
}
static void * /* O - Thread exit status */
process_job(_ipp_job_t *job) /* I - Job */
{
- job->state = IPP_JOB_PROCESSING;
- job->printer->state = IPP_PRINTER_PROCESSING;
+ job->state = IPP_JSTATE_PROCESSING;
+ job->printer->state = IPP_PSTATE_PROCESSING;
+
+ if (job->printer->command)
+ {
+ /*
+ * Execute a command with the job spool file and wait for it to complete...
+ */
+
+ int pid, /* Process ID */
+ status; /* Exit status */
+ time_t start, /* Start time */
+ end; /* End time */
+
+ fprintf(stderr, "Running command \"%s %s\".\n", job->printer->command,
+ job->filename);
+ time(&start);
+
+ if ((pid = fork()) == 0)
+ {
+ /*
+ * Child comes here...
+ */
+
+ execlp(job->printer->command, job->printer->command, job->filename,
+ (void *)NULL);
+ exit(errno);
+ }
+ else if (pid < 0)
+ {
+ /*
+ * Unable to fork process...
+ */
+
+ perror("Unable to start job processing command");
+ }
+ else
+ {
+ /*
+ * Wait for child to complete...
+ */
+
+#ifdef HAVE_WAITPID
+ while (waitpid(pid, &status, 0) < 0);
+#else
+ while (wait(&status) < 0);
+#endif /* HAVE_WAITPID */
+
+ if (status)
+ {
+ if (WIFEXITED(status))
+ fprintf(stderr, "Command \"%s\" exited with status %d.\n",
+ job->printer->command, WEXITSTATUS(status));
+ else
+ fprintf(stderr, "Command \"%s\" terminated with signal %d.\n",
+ job->printer->command, WTERMSIG(status));
+ }
+ else
+ fprintf(stderr, "Command \"%s\" completed successfully.\n",
+ job->printer->command);
+ }
+
+ /*
+ * Make sure processing takes at least 5 seconds...
+ */
+
+ time(&end);
+ if ((end - start) < 5)
+ sleep(5);
+ }
+ else
+ {
+ /*
+ * Sleep for a random amount of time to simulate job processing.
+ */
- sleep(5);
+ sleep(5 + (rand() % 11));
+ }
if (job->cancel)
- job->state = IPP_JOB_CANCELED;
+ job->state = IPP_JSTATE_CANCELED;
else
- job->state = IPP_JOB_COMPLETED;
+ job->state = IPP_JSTATE_COMPLETED;
job->completed = time(NULL);
- job->printer->state = IPP_PRINTER_IDLE;
+ job->printer->state = IPP_PSTATE_IDLE;
job->printer->active_job = NULL;
return (NULL);
const char *adminurl, /* I - Web interface URL */
int color, /* I - 1 = color, 0 = monochrome */
int duplex, /* I - 1 = duplex, 0 = simplex */
- const char *regtype) /* I - Service type */
+ const char *subtype) /* I - Service subtype */
{
DNSServiceErrorType error; /* Error from Bonjour */
char make_model[256],/* Make and model together */
- product[256]; /* Product string */
+ product[256], /* Product string */
+ regtype[256]; /* Bonjour service type */
/*
snprintf(product, sizeof(product), "(%s)", model);
TXTRecordCreate(&(printer->ipp_txt), 1024, NULL);
- TXTRecordSetValue(&(printer->ipp_txt), "txtvers", 1, "1");
- TXTRecordSetValue(&(printer->ipp_txt), "qtotal", 1, "1");
- TXTRecordSetValue(&(printer->ipp_txt), "rp", 3, "ipp");
+ TXTRecordSetValue(&(printer->ipp_txt), "rp", 9, "ipp/print");
TXTRecordSetValue(&(printer->ipp_txt), "ty", (uint8_t)strlen(make_model),
make_model);
TXTRecordSetValue(&(printer->ipp_txt), "adminurl", (uint8_t)strlen(adminurl),
adminurl);
- TXTRecordSetValue(&(printer->ipp_txt), "note", (uint8_t)strlen(location),
- location);
- TXTRecordSetValue(&(printer->ipp_txt), "priority", 1, "0");
+ if (*location)
+ TXTRecordSetValue(&(printer->ipp_txt), "note", (uint8_t)strlen(location),
+ location);
TXTRecordSetValue(&(printer->ipp_txt), "product", (uint8_t)strlen(product),
product);
TXTRecordSetValue(&(printer->ipp_txt), "pdl", (uint8_t)strlen(formats),
make);
TXTRecordSetValue(&(printer->ipp_txt), "usb_MDL", (uint8_t)strlen(model),
model);
- TXTRecordSetValue(&(printer->ipp_txt), "air", 4, "none");
/*
* Create a shared service reference for Bonjour...
printer->ipp_ref = printer->common_ref;
+ if (subtype && *subtype)
+ snprintf(regtype, sizeof(regtype), "_ipp._tcp,%s", subtype);
+ else
+ strlcpy(regtype, "_ipp._tcp", sizeof(regtype));
+
if ((error = DNSServiceRegister(&(printer->ipp_ref),
kDNSServiceFlagsShareConnection,
0 /* interfaceIndex */, printer->dnssd_name,
return (0);
}
+# ifdef HAVE_SSL
+ /*
+ * Then register the _ipps._tcp (IPP) service type with the real port number to
+ * advertise our IPP printer...
+ */
+
+ printer->ipps_ref = printer->common_ref;
+
+ if (subtype && *subtype)
+ snprintf(regtype, sizeof(regtype), "_ipps._tcp,%s", subtype);
+ else
+ strlcpy(regtype, "_ipps._tcp", sizeof(regtype));
+
+ if ((error = DNSServiceRegister(&(printer->ipps_ref),
+ kDNSServiceFlagsShareConnection,
+ 0 /* interfaceIndex */, printer->dnssd_name,
+ regtype, NULL /* domain */,
+ NULL /* host */, htons(printer->port),
+ TXTRecordGetLength(&(printer->ipp_txt)),
+ TXTRecordGetBytesPtr(&(printer->ipp_txt)),
+ (DNSServiceRegisterReply)dnssd_callback,
+ printer)) != kDNSServiceErr_NoError)
+ {
+ fprintf(stderr, "Unable to register \"%s.%s\": %d\n",
+ printer->dnssd_name, regtype, error);
+ return (0);
+ }
+# endif /* HAVE_SSL */
+
/*
* Similarly, register the _http._tcp,_printer (HTTP) service type with the
* real port number to advertise our IPP printer...
*/
int /* O - 1 on success, 0 on failure */
-respond_http(_ipp_client_t *client, /* I - Client */
- http_status_t code, /* I - HTTP status of response */
- const char *type, /* I - MIME type of response */
- size_t length) /* I - Length of response */
+respond_http(
+ _ipp_client_t *client, /* I - Client */
+ http_status_t code, /* I - HTTP status of response */
+ const char *content_encoding, /* I - Content-Encoding of response */
+ const char *type, /* I - MIME media type of response */
+ size_t length) /* I - Length of response */
{
char message[1024]; /* Text message */
- fprintf(stderr, "%s %s\n", client->http.hostname, httpStatus(code));
+ fprintf(stderr, "%s %s\n", client->hostname, httpStatus(code));
- if (code == HTTP_CONTINUE)
+ if (code == HTTP_STATUS_CONTINUE)
{
/*
* 100-continue doesn't send any headers...
*/
- return (httpPrintf(&(client->http), "HTTP/%d.%d 100 Continue\r\n\r\n",
- client->http.version / 100,
- client->http.version % 100) > 0);
+ return (httpWriteResponse(client->http, HTTP_STATUS_CONTINUE) == 0);
}
/*
* Format an error message...
*/
- if (!type && !length && code != HTTP_OK)
+ if (!type && !length && code != HTTP_STATUS_OK)
{
snprintf(message, sizeof(message), "%d - %s\n", code, httpStatus(code));
message[0] = '\0';
/*
- * Send the HTTP status header...
- */
-
- httpFlushWrite(&(client->http));
-
- client->http.data_encoding = HTTP_ENCODE_FIELDS;
-
- if (httpPrintf(&(client->http), "HTTP/%d.%d %d %s\r\n", client->http.version / 100,
- client->http.version % 100, code, httpStatus(code)) < 0)
- return (0);
-
- /*
- * Follow the header with the response fields...
+ * Send the HTTP response header...
*/
- if (httpPrintf(&(client->http), "Date: %s\r\n", httpGetDateString(time(NULL))) < 0)
- return (0);
-
- if (client->http.keep_alive && client->http.version >= HTTP_1_0)
- {
- if (httpPrintf(&(client->http),
- "Connection: Keep-Alive\r\n"
- "Keep-Alive: timeout=10\r\n") < 0)
- return (0);
- }
+ httpClearFields(client->http);
- if (code == HTTP_METHOD_NOT_ALLOWED || client->operation == HTTP_OPTIONS)
- {
- if (httpPrintf(&(client->http), "Allow: GET, HEAD, OPTIONS, POST\r\n") < 0)
- return (0);
- }
+ if (code == HTTP_STATUS_METHOD_NOT_ALLOWED ||
+ client->operation == HTTP_STATE_OPTIONS)
+ httpSetField(client->http, HTTP_FIELD_ALLOW, "GET, HEAD, OPTIONS, POST");
if (type)
{
if (!strcmp(type, "text/html"))
- {
- if (httpPrintf(&(client->http),
- "Content-Type: text/html; charset=utf-8\r\n") < 0)
- return (0);
- }
- else if (httpPrintf(&(client->http), "Content-Type: %s\r\n", type) < 0)
- return (0);
- }
+ httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE,
+ "text/html; charset=utf-8");
+ else
+ httpSetField(client->http, HTTP_FIELD_CONTENT_TYPE, type);
- if (length == 0 && !message[0])
- {
- if (httpPrintf(&(client->http), "Transfer-Encoding: chunked\r\n\r\n") < 0)
- return (0);
+ if (content_encoding)
+ httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, content_encoding);
}
- else if (httpPrintf(&(client->http), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
- CUPS_LLCAST length) < 0)
- return (0);
- if (httpFlushWrite(&(client->http)) < 0)
+ httpSetLength(client->http, length);
+
+ if (httpWriteResponse(client->http, code) < 0)
return (0);
/*
* Send a plain text message.
*/
- if (httpPrintf(&(client->http), "%s", message) < 0)
+ if (httpPrintf(client->http, "%s", message) < 0)
+ return (0);
+
+ if (httpWrite2(client->http, "", 0) < 0)
return (0);
}
else if (client->response)
* 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);
- client->response->state = IPP_IDLE;
+ ippSetState(client->response, IPP_STATE_IDLE);
- if (ippWrite(&(client->http), client->response) != IPP_DATA)
+ if (ippWrite(client->http, client->response) != IPP_STATE_DATA)
return (0);
}
- else
- client->http.data_encoding = HTTP_ENCODE_CHUNKED;
-
- /*
- * Flush the data and return...
- */
- return (httpFlushWrite(&(client->http)) >= 0);
+ return (1);
}
const char *message, /* I - printf-style status-message */
...) /* I - Additional args as needed */
{
- va_list ap; /* Pointer to additional args */
- char formatted[1024]; /* Formatted errror message */
-
+ const char *formatted = NULL; /* Formatted message */
- client->response->request.status.status_code = status;
- if (!client->response->attrs)
- {
- ippAddString(client->response, IPP_TAG_OPERATION,
- IPP_TAG_CHARSET | IPP_TAG_COPY, "attributes-charset", NULL,
- "utf-8");
- ippAddString(client->response, IPP_TAG_OPERATION,
- IPP_TAG_LANGUAGE | IPP_TAG_COPY, "attributes-natural-language",
- NULL, "en-us");
- }
+ ippSetStatusCode(client->response, status);
if (message)
{
+ va_list ap; /* Pointer to additional args */
+ ipp_attribute_t *attr; /* New status-message attribute */
+
va_start(ap, message);
- vsnprintf(formatted, sizeof(formatted), message, ap);
+ if ((attr = ippFindAttribute(client->response, "status-message",
+ IPP_TAG_TEXT)) != NULL)
+ ippSetStringfv(client->response, &attr, 0, message, ap);
+ else
+ attr = ippAddStringfv(client->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
+ "status-message", NULL, message, ap);
va_end(ap);
- ippAddString(client->response, IPP_TAG_OPERATION, IPP_TAG_TEXT,
- "status-message", NULL, formatted);
+ formatted = ippGetString(attr, 0, NULL);
}
+
+ if (formatted)
+ fprintf(stderr, "%s %s %s (%s)\n", client->hostname,
+ ippOpString(client->operation_id), ippErrorString(status),
+ formatted);
else
- formatted[0] = '\0';
+ fprintf(stderr, "%s %s %s\n", client->hostname,
+ ippOpString(client->operation_id), ippErrorString(status));
+}
+
+
+/*
+ * 'respond_unsupported()' - Respond with an unsupported attribute.
+ */
- fprintf(stderr, "%s %s %s (%s)\n", client->http.hostname,
- ippOpString(client->operation_id), ippErrorString(status), formatted);
+static void
+respond_unsupported(
+ _ipp_client_t *client, /* I - Client */
+ ipp_attribute_t *attr) /* I - Atribute */
+{
+ ipp_attribute_t *temp; /* Copy of attribute */
+
+
+ respond_ipp(client, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES,
+ "Unsupported %s %s%s value.", ippGetName(attr),
+ ippGetCount(attr) > 1 ? "1setOf " : "",
+ ippTagString(ippGetValueTag(attr)));
+
+ temp = ippCopyAttribute(client->response, attr, 0);
+ ippSetGroupTag(client->response, &temp, IPP_TAG_UNSUPPORTED_GROUP);
}
else
timeout = -1;
- if (poll(polldata, num_fds, timeout) < 0 && errno != EINTR)
+ if (poll(polldata, (nfds_t)num_fds, timeout) < 0 && errno != EINTR)
{
perror("poll() failed");
break;
{
if (!status)
{
- puts(CUPS_SVERSION " - Copyright 2010 by Apple Inc. All rights reserved.");
+ puts(CUPS_SVERSION " - Copyright 2010-2013 by Apple Inc. All rights "
+ "reserved.");
puts("");
}
puts("Options:");
puts("-2 Supports 2-sided printing (default=1-sided)");
puts("-M manufacturer Manufacturer name (default=Test)");
+ puts("-P PIN printing mode");
+ puts("-c command Run command for every print job");
printf("-d spool-directory Spool directory "
"(default=/tmp/ippserver.%d)\n", (int)getpid());
puts("-f type/subtype[,...] List of supported types "
"(default=application/pdf,image/jpeg)");
puts("-h Show program help");
puts("-i iconfile.png PNG icon file (default=printer.png)");
+ puts("-k Keep job spool files");
puts("-l location Location of printer (default=empty string)");
puts("-m model Model name (default=Printer)");
puts("-n hostname Hostname for printer");
puts("-p port Port number (default=auto)");
- puts("-r regtype Bonjour service type (default=_ipp._tcp)");
+#ifdef HAVE_DNSSD
+ puts("-r subtype Bonjour service subtype (default=_print)");
+#endif /* HAVE_DNSSD */
puts("-s speed[,color-speed] Speed in pages per minute (default=10,0)");
puts("-v[vvv] Be (very) verbose");
/*
- * '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? */
+ ipp_op_t op = ippGetOperation(client->request);
+ /* IPP operation */
+ const char *op_name = ippOpString(op);
+ /* IPP operation name */
+ ipp_attribute_t *attr, /* Current attribute */
+ *supported; /* xxx-supported attribute */
+ const char *compression = NULL,
+ /* compression value */
+ *format = NULL; /* document-format value */
/*
* 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)
{
/*
- * If compression is specified, only accept "none"...
+ * If compression is specified, only accept a supported value in a Print-Job
+ * or Send-Document request...
*/
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_KEYWORD ||
- strcmp(attr->values[0].string.text, "none"))
+ compression = ippGetString(attr, 0, NULL);
+ supported = ippFindAttribute(client->printer->attrs,
+ "compression-supported", IPP_TAG_KEYWORD);
+
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD ||
+ ippGetGroupTag(attr) != IPP_TAG_OPERATION ||
+ (op != IPP_OP_PRINT_JOB && op != IPP_OP_SEND_DOCUMENT &&
+ op != IPP_OP_VALIDATE_JOB) ||
+ !ippContainsString(supported, compression))
{
respond_unsupported(client, attr);
+ valid = 0;
}
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->hostname, op_name, compression);
+
+ if (strcmp(compression, "none"))
+ httpSetField(client->http, HTTP_FIELD_CONTENT_ENCODING, compression);
+ }
}
/*
if ((attr = ippFindAttribute(client->request, "document-format",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_MIMETYPE)
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_MIMETYPE ||
+ ippGetGroupTag(attr) != IPP_TAG_OPERATION)
{
respond_unsupported(client, attr);
+ valid = 0;
}
else
{
- format = attr->values[0].string.text;
+ format = ippGetString(attr, 0, NULL);
fprintf(stderr, "%s %s document-format=\"%s\"\n",
- client->http.hostname,
- ippOpString(client->request->request.op.operation_id), format);
+ client->hostname, op_name, format);
}
}
else
- format = "application/octet-stream";
+ {
+ format = ippGetString(ippFindAttribute(client->printer->attrs,
+ "document-format-default",
+ IPP_TAG_MIMETYPE), 0, NULL);
+ if (!format)
+ format = "application/octet-stream"; /* Should never happen */
+
+ attr = ippAddString(client->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE,
+ "document-format", NULL, format);
+ }
if (!strcmp(format, "application/octet-stream") &&
- client->request->request.op.operation_id != IPP_VALIDATE_JOB)
+ (ippGetOperation(client->request) == IPP_OP_PRINT_JOB ||
+ ippGetOperation(client->request) == IPP_OP_SEND_DOCUMENT))
{
/*
* Auto-type the file using the first 4 bytes of the file...
unsigned char header[4]; /* First 4 bytes of file */
memset(header, 0, sizeof(header));
- _httpPeek(&(client->http), (char *)header, sizeof(header));
+ httpPeek(client->http, (char *)header, sizeof(header));
if (!memcmp(header, "%PDF", 4))
format = "application/pdf";
if (format)
fprintf(stderr, "%s %s Auto-typed document-format=\"%s\"\n",
- client->http.hostname,
- ippOpString(client->request->request.op.operation_id), format);
+ client->hostname, op_name, 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);
- attr->values[0].string.text = _cupsStrAlloc(format);
- }
+ ippSetString(client->request, &attr, 0, format);
}
- if ((supported = ippFindAttribute(client->printer->attrs,
+ if (op != IPP_OP_CREATE_JOB &&
+ (supported = ippFindAttribute(client->printer->attrs,
"document-format-supported",
- IPP_TAG_MIMETYPE)) != NULL)
+ IPP_TAG_MIMETYPE)) != NULL &&
+ !ippContainsString(supported, format))
{
- for (i = 0; i < supported->num_values; i ++)
- if (!_cups_strcasecmp(format, supported->values[i].string.text))
- break;
-
- if (i >= supported->num_values)
- {
- respond_unsupported(client, attr);
- }
+ respond_unsupported(client, attr);
+ valid = 0;
}
+ return (valid);
+}
+
+
+/*
+ * '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 */
+ valid = 1; /* Valid attributes? */
+ ipp_attribute_t *attr, /* Current attribute */
+ *supported; /* xxx-supported attribute */
+
+
+ /*
+ * Check operation attributes...
+ */
+
+ valid = valid_doc_attributes(client);
+
/*
* Check the various job template attributes...
*/
if ((attr = ippFindAttribute(client->request, "copies",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_INTEGER ||
- attr->values[0].integer < 1 || attr->values[0].integer > 999)
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER ||
+ ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 999)
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
if ((attr = ippFindAttribute(client->request, "ipp-attribute-fidelity",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_BOOLEAN)
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_BOOLEAN)
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
if ((attr = ippFindAttribute(client->request, "job-hold-until",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 ||
- (attr->value_tag != IPP_TAG_NAME &&
- attr->value_tag != IPP_TAG_NAMELANG &&
- attr->value_tag != IPP_TAG_KEYWORD) ||
- strcmp(attr->values[0].string.text, "no-hold"))
+ if (ippGetCount(attr) != 1 ||
+ (ippGetValueTag(attr) != IPP_TAG_NAME &&
+ ippGetValueTag(attr) != IPP_TAG_NAMELANG &&
+ ippGetValueTag(attr) != IPP_TAG_KEYWORD) ||
+ strcmp(ippGetString(attr, 0, NULL), "no-hold"))
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
if ((attr = ippFindAttribute(client->request, "job-name",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 ||
- (attr->value_tag != IPP_TAG_NAME &&
- attr->value_tag != IPP_TAG_NAMELANG))
+ if (ippGetCount(attr) != 1 ||
+ (ippGetValueTag(attr) != IPP_TAG_NAME &&
+ ippGetValueTag(attr) != IPP_TAG_NAMELANG))
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
if ((attr = ippFindAttribute(client->request, "job-priority",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_INTEGER ||
- attr->values[0].integer < 1 || attr->values[0].integer > 100)
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_INTEGER ||
+ ippGetInteger(attr, 0) < 1 || ippGetInteger(attr, 0) > 100)
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
if ((attr = ippFindAttribute(client->request, "job-sheets",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 ||
- (attr->value_tag != IPP_TAG_NAME &&
- attr->value_tag != IPP_TAG_NAMELANG &&
- attr->value_tag != IPP_TAG_KEYWORD) ||
- strcmp(attr->values[0].string.text, "none"))
+ if (ippGetCount(attr) != 1 ||
+ (ippGetValueTag(attr) != IPP_TAG_NAME &&
+ ippGetValueTag(attr) != IPP_TAG_NAMELANG &&
+ ippGetValueTag(attr) != IPP_TAG_KEYWORD) ||
+ strcmp(ippGetString(attr, 0, NULL), "none"))
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
if ((attr = ippFindAttribute(client->request, "media",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 ||
- (attr->value_tag != IPP_TAG_NAME &&
- attr->value_tag != IPP_TAG_NAMELANG &&
- attr->value_tag != IPP_TAG_KEYWORD))
+ if (ippGetCount(attr) != 1 ||
+ (ippGetValueTag(attr) != IPP_TAG_NAME &&
+ ippGetValueTag(attr) != IPP_TAG_NAMELANG &&
+ ippGetValueTag(attr) != IPP_TAG_KEYWORD))
{
respond_unsupported(client, attr);
+ valid = 0;
}
else
{
for (i = 0;
i < (int)(sizeof(media_supported) / sizeof(media_supported[0]));
i ++)
- if (!strcmp(attr->values[0].string.text, media_supported[i]))
+ if (!strcmp(ippGetString(attr, 0, NULL), media_supported[i]))
break;
if (i >= (int)(sizeof(media_supported) / sizeof(media_supported[0])))
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
}
if ((attr = ippFindAttribute(client->request, "media-col",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_BEGIN_COLLECTION)
+ if (ippGetCount(attr) != 1 ||
+ ippGetValueTag(attr) != IPP_TAG_BEGIN_COLLECTION)
{
respond_unsupported(client, attr);
+ valid = 0;
}
/* TODO: check for valid media-col */
}
if ((attr = ippFindAttribute(client->request, "multiple-document-handling",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_KEYWORD ||
- (strcmp(attr->values[0].string.text,
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD ||
+ (strcmp(ippGetString(attr, 0, NULL),
"separate-documents-uncollated-copies") &&
- strcmp(attr->values[0].string.text,
+ strcmp(ippGetString(attr, 0, NULL),
"separate-documents-collated-copies")))
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
if ((attr = ippFindAttribute(client->request, "orientation-requested",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_ENUM ||
- attr->values[0].integer < IPP_PORTRAIT ||
- attr->values[0].integer > IPP_REVERSE_PORTRAIT)
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM ||
+ ippGetInteger(attr, 0) < IPP_ORIENT_PORTRAIT ||
+ ippGetInteger(attr, 0) > IPP_ORIENT_REVERSE_PORTRAIT)
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
IPP_TAG_ZERO)) != NULL)
{
respond_unsupported(client, attr);
+ valid = 0;
}
if ((attr = ippFindAttribute(client->request, "print-quality",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_ENUM ||
- attr->values[0].integer < IPP_QUALITY_DRAFT ||
- attr->values[0].integer > IPP_QUALITY_HIGH)
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_ENUM ||
+ ippGetInteger(attr, 0) < IPP_QUALITY_DRAFT ||
+ ippGetInteger(attr, 0) > IPP_QUALITY_HIGH)
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
IPP_TAG_ZERO)) != NULL)
{
respond_unsupported(client, attr);
+ valid = 0;
}
if ((attr = ippFindAttribute(client->request, "sides",
IPP_TAG_ZERO)) != NULL)
{
- if (attr->num_values != 1 || attr->value_tag != IPP_TAG_KEYWORD)
+ const char *sides = NULL; /* "sides" value... */
+
+ if (ippGetCount(attr) != 1 || ippGetValueTag(attr) != IPP_TAG_KEYWORD)
{
respond_unsupported(client, attr);
+ valid = 0;
}
- if ((supported = ippFindAttribute(client->printer->attrs, "sides",
+ sides = ippGetString(attr, 0, NULL);
+
+ if ((supported = ippFindAttribute(client->printer->attrs, "sides-supported",
IPP_TAG_KEYWORD)) != NULL)
{
- for (i = 0; i < supported->num_values; i ++)
- if (!strcmp(attr->values[0].string.text,
- supported->values[i].string.text))
- break;
-
- if (i >= supported->num_values)
+ if (!ippContainsString(supported, sides))
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
- else
+ else if (strcmp(sides, "one-sided"))
{
respond_unsupported(client, attr);
+ valid = 0;
}
}
/*
- * End of "$Id$".
+ * End of "$Id: ippserver.c 11986 2014-07-02 15:52:01Z msweet $".
*/