typedef struct ippeve_printer_s // Printer data
{
- // TODO: One IPv4 and one IPv6 listener are really not sufficient
+ // Note: A "real" IPP implementation will support more than one IPv4 and one IPv6 listener
int ipv4, // IPv4 listener
ipv6; // IPv6 listener
cups_dnssd_t *dnssd; // DNS-SD context
int impressions, // job-impressions value
impcompleted; // job-impressions-completed value
ipp_t *attrs; // Static attributes
+ char password[256]; // Document password, if any
int cancel; // Non-zero when job canceled
char *filename; // Print file name
int fd; // Print file descriptor
static bool html_header(ippeve_client_t *client, const char *title, int refresh);
static bool html_printf(ippeve_client_t *client, const char *format, ...) _CUPS_FORMAT(2, 3);
static void ipp_cancel_job(ippeve_client_t *client);
-static void ipp_cancel_my_jobs(ippeve_client_t *client);
+static void ipp_cancel_jobs(ippeve_client_t *client);
static void ipp_close_job(ippeve_client_t *client);
static void ipp_create_job(ippeve_client_t *client);
static void ipp_get_job_attributes(ippeve_client_t *client);
static void ipp_send_document(ippeve_client_t *client);
static void ipp_send_uri(ippeve_client_t *client);
static void ipp_validate_job(ippeve_client_t *client);
-static ipp_t *load_ippserver_attributes(const char *servername, int serverport, const char *filename, cups_array_t *docformats);
+static ipp_t *load_ippfile_attributes(const char *servername, int serverport, const char *filename, cups_array_t *docformats);
static ipp_t *load_legacy_attributes(const char *make, const char *model, int ppm, int ppm_color, int duplex, cups_array_t *docformats);
#if HAVE_LIBPAM
static int pam_func(int, const struct pam_message **, struct pam_response **, void *);
// Create the printer...
if (attrfile)
- attrs = load_ippserver_attributes(servername, serverport, attrfile, docformats);
+ attrs = load_ippfile_attributes(servername, serverport, attrfile, docformats);
else
attrs = load_legacy_attributes(make, model, ppm, ppm_color, duplex, docformats);
// 'compare_jobs()' - Compare two jobs.
//
-static int // O - Result of comparison
-compare_jobs(ippeve_job_t *a, // I - First job
- ippeve_job_t *b, // I - Second job
- void *data) // I - Unused
+static int // O - Result of comparison
+compare_jobs(ippeve_job_t *a, // I - First job
+ ippeve_job_t *b, // I - Second job
+ void *data) // I - Callback data (unused)
{
(void)data;
+
return (b->id - a->id);
}
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username);
+ if ((attr = ippFindAttribute(client->request, "requesting-user-uri", IPP_TAG_ZERO)) != NULL)
+ {
+ const char *user_uri = ippGetString(attr, 0, /*language*/NULL);
+ // String value
+
+ if (ippGetGroupTag(attr) == IPP_TAG_OPERATION && ippGetValueTag(attr) == IPP_TAG_URI && ippGetCount(attr) == 1 && user_uri && !strncmp(user_uri, "mailto:", 7))
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-originating-user-uri", NULL, user_uri);
+ else
+ respond_ignored(client, attr);
+ }
+
+ if ((attr = ippFindAttribute(client->request, "document-metadata", IPP_TAG_ZERO)) != NULL)
+ {
+ if (ippGetGroupTag(attr) == IPP_TAG_OPERATION && ippGetValueTag(attr) == IPP_TAG_STRING)
+ {
+ if ((attr = ippCopyAttribute(job->attrs, attr, /*quickcopy*/false)) != NULL)
+ ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB);
+ }
+ else
+ {
+ respond_ignored(client, attr);
+ }
+ }
+
+ if ((attr = ippFindAttribute(client->request, "document-password", IPP_TAG_ZERO)) != NULL)
+ {
+ if (ippGetGroupTag(attr) == IPP_TAG_OPERATION && ippGetValueTag(attr) == IPP_TAG_STRING && ippGetCount(attr) == 1)
+ {
+ void *dataptr; // octetString pointer
+ int datalen; // Length of octetString
+
+ if ((dataptr = ippGetOctetString(attr, 0, &datalen)) != NULL && datalen < (sizeof(job->password) - 1))
+ memcpy(job->password, dataptr, datalen);
+ else
+ respond_ignored(client, attr);
+ }
+ else
+ {
+ respond_ignored(client, attr);
+ }
+ }
+
if (ippGetOperation(client->request) != IPP_OP_CREATE_JOB)
{
if ((attr = ippFindAttribute(job->attrs, "document-format-detected", IPP_TAG_MIMETYPE)) != NULL)
{
ippeve_printer_t *printer; // Printer
int i; // Looping var
+ ipp_attribute_t *attr; // Current attribute
#ifndef _WIN32
char path[1024]; // Full path to command
#endif // !_WIN32
size_t num_formats = 0;// Number of supported document formats
const char *formats[100], // Supported document formats
*format; // Current format
+ bool has_jpeg = false,
+ // Supports JPEG?
+ has_pdf = false;// Supports PDF?
size_t num_sup_attrs; // Number of supported attributes
const char *sup_attrs[100];// Supported attributes
char xxx_supported[256];
IPP_OP_GET_JOB_ATTRIBUTES,
IPP_OP_GET_JOBS,
IPP_OP_GET_PRINTER_ATTRIBUTES,
+ IPP_OP_CANCEL_JOBS,
IPP_OP_CANCEL_MY_JOBS,
IPP_OP_CLOSE_JOB,
IPP_OP_IDENTIFY_PRINTER
"y-side1-image-shift",
"y-side2-image-shift"
};
+ static const char * const job_history[] =
+ { // job-history-attributes-configured/supported
+ "date-time-at-creation",
+ "date-time-at-processing",
+ "date-time-at-completed",
+ "job-id",
+ "job-name",
+ "job-originating-user-name",
+ "job-originating-user-uri",
+ "job-printer-uri",
+ "job-state",
+ "job-state-reasons",
+ "job-uri",
+ "time-at-creation",
+ "time-at-processing",
+ "time-at-completed"
+ };
static const char * const media_col_supported[] =
{ // media-col-supported values
"media-bottom-margin",
for (format = (const char *)cupsArrayGetFirst(docformats); format && num_formats < (sizeof(formats) / sizeof(formats[0])); format = (const char *)cupsArrayGetNext(docformats))
formats[num_formats ++] = format;
}
+ else if ((attr = ippFindAttribute(attrs, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL)
+ {
+ int count = ippGetCount(attr); // Number of formats
+
+ for (i = 0; i < count && i < (int)(sizeof(formats) / sizeof(formats[0])); i ++)
+ formats[i] = ippGetString(attr, i, /*language*/NULL);
+
+ num_formats = i;
+ }
+
+ for (i = 0; i < num_formats; i ++)
+ {
+ if (!strcasecmp(formats[i], "image/jpeg"))
+ has_jpeg = true;
+ else if (!strcasecmp(formats[i], "application/pdf"))
+ has_pdf = true;
+ }
// Get the list of attributes that can be used when creating a job...
num_sup_attrs = 0;
sup_attrs[num_sup_attrs ++] = "document-metadata";
sup_attrs[num_sup_attrs ++] = "document-name";
sup_attrs[num_sup_attrs ++] = "document-natural-language";
+ if (has_pdf)
+ sup_attrs[num_sup_attrs ++] = "document-password";
sup_attrs[num_sup_attrs ++] = "ipp-attribute-fidelity";
sup_attrs[num_sup_attrs ++] = "job-name";
sup_attrs[num_sup_attrs ++] = "job-priority";
if (!ippFindAttribute(printer->attrs, "compression-supported", IPP_TAG_ZERO))
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "compression-supported", (int)(sizeof(compressions) / sizeof(compressions[0])), NULL, compressions);
+ // device-uuid
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uuid", /*language*/NULL, uuid);
+
if (docformats)
{
- ipp_attribute_t *attr; // Attribute
-
// document-format-default
if (!ippFindAttribute(printer->attrs, "document-format-default", IPP_TAG_MIMETYPE))
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_MIMETYPE), "document-format-default", NULL, "application/octet-stream");
// job-creation-attributes-supported
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-creation-attributes-supported", num_sup_attrs, NULL, sup_attrs);
+ // job-history-attributes-configured
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-history-attributes-configured", sizeof(job_history) / sizeof(job_history[0]), /*language*/NULL, job_history);
+
+ // job-history-attributes-supported
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-history-attributes-supported", sizeof(job_history) / sizeof(job_history[0]), /*language*/NULL, job_history);
+
+ // job-history-interval-configured
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-history-interval-configured", 60);
+
+ // job-history-interval-supported
+ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "job-history-interval-supported", 0, 3600);
+
// job-ids-supported
ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-ids-supported", 1);
// job-k-octets-supported
ippAddRange(printer->attrs, IPP_TAG_PRINTER, "job-k-octets-supported", 0, k_supported);
+ // job-mandatory-attributes-supported
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "job-mandatory-attributes-supported", true);
+
// job-priority-default
ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-default", 50);
ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "job-priority-supported", 1);
// job-sheets-default
- ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-default", NULL, "none");
+// 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_CONST_TAG(IPP_TAG_NAME), "job-sheets-supported", NULL, "none");
+// ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "job-sheets-supported", NULL, "none");
+
+ // job-spooling-supported
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "job-spooling-supported", /*language*/NULL, "stream");
+
+ if (has_jpeg)
+ {
+ // jpeg-features-supported
+ if (!ippFindAttribute(printer->attrs, "jpeg-features-supported", IPP_TAG_ZERO))
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "jpeg-features-supported", /*language*/NULL, "none");
+
+ // jpeg-k-octets-supported
+ if (!ippFindAttribute(printer->attrs, "jpeg-k-octets-supported", IPP_TAG_ZERO))
+ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "jpeg-k-octets-supported", 0, k_supported);
+
+ // jpeg-x-dimension-supported
+ if (!ippFindAttribute(printer->attrs, "jpeg-x-dimension-supported", IPP_TAG_ZERO))
+ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "jpeg-x-dimension-supported", 0, 16384);
+
+ // jpeg-y-dimension-supported
+ if (!ippFindAttribute(printer->attrs, "jpeg-y-dimension-supported", IPP_TAG_ZERO))
+ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "jpeg-y-dimension-supported", 1, 16384);
+ }
// media-col-supported
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);
+ // multiple-document-handling-default
+ if (!ippFindAttribute(printer->attrs, "multiple-document-handling-default", IPP_TAG_ZERO))
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-document-handling-default", NULL, "separate-documents-collated-copies");
+
// multiple-document-handling-supported
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_handling);
// operations-supported
ippAddIntegers(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "operations-supported", sizeof(ops) / sizeof(ops[0]), ops);
+ if (has_pdf)
+ {
+ // document-password-supported
+ if (!ippFindAttribute(printer->attrs, "document-password-supported", IPP_TAG_ZERO))
+ ippAddInteger(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 255);
+
+ // pdf-k-octets-supported
+ if (!ippFindAttribute(printer->attrs, "pdf-k-octets-supported", IPP_TAG_ZERO))
+ ippAddRange(printer->attrs, IPP_TAG_PRINTER, "pdf-k-octets-supported", 0, k_supported);
+
+ // pdf-versions-supported
+ if (!ippFindAttribute(printer->attrs, "pdf-versions-supported", IPP_TAG_ZERO))
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pdf-versions-supported", /*language*/NULL, "iso-32000-2_2017");
+ }
+
// pdl-override-supported
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pdl-override-supported", NULL, "attempted");
// preferred-attributes-supported
ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "preferred-attributes-supported", 0);
+ // print-processing-attributes-supported
+ if (!ippFindAttribute(printer->attrs, "print-processing-attributes-supported", IPP_TAG_ZERO))
+ {
+ num_sup_attrs = 0;
+ if (ippFindAttribute(printer->attrs, "media-overprint-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "media-overprint";
+ if (ippFindAttribute(printer->attrs, "print-color-mode-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "print-color-mode";
+ if (ippFindAttribute(printer->attrs, "print-content-optimize-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "print-content-optimize";
+ if (ippFindAttribute(printer->attrs, "print-darkness-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "print-darkness";
+ if (ippFindAttribute(printer->attrs, "print-rendering-intent-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "print-rendering-intent";
+ if (ippFindAttribute(printer->attrs, "print-quality-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "print-quality";
+ if (ippFindAttribute(printer->attrs, "print-speed-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "print-speed";
+ if (ippFindAttribute(printer->attrs, "printer-resolution-supported", IPP_TAG_ZERO))
+ sup_attrs[num_sup_attrs ++] = "printer-resolution";
+
+ if (num_sup_attrs > 0)
+ ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-processing-attributes-supported", num_sup_attrs, /*language*/NULL, sup_attrs);
+ }
+
+ // print-scaling-default
+ if (!ippFindAttribute(printer->attrs, "print-scaling-default", IPP_TAG_ZERO))
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-scaling-default", /*language*/NULL, "none");
+
+ // print-scaling-supported
+ if (!ippFindAttribute(printer->attrs, "print-scaling-supported", IPP_TAG_ZERO))
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-scaling-supported", /*language*/NULL, "none");
+
// printer-get-attributes-supported
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-get-attributes-supported", NULL, "document-format");
// printer-info
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, name);
+ // printer-kind
+ if (!ippFindAttribute(printer->attrs, "printer-kind", IPP_TAG_ZERO))
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-kind", /*language*/NULL, "document");
+
// printer-location
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location", NULL, location);
// printer-uuid
ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, uuid);
- // reference-uri-scheme-supported
+ // reference-uri-schemes-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);
+ // requesting-user-uri-supported
+ ippAddBoolean(printer->attrs, IPP_TAG_PRINTER, "requesting-user-uri-supported", 1);
+
+ // requesting-user-uri-scheme-supported
+ ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_URISCHEME, "requesting-user-uri-schemes-supported", NULL, "mailto");
+
// uri-authentication-supported
if (PAMService)
ippAddStrings(printer->attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "uri-authentication-supported", 2, NULL, uri_authentication_basic);
ippDelete(job->attrs);
- if (job->message)
- free(job->message);
+ free(job->message);
if (job->filename)
{
ippeve_printer_t *printer) // I - Printer
{
if (printer->ipv4 >= 0)
- close(printer->ipv4);
+ httpAddrClose(/*addr*/NULL, printer->ipv4);
if (printer->ipv6 >= 0)
- close(printer->ipv6);
+ httpAddrClose(/*addr*/NULL, printer->ipv6);
cupsDNSSDDelete(printer->dnssd);
- if (printer->dnssd_name)
- free(printer->dnssd_name);
- if (printer->name)
- free(printer->name);
- if (printer->icons[0])
- free(printer->icons[0]);
- if (printer->strings)
- free(printer->strings);
- if (printer->command)
- free(printer->command);
- if (printer->device_uri)
- free(printer->device_uri);
- if (printer->directory)
- free(printer->directory);
- if (printer->hostname)
- free(printer->hostname);
+ free(printer->dnssd_name);
+ free(printer->name);
+ free(printer->icons[0]);
+ free(printer->strings);
+ free(printer->command);
+ free(printer->device_uri);
+ free(printer->directory);
+ free(printer->hostname);
ippDelete(printer->attrs);
cupsArrayDelete(printer->jobs);
// Create a file for the request data...
- //
- // TODO: Update code to support piping large raster data to the print command.
if ((job->fd = create_job_file(job, filename, sizeof(filename), client->printer->directory, NULL)) < 0)
{
respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to create print file: %s", strerror(errno));
if (bytes < 0)
{
+ // Got an error while reading the print data, so abort this job.
respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to read print file.");
goto cleanup_and_abort;
}
goto abort_job;
}
- 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)
+ if ((uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, ippGetString(uri, 0, NULL), scheme, sizeof(scheme), userpass, sizeof(userpass), hostname, sizeof(hostname), &port, resource, sizeof(resource))) < HTTP_URI_STATUS_OK)
{
respond_ipp(client, IPP_STATUS_ERROR_BAD_REQUEST, "Bad document-uri: %s", httpURIStatusString(uri_status));
if (strcmp(scheme, "file") && strcmp(scheme, "https") && strcmp(scheme, "http"))
{
- respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, "URI scheme \"%s\" not supported.", scheme);
+ respond_ipp(client, IPP_STATUS_ERROR_URI_SCHEME, "URI scheme '%s' not supported.", scheme);
goto abort_job;
}
{
if ((infile = open(resource, O_RDONLY | O_BINARY)) < 0)
{
- respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI: %s", strerror(errno));
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to access URI '%s': %s", ippGetString(uri, 0, NULL), strerror(errno));
goto abort_job;
}
do
{
- if ((bytes = read(infile, buffer, sizeof(buffer))) < 0 &&
- (errno == EAGAIN || errno == EINTR))
+ 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
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(errno));
close(infile);
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error));
-
- goto abort_job;
+ goto cleanup_and_abort;
}
}
while (bytes > 0);
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, cupsGetErrorString());
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
-
- goto abort_job;
+ respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to connect to '%s' on port %d: %s", hostname, port, cupsGetErrorString());
+ goto cleanup_and_abort;
}
httpClearFields(http);
if (!httpWriteRequest(http, "GET", resource))
{
respond_ipp(client, IPP_STATUS_ERROR_DOCUMENT_ACCESS, "Unable to GET URI: %s", strerror(errno));
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
httpClose(http);
- goto abort_job;
+ goto cleanup_and_abort;
}
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", httpStatusString(status));
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
httpClose(http);
- goto abort_job;
+ goto cleanup_and_abort;
}
while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0)
{
if (write(job->fd, buffer, (size_t)bytes) < bytes)
{
- int error = errno; // Write error
-
- close(job->fd);
- job->fd = -1;
-
- unlink(filename);
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(errno));
httpClose(http);
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL,
- "Unable to write print file: %s", strerror(error));
-
- goto abort_job;
+ goto cleanup_and_abort;
}
}
if (close(job->fd))
{
- int error = errno; // Write error
-
job->fd = -1;
-
- unlink(filename);
-
- respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to write print file: %s", strerror(error));
-
- goto abort_job;
+ respond_ipp(client, IPP_STATUS_ERROR_INTERNAL, "Unable to close print file: %s", strerror(errno));
+ goto cleanup_and_abort;
}
cupsRWLockWrite(&(client->printer->rwlock));
cupsArrayDelete(ra);
return;
+ // Cleanup and then abort...
+ cleanup_and_abort:
+
+ if (job->fd >= 0)
+ {
+ close(job->fd);
+ job->fd = -1;
+ }
+
+ unlink(filename);
+
// If we get here we had to abort the job...
abort_job:
//
-// 'ipp_cancel_my_jobs()' - Cancel all jobs.
+// 'ipp_cancel_jobs()' - Cancel all jobs.
//
// Note: Since ippeveprinter doesn't do spooling, this really just cancels the
// current job.
//
static void
-ipp_cancel_my_jobs(
+ipp_cancel_jobs(
ippeve_client_t *client) // I - Client
{
ippeve_job_t *job; // Job information
// which-jobs values
int job_comparison; // Job comparison
ipp_jstate_t job_state; // job-state value
- int first_job_id, // First job ID
+ int first_index, // First job index
limit, // Maximum number of jobs to return
- count; // Number of jobs that match
+ matches; // Number of jobs that match
+ int i, // Current job index
+ first_i, // First job index (0-based)
+ count; // Number of jobs
const char *username; // Username
ippeve_job_t *job; // Current job pointer
cups_array_t *ra; // Requested attributes array
limit = 0;
}
- if ((attr = ippFindAttribute(client->request, "first-job-id", IPP_TAG_INTEGER)) != NULL)
+ if ((attr = ippFindAttribute(client->request, "first-index", IPP_TAG_INTEGER)) != NULL && (first_index = ippGetInteger(attr, 0)) >= 1)
{
- first_job_id = ippGetInteger(attr, 0);
+ first_i = (size_t)first_index - 1;
- fprintf(stderr, "%s Get-Jobs first-job-id=%d", client->hostname, first_job_id);
+ fprintf(stderr, "%s Get-Jobs first-index=%d", client->hostname, first_index);
}
else
{
- first_job_id = 1;
+ first_i = 0;
}
// See if we only want to see jobs for a specific user...
cupsRWLockRead(&(client->printer->rwlock));
- for (count = 0, job = (ippeve_job_t *)cupsArrayGetFirst(client->printer->jobs); (limit <= 0 || count < limit) && job; job = (ippeve_job_t *)cupsArrayGetNext(client->printer->jobs))
+ for (i = 0, count = cupsArrayGetCount(client->printer->jobs), matches = 0; i < count && (limit <= 0 || matches < limit); i ++)
{
// Filter out jobs that don't match...
+ job = (ippeve_job_t *)cupsArrayGetElement(client->printer->jobs, i);
+
if ((job_comparison < 0 && job->state > job_state) ||
(job_comparison == 0 && job->state != job_state) ||
(job_comparison > 0 && job->state < job_state) ||
- job->id < first_job_id ||
+ i < first_i ||
(username && job->username && strcasecmp(username, job->username)))
continue;
- if (count > 0)
+ if (matches > 0)
ippAddSeparator(client->response);
- count ++;
+ matches ++;
copy_job_attributes(client, job, ra);
}
if (!ra || cupsArrayFind(ra, "printer-current-time"))
ippAddDate(client->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(time(NULL)));
+ if (!ra || cupsArrayFind(ra, "printer-dns-sd-name"))
+ ippAddString(client->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-dns-sd-name", /*language*/NULL, printer->dnssd_name);
+
if (!ra || cupsArrayFind(ra, "printer-icons"))
{
char uris[3][1024]; // Buffers for URIs
//
-// 'ippserver_attr_cb()' - Determine whether an attribute should be loaded.
+// 'ippfile_attr_cb()' - Determine whether an attribute should be loaded.
//
static bool // O - `true` to use, `false` to ignore
-ippserver_attr_cb(
+ippfile_attr_cb(
ipp_file_t *f, // I - IPP file
void *user_data, // I - User data pointer (unused)
const char *attr) // I - Attribute name
{
- int i, // Current element
- result; // Result of comparison
+ size_t i; // Current element
static const char * const ignored[] =
{ // Ignored attributes
"attributes-charset",
"notify-pull-method-supported",
"operations-supported",
"pdl-override-supported",
+ "preferred-attributes-supported",
"printer-alert",
"printer-alert-description",
"printer-camera-image-uri",
"printer-uuid",
"printer-xri-supported",
"queued-job-count",
- "reference-uri-scheme-supported",
+ "reference-uri-schemes-supported",
+ "requesting-user-uri-supported",
"uri-authentication-supported",
"uri-security-supported",
"which-jobs-supported",
(void)f;
(void)user_data;
- for (i = 0, result = 1; i < (int)(sizeof(ignored) / sizeof(ignored[0])); i ++)
+ for (i = 0; i < (sizeof(ignored) / sizeof(ignored[0])); i ++)
{
- if ((result = strcmp(attr, ignored[i])) <= 0)
- break;
+ if (!strcmp(attr, ignored[i]))
+ return (false);
}
- return (result != 0);
+ return (true);
}
//
-// 'ippserver_error_cb()' - Log an error message.
+// 'ippfile_error_cb()' - Log an error message.
//
static bool // O - `true` to continue, `false` to stop
-ippserver_error_cb(
+ippfile_error_cb(
ipp_file_t *f, // I - IPP file data
void *user_data, // I - User data pointer (unused)
const char *error) // I - Error message
//
-// 'load_ippserver_attributes()' - Load IPP attributes from an ippserver file.
+// 'load_ippfile_attributes()' - Load IPP attributes from an ippserver file.
//
static ipp_t * // O - IPP attributes or `NULL` on error
-load_ippserver_attributes(
+load_ippfile_attributes(
const char *servername, // I - Server name or `NULL` for default
int serverport, // I - Server port number
const char *filename, // I - ippserver attribute filename
// - SERVERNAME: The host name of the server.
// - SERVERPORT: The default port of the server.
attrs = ippNew();
- file = ippFileNew(NULL, (ipp_fattr_cb_t)ippserver_attr_cb, (ipp_ferror_cb_t)ippserver_error_cb, NULL);
+ file = ippFileNew(NULL, (ipp_fattr_cb_t)ippfile_attr_cb, (ipp_ferror_cb_t)ippfile_error_cb, NULL);
ippFileSetAttributes(file, attrs);
ippFileSetGroupTag(file, IPP_TAG_PRINTER);
ipp_cancel_job(client);
break;
+ case IPP_OP_CANCEL_JOBS :
case IPP_OP_CANCEL_MY_JOBS :
- ipp_cancel_my_jobs(client);
+ ipp_cancel_jobs(client);
break;
case IPP_OP_GET_JOB_ATTRIBUTES :
myenvp[myenvc ++] = strdup(val);
}
+ if (job->password[0])
+ {
+ snprintf(val, sizeof(val), "IPP_DOCUMENT_PASSWORD=%s", job->password);
+ myenvp[myenvc ++] = strdup(val);
+ }
+
for (attr = ippGetFirstAttribute(job->printer->attrs); attr && myenvc < (int)(sizeof(myenvp) / sizeof(myenvp[0]) - 1); attr = ippGetNextAttribute(job->printer->attrs))
{
- // Convert "attribute-name-default" to "IPP_ATTRIBUTE_NAME_DEFAULT=" and
- // "pwg-xxx" to "IPP_PWG_XXX", then add the value(s) from the attribute.
+ // Convert "attribute-name-default" to "IPP_ATTRIBUTE_NAME_DEFAULT=",
+ // "pclm-xxx" to "IPP_PCLM_XXX", and "pwg-xxx" to "IPP_PWG_XXX", then add
+ // the value(s) from the attribute.
const char *name = ippGetName(attr),
// Attribute name
*suffix = strstr(name, "-default");
// Suffix on attribute name
- if (strncmp(name, "pwg-", 4) && (!suffix || suffix[8]))
+ if (strncmp(name, "pclm-", 5) && strncmp(name, "pwg-", 4) && strcmp(name, "urf-supported") && (!suffix || suffix[8]))
continue;
valptr = val;
if (httpSeparateURI(HTTP_URI_CODING_ALL, job->printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
{
- fprintf(stderr, "[Job %d] Bad device URI \"%s\".\n", job->id, job->printer->device_uri);
+ fprintf(stderr, "[Job %d] Bad device URI '%s'.\n", job->id, job->printer->device_uri);
}
else if (!strcmp(scheme, "file"))
{
if (errno == ENOENT)
{
if ((mystdout = open(resource, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, resource);
+ fprintf(stderr, "[Job %d] Saving print command output to '%s'.\n", job->id, resource);
else
- fprintf(stderr, "[Job %d] Unable to create \"%s\": %s\n", job->id, resource, strerror(errno));
+ fprintf(stderr, "[Job %d] Unable to create '%s': %s\n", job->id, resource, strerror(errno));
}
else
- fprintf(stderr, "[Job %d] Unable to access \"%s\": %s\n", job->id, resource, strerror(errno));
+ {
+ fprintf(stderr, "[Job %d] Unable to access '%s': %s\n", job->id, resource, strerror(errno));
+ }
}
else if (S_ISDIR(fileinfo.st_mode))
{
if ((mystdout = create_job_file(job, line, sizeof(line), resource, "prn")) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, line);
+ fprintf(stderr, "[Job %d] Saving print command output to '%s'.\n", job->id, line);
else
- fprintf(stderr, "[Job %d] Unable to create \"%s\": %s\n", job->id, line, strerror(errno));
+ fprintf(stderr, "[Job %d] Unable to create '%s': %s\n", job->id, line, strerror(errno));
}
else if (!S_ISREG(fileinfo.st_mode))
{
if ((mystdout = open(resource, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666)) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, resource);
+ fprintf(stderr, "[Job %d] Saving print command output to '%s'.\n", job->id, resource);
else
- fprintf(stderr, "[Job %d] Unable to create \"%s\": %s\n", job->id, resource, strerror(errno));
+ fprintf(stderr, "[Job %d] Unable to create '%s': %s\n", job->id, resource, strerror(errno));
}
else if ((mystdout = open(resource, O_WRONLY | O_BINARY)) >= 0)
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, resource);
+ {
+ fprintf(stderr, "[Job %d] Saving print command output to '%s'.\n", job->id, resource);
+ }
else
- fprintf(stderr, "[Job %d] Unable to open \"%s\": %s\n", job->id, resource, strerror(errno));
+ {
+ fprintf(stderr, "[Job %d] Unable to open '%s': %s\n", job->id, resource, strerror(errno));
+ }
}
else if (!strcmp(scheme, "socket"))
{
snprintf(service, sizeof(service), "%d", port);
if ((addrlist = httpAddrGetList(host, AF_UNSPEC, service)) == NULL)
- fprintf(stderr, "[Job %d] Unable to find \"%s\": %s\n", job->id, host, cupsGetErrorString());
+ fprintf(stderr, "[Job %d] Unable to find '%s': %s\n", job->id, host, cupsGetErrorString());
else if (!httpAddrConnect2(addrlist, &mystdout, 30000, &(job->cancel)))
- fprintf(stderr, "[Job %d] Unable to connect to \"%s\": %s\n", job->id, host, cupsGetErrorString());
+ fprintf(stderr, "[Job %d] Unable to connect to '%s' on port %d: %s\n", job->id, host, port, cupsGetErrorString());
httpAddrFreeList(addrlist);
}
else
{
- fprintf(stderr, "[Job %d] Unsupported device URI scheme \"%s\".\n", job->id, scheme);
+ fprintf(stderr, "[Job %d] Unsupported device URI scheme '%s'.\n", job->id, scheme);
}
}
else if ((mystdout = create_job_file(job, line, sizeof(line), job->printer->directory, "prn")) >= 0)
{
- fprintf(stderr, "[Job %d] Saving print command output to \"%s\".\n", job->id, line);
+ fprintf(stderr, "[Job %d] Saving print command output to '%s'.\n", job->id, line);
}
if (mystdout < 0)
if ((printer->services = cupsDNSSDServiceNew(printer->dnssd, if_index, printer->dnssd_name, (cups_dnssd_service_cb_t)dnssd_callback, printer)) == NULL)
goto error;
- if (!cupsDNSSDServiceAdd(printer->services, "_printer._tcp", /*domain*/NULL, /*hostname*/NULL, /*port*/0, /*num_txt*/0, /*txt*/NULL))
+ if (!cupsDNSSDServiceAdd(printer->services, "_printer._tcp", /*domain*/NULL, printer->hostname, /*port*/0, /*num_txt*/0, /*txt*/NULL))
goto error;
// Then register the _ipp._tcp (IPP) service type with the real port number to
else
cupsCopyString(regtype, "_ipp._tcp", sizeof(regtype));
- if (!cupsDNSSDServiceAdd(printer->services, regtype, /*domain*/NULL, /*hostname*/NULL, (uint16_t)printer->port, num_txt, txt))
+ if (!cupsDNSSDServiceAdd(printer->services, regtype, /*domain*/NULL, printer->hostname, (uint16_t)printer->port, num_txt, txt))
goto error;
// Then register the _ipps._tcp (IPP) service type with the real port number
else
cupsCopyString(regtype, "_ipps._tcp", sizeof(regtype));
- if (!cupsDNSSDServiceAdd(printer->services, regtype, /*domain*/NULL, /*hostname*/NULL, (uint16_t)printer->port, num_txt, txt))
+ if (!cupsDNSSDServiceAdd(printer->services, regtype, /*domain*/NULL, printer->hostname, (uint16_t)printer->port, num_txt, txt))
goto error;
// Similarly, register the _http._tcp,_printer (HTTP) service type with the
// real port number to advertise our IPP printer's web interface...
- if (!cupsDNSSDServiceAdd(printer->services, "_http._tcp,_printer", /*domain*/NULL, /*hostname*/NULL, (uint16_t)printer->port, num_txt, txt))
+ if (!cupsDNSSDServiceAdd(printer->services, "_http._tcp,_printer", /*domain*/NULL, printer->hostname, (uint16_t)printer->port, num_txt, txt))
goto error;
cupsFreeOptions(num_txt, txt);