From: Michael R Sweet Date: Tue, 16 Dec 2025 17:51:50 +0000 (-0500) Subject: Synchronize changes with CUPS 3.0. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32ea3fd0e80aaa0fbbb1e6e5e59c4d19332ace30;p=thirdparty%2Fcups.git Synchronize changes with CUPS 3.0. --- diff --git a/tools/ippeveprinter.c b/tools/ippeveprinter.c index edb18378af..22500d9378 100644 --- a/tools/ippeveprinter.c +++ b/tools/ippeveprinter.c @@ -151,7 +151,7 @@ typedef struct ippeve_job_s ippeve_job_t; 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 @@ -197,6 +197,7 @@ struct ippeve_job_s // Job data 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 @@ -258,7 +259,7 @@ static bool html_footer(ippeve_client_t *client); 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); @@ -270,7 +271,7 @@ static void ipp_print_uri(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 *); @@ -603,7 +604,7 @@ main(int argc, // I - Number of command-line args // 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); @@ -754,12 +755,13 @@ clean_jobs(ippeve_printer_t *printer) // I - Printer // '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); } @@ -1034,6 +1036,48 @@ create_job(ippeve_client_t *client) // I - Client 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) @@ -1297,6 +1341,7 @@ create_printer( { 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 @@ -1308,6 +1353,9 @@ create_printer( 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]; @@ -1340,6 +1388,7 @@ create_printer( 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 @@ -1425,6 +1474,23 @@ create_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", @@ -1647,6 +1713,23 @@ create_printer( 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; @@ -1657,6 +1740,8 @@ create_printer( 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"; @@ -1681,10 +1766,11 @@ create_printer( 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"); @@ -1717,12 +1803,27 @@ create_printer( // 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); @@ -1730,14 +1831,40 @@ create_printer( 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); @@ -1756,12 +1883,60 @@ create_printer( // 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"); @@ -1774,6 +1949,10 @@ create_printer( // 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); @@ -1792,9 +1971,15 @@ create_printer( // 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); @@ -1913,8 +2098,7 @@ delete_job(ippeve_job_t *job) // I - Job ippDelete(job->attrs); - if (job->message) - free(job->message); + free(job->message); if (job->filename) { @@ -1938,29 +2122,21 @@ delete_printer( 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); @@ -2065,8 +2241,6 @@ finish_document_data( // 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)); @@ -2087,6 +2261,7 @@ finish_document_data( 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; } @@ -2209,11 +2384,7 @@ finish_document_uri( 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)); @@ -2222,7 +2393,7 @@ finish_document_uri( 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; } @@ -2251,31 +2422,23 @@ finish_document_uri( { 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); @@ -2291,14 +2454,8 @@ finish_document_uri( 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); @@ -2306,14 +2463,9 @@ finish_document_uri( 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); @@ -2321,32 +2473,19 @@ finish_document_uri( 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; } } @@ -2355,15 +2494,9 @@ finish_document_uri( 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)); @@ -2390,6 +2523,17 @@ finish_document_uri( 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: @@ -2855,14 +2999,14 @@ ipp_cancel_job(ippeve_client_t *client) // I - Client // -// '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 @@ -3026,9 +3170,12 @@ ipp_get_jobs(ippeve_client_t *client) // I - Client // 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 @@ -3107,15 +3254,15 @@ ipp_get_jobs(ippeve_client_t *client) // I - Client 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... @@ -3148,20 +3295,22 @@ ipp_get_jobs(ippeve_client_t *client) // I - Client 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); } @@ -3203,6 +3352,9 @@ ipp_get_printer_attributes( 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 @@ -3592,17 +3744,16 @@ ipp_validate_job(ippeve_client_t *client) // I - Client // -// '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", @@ -3643,6 +3794,7 @@ ippserver_attr_cb( "notify-pull-method-supported", "operations-supported", "pdl-override-supported", + "preferred-attributes-supported", "printer-alert", "printer-alert-description", "printer-camera-image-uri", @@ -3686,7 +3838,8 @@ ippserver_attr_cb( "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", @@ -3699,22 +3852,22 @@ ippserver_attr_cb( (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 @@ -3729,11 +3882,11 @@ ippserver_error_cb( // -// '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 @@ -3753,7 +3906,7 @@ load_ippserver_attributes( // - 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); @@ -5294,8 +5447,9 @@ process_ipp(ippeve_client_t *client) // I - Client 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 : @@ -5412,16 +5566,23 @@ process_job(ippeve_job_t *job) // I - Job 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; @@ -5499,7 +5660,7 @@ process_job(ippeve_job_t *job) // I - Job 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")) { @@ -5510,31 +5671,37 @@ process_job(ippeve_job_t *job) // I - Job 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")) { @@ -5544,20 +5711,20 @@ process_job(ippeve_job_t *job) // I - Job 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) @@ -5943,7 +6110,7 @@ register_printer( 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 @@ -5953,7 +6120,7 @@ register_printer( 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 @@ -5963,12 +6130,12 @@ register_printer( 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);