X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=backend%2Fipp.c;h=b2b22065ef4ab9e5e964f1c36d482c9eff4eee8d;hp=85029a69b611ab572f6da477606eacdb339dd698;hb=e35d176c54420e940c32cff2fe8d638b89630dde;hpb=6961465fb290ecc4f99b4e3a8225d594782d15f5 diff --git a/backend/ipp.c b/backend/ipp.c index 85029a69b..b2b22065e 100644 --- a/backend/ipp.c +++ b/backend/ipp.c @@ -1,36 +1,11 @@ /* - * "$Id: ipp.c 9759 2011-05-11 03:24:33Z mike $" + * IPP backend for CUPS. * - * IPP backend for CUPS. + * Copyright © 2007-2019 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2013 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. - * - * 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" - * "LICENSE" which should have been included with this file. If this - * 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() - Send a file to the printer or server. - * cancel_job() - Cancel a print job. - * check_printer_state() - Check the printer state. - * monitor_printer() - Monitor the printer state. - * new_request() - Create a new print creation or validation - * request. - * password_cb() - Disable the password prompt for - * cupsDoFileRequest(). - * quote_string() - Quote a string value. - * report_attr() - Report an IPP attribute value. - * report_printer_state() - Report the printer state. - * run_as_user() - Run the IPP backend as the printing user. - * sigterm_handler() - Handle 'terminate' signals that stop the backend. - * timeout_cb() - Handle HTTP timeouts. - * update_reasons() - Update the printer-state-reasons values. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -38,6 +13,7 @@ */ #include "backend-private.h" +#include #include #include #include @@ -47,12 +23,8 @@ # define kPMPrintUIToolAgent "com.apple.printuitool.agent" # define kPMStartJob 100 # define kPMWaitForJob 101 -# ifdef HAVE_XPC_PRIVATE_H -# include -# else extern void xpc_connection_set_target_uid(xpc_connection_t connection, uid_t uid); -# endif /* HAVE_XPC_PRIVATE_H */ #endif /* HAVE_GSSAPI && HAVE_XPC */ @@ -66,6 +38,8 @@ extern void xpc_connection_set_target_uid(xpc_connection_t connection, #define _CUPS_JSR_ACCOUNT_LIMIT_REACHED 0x08 #define _CUPS_JSR_JOB_PASSWORD_WAIT 0x10 #define _CUPS_JSR_JOB_RELEASE_WAIT 0x20 +#define _CUPS_JSR_DOCUMENT_FORMAT_ERROR 0x40 +#define _CUPS_JSR_DOCUMENT_UNPRINTABLE 0x80 /* @@ -82,11 +56,13 @@ typedef struct _cups_monitor_s /**** Monitoring data ****/ version, /* IPP version */ job_id, /* Job ID for submitted job */ job_reasons, /* Job state reasons bits */ + create_job, /* Support Create-Job? */ get_job_attrs; /* Support Get-Job-Attributes? */ const char *job_name; /* Job name for submitted job */ http_encryption_t encryption; /* Use encryption? */ ipp_jstate_t job_state; /* Current job state */ ipp_pstate_t printer_state; /* Current printer state */ + int retryable; /* Is this a job that should be retried? */ } _cups_monitor_t; @@ -97,7 +73,7 @@ typedef struct _cups_monitor_s /**** Monitoring data ****/ static const char *auth_info_required; /* New auth-info-required value */ #if defined(HAVE_GSSAPI) && defined(HAVE_XPC) -static int child_pid = 0; /* Child process ID */ +static pid_t child_pid = 0; /* Child process ID */ #endif /* HAVE_GSSAPI && HAVE_XPC */ static const char * const jattrs[] = /* Job attributes we want */ { @@ -109,8 +85,10 @@ static const char * const jattrs[] = /* Job attributes we want */ "job-state", "job-state-reasons" }; -static int job_canceled = 0; +static int job_canceled = 0, /* Job cancelled? */ + uri_credentials = 0; + /* Credentials supplied in URI? */ static char username[256] = "", /* Username for device URI */ *password = NULL; @@ -123,6 +101,7 @@ static const char * const pattrs[] = /* Printer attributes we want */ "copies-supported", "cups-version", "document-format-supported", + "job-password-encryption-supported", "marker-colors", "marker-high-levels", "marker-levels", @@ -133,9 +112,11 @@ static const char * const pattrs[] = /* Printer attributes we want */ "media-col-supported", "multiple-document-handling-supported", "operations-supported", + "print-color-mode-supported", "printer-alert", "printer-alert-description", "printer-is-accepting-jobs", + "printer-mandatory-job-attributes", "printer-state", "printer-state-message", "printer-state-reasons" @@ -159,6 +140,8 @@ static cups_option_t *attr_cache = NULL; static cups_array_t *state_reasons; /* Array of printe-state-reasons keywords */ static char tmpfilename[1024] = ""; /* Temporary spool file name */ +static char mandatory_attrs[1024] = ""; + /* cupsMandatory value */ /* @@ -171,6 +154,7 @@ static void cancel_job(http_t *http, const char *uri, int id, static ipp_pstate_t check_printer_state(http_t *http, const char *uri, const char *resource, const char *user, int version); +static void debug_attributes(ipp_t *ipp); static void *monitor_printer(_cups_monitor_t *monitor); static ipp_t *new_request(ipp_op_t op, int version, const char *uri, const char *user, const char *title, @@ -180,7 +164,7 @@ static ipp_t *new_request(ipp_op_t op, int version, const char *uri, ppd_file_t *ppd, ipp_attribute_t *media_col_sup, ipp_attribute_t *doc_handling_sup, - int print_color_mode); + ipp_attribute_t *print_color_mode_sup); static const char *password_cb(const char *prompt, http_t *http, const char *method, const char *resource, int *user_data); @@ -233,7 +217,6 @@ main(int argc, /* I - Number of command-line args */ *compatfile = NULL; /* Compatibility filename */ off_t compatsize = 0; /* Size of compatibility file */ int port; /* Port number (not used) */ - char portname[255]; /* Port name */ char uri[HTTP_MAX_URI]; /* Updated URI without user/pass */ char print_job_name[1024]; /* Update job-name for Print-Job */ http_status_t http_status; /* Status of HTTP request */ @@ -247,9 +230,10 @@ main(int argc, /* I - Number of command-line args */ int delay, /* Delay for retries */ prev_delay; /* Previous delay */ const char *compression; /* Compression mode */ - int waitjob, /* Wait for job complete? */ + int waitjob, /* Wait for job complete? */ waitjob_tries = 0, /* Number of times we've waited */ waitprinter; /* Wait for printer ready? */ + time_t waittime; /* Wait time for held jobs */ _cups_monitor_t monitor; /* Monitoring data */ ipp_attribute_t *job_id_attr; /* job-id attribute */ int job_id; /* job-id value */ @@ -260,6 +244,7 @@ main(int argc, /* I - Number of command-line args */ #endif /* HAVE_LIBZ */ ipp_attribute_t *copies_sup; /* copies-supported */ ipp_attribute_t *cups_version; /* cups-version */ + ipp_attribute_t *encryption_sup; /* job-password-encryption-supported */ ipp_attribute_t *format_sup; /* document-format-supported */ ipp_attribute_t *job_auth; /* job-authorization-uri */ ipp_attribute_t *media_col_sup; /* media-col-supported */ @@ -267,12 +252,12 @@ main(int argc, /* I - Number of command-line args */ ipp_attribute_t *doc_handling_sup; /* multiple-document-handling-supported */ ipp_attribute_t *printer_state; /* printer-state attribute */ ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs */ + ipp_attribute_t *print_color_mode_sup;/* Does printer support print-color-mode? */ int create_job = 0, /* Does printer support Create-Job? */ get_job_attrs = 0, /* Does printer support Get-Job-Attributes? */ send_document = 0, /* Does printer support Send-Document? */ validate_job = 0, /* Does printer support Validate-Job? */ - print_color_mode = 0; /* Does printer support print-color-mode? */ - int copies, /* Number of copies for job */ + copies, /* Number of copies for job */ copies_remaining; /* Number of copies remaining */ const char *content_type, /* CONTENT_TYPE environment variable */ *final_content_type, /* FINAL_CONTENT_TYPE environment var */ @@ -400,7 +385,7 @@ main(int argc, /* I - Number of command-line args */ # else /* No XPC, just try to run as the user ID */ if (uid > 0) - seteuid(uid); + setuid(uid); # endif /* HAVE_XPC */ } #endif /* HAVE_GSSAPI */ @@ -431,10 +416,10 @@ main(int argc, /* I - Number of command-line args */ if (!port) port = IPP_PORT; /* Default to port 631 */ - if (!strcmp(scheme, "https")) - cupsSetEncryption(HTTP_ENCRYPT_ALWAYS); + if (!strcmp(scheme, "https") || !strcmp(scheme, "ipps")) + cupsSetEncryption(HTTP_ENCRYPTION_ALWAYS); else - cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED); + cupsSetEncryption(HTTP_ENCRYPTION_IF_REQUESTED); /* * See if there are any options... @@ -521,13 +506,13 @@ main(int argc, /* I - Number of command-line args */ */ if (!_cups_strcasecmp(value, "always")) - cupsSetEncryption(HTTP_ENCRYPT_ALWAYS); + cupsSetEncryption(HTTP_ENCRYPTION_ALWAYS); else if (!_cups_strcasecmp(value, "required")) - cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + cupsSetEncryption(HTTP_ENCRYPTION_REQUIRED); else if (!_cups_strcasecmp(value, "never")) - cupsSetEncryption(HTTP_ENCRYPT_NEVER); + cupsSetEncryption(HTTP_ENCRYPTION_NEVER); else if (!_cups_strcasecmp(value, "ifrequested")) - cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED); + cupsSetEncryption(HTTP_ENCRYPTION_IF_REQUESTED); else { _cupsLangPrintFilter(stderr, "ERROR", @@ -542,8 +527,8 @@ main(int argc, /* I - Number of command-line args */ */ snmp_enabled = !value[0] || !_cups_strcasecmp(value, "on") || - _cups_strcasecmp(value, "yes") || - _cups_strcasecmp(value, "true"); + !_cups_strcasecmp(value, "yes") || + !_cups_strcasecmp(value, "true"); } else if (!_cups_strcasecmp(name, "version")) { @@ -646,6 +631,7 @@ main(int argc, /* I - Number of command-line args */ *password++ = '\0'; cupsSetUser(username); + uri_credentials = 1; } else { @@ -670,26 +656,7 @@ main(int argc, /* I - Number of command-line args */ start_time = time(NULL); - sprintf(portname, "%d", port); - - update_reasons(NULL, "+connecting-to-device"); - fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname); - - while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) - { - _cupsLangPrintFilter(stderr, "INFO", - _("Unable to locate printer \"%s\"."), hostname); - sleep(10); - - if (getenv("CLASS") != NULL) - { - update_reasons(NULL, "-connecting-to-device"); - return (CUPS_BACKEND_STOP); - } - - if (job_canceled) - return (CUPS_BACKEND_OK); - } + addrlist = backendLookup(hostname, port, &job_canceled); http = httpConnect2(hostname, port, addrlist, AF_UNSPEC, cupsEncryption(), 1, 0, NULL); @@ -733,11 +700,11 @@ main(int argc, /* I - Number of command-line args */ fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port); _cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer.")); - if (httpReconnect(http)) + if (httpReconnect2(http, 30000, NULL)) { int error = errno; /* Connection error */ - if (http->status == HTTP_PKI_ERROR) + if (http->status == HTTP_STATUS_CUPS_PKI_ERROR) update_reasons(NULL, "+cups-certificate-error"); if (job_canceled) @@ -769,8 +736,7 @@ main(int argc, /* I - Number of command-line args */ fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(errno)); - if (errno == ECONNREFUSED || errno == EHOSTDOWN || - errno == EHOSTUNREACH) + if (errno == ECONNREFUSED || errno == EHOSTDOWN || errno == EHOSTUNREACH || errno == ETIMEDOUT || errno == ENOTCONN) { if (contimeout && (time(NULL) - start_time) > contimeout) { @@ -789,19 +755,19 @@ main(int argc, /* I - Number of command-line args */ break; case EHOSTUNREACH : + default : _cupsLangPrintFilter(stderr, "WARNING", _("The printer is unreachable at this " "time.")); break; case ECONNREFUSED : - default : _cupsLangPrintFilter(stderr, "WARNING", _("The printer is in use.")); break; } - sleep(delay); + sleep((unsigned)delay); delay = _cupsNextDelay(delay, &prev_delay); } @@ -825,6 +791,76 @@ main(int argc, /* I - Number of command-line args */ else if (!http) return (CUPS_BACKEND_FAILED); + if (httpIsEncrypted(http)) + { + /* + * Validate TLS credentials... + */ + + cups_array_t *creds; /* TLS credentials */ + cups_array_t *lcreds = NULL; /* Loaded credentials */ + http_trust_t trust; /* Trust level */ + char credinfo[1024], /* Information on credentials */ + lcredinfo[1024];/* Information on saved credentials */ + static const char * const trusts[] = { NULL, "+cups-pki-invalid", "+cups-pki-changed", "+cups-pki-expired", NULL, "+cups-pki-unknown" }; + /* Trust keywords */ + static const char * const trust_msgs[] = + { + "Credentials are OK/trusted", + "Credentials are invalid", + "Credentials have changed", + "Credentials are expired", + "Credentials have been renewed", + "Credentials are unknown/new" + }; + + fputs("DEBUG: Connection is encrypted.\n", stderr); + + if (!httpCopyCredentials(http, &creds)) + { + trust = httpCredentialsGetTrust(creds, hostname); + httpCredentialsString(creds, credinfo, sizeof(credinfo)); + + fprintf(stderr, "DEBUG: %s (%s)\n", trust_msgs[trust], cupsLastErrorString()); + fprintf(stderr, "DEBUG: Printer credentials: %s\n", credinfo); + + if (!httpLoadCredentials(NULL, &lcreds, hostname)) + { + httpCredentialsString(lcreds, lcredinfo, sizeof(lcredinfo)); + fprintf(stderr, "DEBUG: Stored credentials: %s\n", lcredinfo); + } + else + fputs("DEBUG: No stored credentials.\n", stderr); + + update_reasons(NULL, "-cups-pki-invalid,cups-pki-changed,cups-pki-expired,cups-pki-unknown"); + if (trusts[trust]) + { + update_reasons(NULL, trusts[trust]); + return (CUPS_BACKEND_STOP); + } + + if (!lcreds) + { + /* + * Could not load the credentials, let's save the ones we have so we + * can detect changes... + */ + + httpSaveCredentials(NULL, creds, hostname); + } + + httpFreeCredentials(lcreds); + httpFreeCredentials(creds); + } + else + { + fputs("DEBUG: No printer credentials.\n", stderr); + + update_reasons(NULL, "cups-pki-unknown"); + return (CUPS_BACKEND_STOP); + } + } + update_reasons(NULL, "-connecting-to-device"); _cupsLangPrintFilter(stderr, "INFO", _("Connected to printer.")); @@ -847,15 +883,17 @@ main(int argc, /* I - Number of command-line args */ */ #ifdef HAVE_LIBZ - compression_sup = NULL; + compression_sup = NULL; #endif /* HAVE_LIBZ */ - copies_sup = NULL; - cups_version = NULL; - format_sup = NULL; - media_col_sup = NULL; - supported = NULL; - operations_sup = NULL; - doc_handling_sup = NULL; + copies_sup = NULL; + cups_version = NULL; + encryption_sup = NULL; + format_sup = NULL; + media_col_sup = NULL; + supported = NULL; + operations_sup = NULL; + doc_handling_sup = NULL; + print_color_mode_sup = NULL; do { @@ -869,10 +907,8 @@ main(int argc, /* I - Number of command-line args */ * Build the IPP request... */ - request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); - request->request.op.version[0] = version / 10; - request->request.op.version[1] = version % 10; - + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippSetVersion(request, version / 10, version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -886,7 +922,7 @@ main(int argc, /* I - Number of command-line args */ fputs("DEBUG: Getting supported attributes...\n", stderr); - if (http->version < HTTP_1_1) + if (http->version < HTTP_VERSION_1_1) { fprintf(stderr, "DEBUG: Printer responded with HTTP version %d.%d.\n", http->version / 100, http->version % 100); @@ -900,15 +936,15 @@ main(int argc, /* I - Number of command-line args */ fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n", ippErrorString(ipp_status), cupsLastErrorString()); - if (ipp_status <= IPP_OK_CONFLICT) + if (ipp_status <= IPP_STATUS_OK_CONFLICTING) password_tries = 0; else { fprintf(stderr, "DEBUG: Get-Printer-Attributes returned %s.\n", ippErrorString(ipp_status)); - if (ipp_status == IPP_PRINTER_BUSY || - ipp_status == IPP_SERVICE_UNAVAILABLE) + if (ipp_status == IPP_STATUS_ERROR_BUSY || + ipp_status == IPP_STATUS_ERROR_SERVICE_UNAVAILABLE) { if (contimeout && (time(NULL) - start_time) > contimeout) { @@ -921,12 +957,12 @@ main(int argc, /* I - Number of command-line args */ report_printer_state(supported); - sleep(delay); + sleep((unsigned)delay); delay = _cupsNextDelay(delay, &prev_delay); } - else if ((ipp_status == IPP_BAD_REQUEST || - ipp_status == IPP_VERSION_NOT_SUPPORTED) && version > 10) + else if ((ipp_status == IPP_STATUS_ERROR_BAD_REQUEST || + ipp_status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) && version > 10) { /* * Switch to IPP/1.1 or IPP/1.0... @@ -949,9 +985,9 @@ main(int argc, /* I - Number of command-line args */ version = 10; } - httpReconnect(http); + httpReconnect2(http, 30000, NULL); } - else if (ipp_status == IPP_NOT_FOUND) + else if (ipp_status == IPP_STATUS_ERROR_NOT_FOUND) { _cupsLangPrintFilter(stderr, "ERROR", _("The printer configuration is incorrect or the " @@ -961,8 +997,8 @@ main(int argc, /* I - Number of command-line args */ return (CUPS_BACKEND_STOP); } - else if (ipp_status == IPP_FORBIDDEN || - ipp_status == IPP_AUTHENTICATION_CANCELED) + else if (ipp_status == IPP_STATUS_ERROR_FORBIDDEN || + ipp_status == IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED) { const char *www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); /* WWW-Authenticate field value */ @@ -975,13 +1011,13 @@ main(int argc, /* I - Number of command-line args */ fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required); return (CUPS_BACKEND_AUTH_REQUIRED); } - else if (ipp_status != IPP_NOT_AUTHORIZED) + else if (ipp_status != IPP_STATUS_ERROR_NOT_AUTHORIZED) { _cupsLangPrintFilter(stderr, "ERROR", _("Unable to get printer status.")); sleep(10); - httpReconnect(http); + httpReconnect2(http, 30000, NULL); } ippDelete(supported); @@ -1035,12 +1071,13 @@ main(int argc, /* I - Number of command-line args */ report_printer_state(supported); - sleep(delay); + sleep((unsigned)delay); delay = _cupsNextDelay(delay, &prev_delay); ippDelete(supported); - supported = NULL; + supported = NULL; + ipp_status = IPP_STATUS_ERROR_BUSY; continue; } } @@ -1064,7 +1101,7 @@ main(int argc, /* I - Number of command-line args */ "compression value \"%s\".\n", compression); compression = NULL; } - else if (!compression) + else if (!compression && (!strcmp(final_content_type, "image/pwg-raster") || !strcmp(final_content_type, "image/urf"))) { if (ippContainsString(compression_sup, "gzip")) compression = "gzip"; @@ -1094,7 +1131,16 @@ main(int argc, /* I - Number of command-line args */ copies_sup = NULL; /* No */ } - cups_version = ippFindAttribute(supported, "cups-version", IPP_TAG_TEXT); + if ((cups_version = ippFindAttribute(supported, "cups-version", IPP_TAG_TEXT)) != NULL) + { + const char *val = ippGetString(cups_version, 0, NULL); + + fprintf(stderr, "DEBUG: cups-version = \"%s\"\n", val); + if (!strcmp(val, "cups-version")) + cups_version = NULL; /* Bogus cups-version value returned by buggy printers! */ + } + + encryption_sup = ippFindAttribute(supported, "job-password-encryption-supported", IPP_TAG_KEYWORD); if ((format_sup = ippFindAttribute(supported, "document-format-supported", IPP_TAG_MIMETYPE)) != NULL) @@ -1116,9 +1162,7 @@ main(int argc, /* I - Number of command-line args */ media_col_sup->values[i].string.text); } - print_color_mode = ippFindAttribute(supported, - "print-color-mode-supported", - IPP_TAG_KEYWORD) != NULL; + print_color_mode_sup = ippFindAttribute(supported, "print-color-mode-supported", IPP_TAG_KEYWORD); if ((operations_sup = ippFindAttribute(supported, "operations-supported", IPP_TAG_ENUM)) != NULL) @@ -1130,7 +1174,7 @@ main(int argc, /* I - Number of command-line args */ ippOpString(operations_sup->values[i].integer)); for (i = 0; i < operations_sup->num_values; i ++) - if (operations_sup->values[i].integer == IPP_PRINT_JOB) + if (operations_sup->values[i].integer == IPP_OP_PRINT_JOB) break; if (i >= operations_sup->num_values) @@ -1138,7 +1182,7 @@ main(int argc, /* I - Number of command-line args */ "cups-ipp-missing-print-job"); for (i = 0; i < operations_sup->num_values; i ++) - if (operations_sup->values[i].integer == IPP_CANCEL_JOB) + if (operations_sup->values[i].integer == IPP_OP_CANCEL_JOB) break; if (i >= operations_sup->num_values) @@ -1146,7 +1190,7 @@ main(int argc, /* I - Number of command-line args */ "cups-ipp-missing-cancel-job"); for (i = 0; i < operations_sup->num_values; i ++) - if (operations_sup->values[i].integer == IPP_GET_JOB_ATTRIBUTES) + if (operations_sup->values[i].integer == IPP_OP_GET_JOB_ATTRIBUTES) break; if (i >= operations_sup->num_values) @@ -1154,7 +1198,7 @@ main(int argc, /* I - Number of command-line args */ "cups-ipp-missing-get-job-attributes"); for (i = 0; i < operations_sup->num_values; i ++) - if (operations_sup->values[i].integer == IPP_GET_PRINTER_ATTRIBUTES) + if (operations_sup->values[i].integer == IPP_OP_GET_PRINTER_ATTRIBUTES) break; if (i >= operations_sup->num_values) @@ -1163,13 +1207,13 @@ main(int argc, /* I - Number of command-line args */ for (i = 0; i < operations_sup->num_values; i ++) { - if (operations_sup->values[i].integer == IPP_VALIDATE_JOB) + if (operations_sup->values[i].integer == IPP_OP_VALIDATE_JOB) validate_job = 1; - else if (operations_sup->values[i].integer == IPP_CREATE_JOB) + else if (operations_sup->values[i].integer == IPP_OP_CREATE_JOB) create_job = 1; - else if (operations_sup->values[i].integer == IPP_SEND_DOCUMENT) + else if (operations_sup->values[i].integer == IPP_OP_SEND_DOCUMENT) send_document = 1; - else if (operations_sup->values[i].integer == IPP_GET_JOB_ATTRIBUTES) + else if (operations_sup->values[i].integer == IPP_OP_GET_JOB_ATTRIBUTES) get_job_attrs = 1; } @@ -1197,7 +1241,7 @@ main(int argc, /* I - Number of command-line args */ report_printer_state(supported); } - while (!job_canceled && ipp_status > IPP_OK_CONFLICT); + while (!job_canceled && ipp_status > IPP_STATUS_OK_CONFLICTING); if (job_canceled) return (CUPS_BACKEND_OK); @@ -1215,7 +1259,7 @@ main(int argc, /* I - Number of command-line args */ IPP_TAG_BOOLEAN); if (printer_state == NULL || - (printer_state->values[0].integer > IPP_PRINTER_PROCESSING && + (printer_state->values[0].integer > IPP_PSTATE_PROCESSING && waitprinter) || printer_accepting == NULL || !printer_accepting->values[0].boolean) @@ -1271,11 +1315,51 @@ main(int argc, /* I - Number of command-line args */ * Load the PPD file and generate PWG attribute mapping information... */ + ppd_attr_t *mandatory; /* cupsMandatory value */ + ppd = ppdOpenFile(getenv("PPD")); pc = _ppdCacheCreateWithPPD(ppd); ppdMarkDefaults(ppd); cupsMarkOptions(ppd, num_options, options); + + if ((mandatory = ppdFindAttr(ppd, "cupsMandatory", NULL)) != NULL) + strlcpy(mandatory_attrs, mandatory->value, sizeof(mandatory_attrs)); + } + + /* + * Validate job-password/-encryption... + */ + + if (cupsGetOption("job-password", num_options, options)) + { + const char *keyword; /* job-password-encryption value */ + static const char * const hashes[] = + { /* List of supported hash algorithms, in order of preference */ + "sha-512", + "sha-384", + "sha-512_256", + "sha-512-224", + "sha-256", + "sha-224", + "sha", + "none" + }; + + if ((keyword = cupsGetOption("job-password-encryption", num_options, options)) == NULL || !ippContainsString(encryption_sup, keyword)) + { + /* + * Either no job-password-encryption or the value isn't supported by + * the printer... + */ + + for (i = 0; i < (int)(sizeof(hashes) / sizeof(hashes[0])); i ++) + if (ippContainsString(encryption_sup, hashes[i])) + break; + + if (i < (int)(sizeof(hashes) / sizeof(hashes[0]))) + num_options = cupsAddOption("job-password-encryption", hashes[i], num_options, &options); + } } } else @@ -1285,24 +1369,10 @@ main(int argc, /* I - Number of command-line args */ if (format_sup != NULL) { - for (i = 0; i < format_sup->num_values; i ++) - if (!_cups_strcasecmp(final_content_type, - format_sup->values[i].string.text)) - { - document_format = final_content_type; - break; - } - - if (!document_format) - { - for (i = 0; i < format_sup->num_values; i ++) - if (!_cups_strcasecmp("application/octet-stream", - format_sup->values[i].string.text)) - { - document_format = "application/octet-stream"; - break; - } - } + if (ippContainsString(format_sup, final_content_type)) + document_format = final_content_type; + else if (ippContainsString(format_sup, "application/octet-stream")) + document_format = "application/octet-stream"; } fprintf(stderr, "DEBUG: final_content_type=\"%s\", document_format=\"%s\"\n", @@ -1315,7 +1385,7 @@ main(int argc, /* I - Number of command-line args */ * (I hate compatibility hacks!) */ - if (http->version < HTTP_1_1 && num_files == 0) + if (http->version < HTTP_VERSION_1_1 && num_files == 0) { if ((fd = cupsTempFd(tmpfilename, sizeof(tmpfilename))) < 0) { @@ -1325,7 +1395,7 @@ main(int argc, /* I - Number of command-line args */ _cupsLangPrintFilter(stderr, "INFO", _("Copying print data.")); - if ((compatsize = write(fd, buffer, bytes)) < 0) + if ((compatsize = write(fd, buffer, (size_t)bytes)) < 0) { perror("DEBUG: Unable to write temporary file"); return (CUPS_BACKEND_FAILED); @@ -1343,7 +1413,7 @@ main(int argc, /* I - Number of command-line args */ files = &compatfile; num_files = 1; } - else if (http->version < HTTP_1_1 && num_files == 1) + else if (http->version < HTTP_VERSION_1_1 && num_files == 1) { struct stat fileinfo; /* File information */ @@ -1373,10 +1443,14 @@ main(int argc, /* I - Number of command-line args */ monitor.port = port; monitor.version = version; monitor.job_id = 0; + monitor.create_job = create_job; monitor.get_job_attrs = get_job_attrs; monitor.encryption = cupsEncryption(); - monitor.job_state = IPP_JOB_PENDING; - monitor.printer_state = IPP_PRINTER_IDLE; + monitor.job_state = IPP_JSTATE_PENDING; + monitor.printer_state = IPP_PSTATE_IDLE; + monitor.retryable = argc == 6 && document_format && strcmp(document_format, "image/pwg-raster") && strcmp(document_format, "image/urf"); + + fprintf(stderr, "DEBUG: retryable=%d\n", monitor.retryable); if (create_job) { @@ -1397,10 +1471,10 @@ main(int argc, /* I - Number of command-line args */ while (!job_canceled && validate_job) { - request = new_request(IPP_VALIDATE_JOB, version, uri, argv[2], + request = new_request(IPP_OP_VALIDATE_JOB, version, uri, argv[2], monitor.job_name, num_options, options, compression, copies_sup ? copies : 1, document_format, pc, ppd, - media_col_sup, doc_handling_sup, print_color_mode); + media_col_sup, doc_handling_sup, print_color_mode_sup); response = cupsDoRequest(http, request, resource); @@ -1408,6 +1482,7 @@ main(int argc, /* I - Number of command-line args */ fprintf(stderr, "DEBUG: Validate-Job: %s (%s)\n", ippErrorString(ipp_status), cupsLastErrorString()); + debug_attributes(response); if ((job_auth = ippFindAttribute(response, "job-authorization-uri", IPP_TAG_URI)) != NULL) @@ -1415,6 +1490,30 @@ main(int argc, /* I - Number of command-line args */ ippGetString(job_auth, 0, NULL), num_options, &options); + if (ipp_status == IPP_STATUS_OK_IGNORED_OR_SUBSTITUTED || ipp_status == IPP_STATUS_OK_CONFLICTING) + { + /* + * One or more options are not supported... + */ + + ipp_attribute_t *attr; /* Unsupported attribute */ + + if ((attr = ippFindAttribute(response, "sides", IPP_TAG_ZERO)) != NULL) + { + /* + * The sides value is not supported, revert to one-sided as needed... + */ + + const char *sides = cupsGetOption("sides", num_options, options); + + if (!sides || !strncmp(sides, "two-sided-", 10)) + { + fputs("DEBUG: Unable to do two-sided printing, setting sides to 'one-sided'.\n", stderr); + num_options = cupsAddOption("sides", "one-sided", num_options, &options); + } + } + } + ippDelete(response); if (job_canceled) @@ -1427,12 +1526,14 @@ main(int argc, /* I - Number of command-line args */ sleep(10); } else if (ipp_status == IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED || + ipp_status == IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_INFO_NEEDED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_CLOSED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_LIMIT_REACHED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED) goto cleanup; else if (ipp_status == IPP_STATUS_ERROR_FORBIDDEN || + ipp_status == IPP_STATUS_ERROR_NOT_AUTHORIZED || ipp_status == IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED) { const char *www_auth = httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE); @@ -1455,9 +1556,11 @@ main(int argc, /* I - Number of command-line args */ "cups-ipp-missing-validate-job"); break; } - else if (ipp_status < IPP_REDIRECTION_OTHER_SITE || - ipp_status == IPP_BAD_REQUEST) + else if (ipp_status < IPP_STATUS_REDIRECTION_OTHER_SITE || + ipp_status == IPP_STATUS_ERROR_BAD_REQUEST) break; + else if (job_auth == NULL && ipp_status > IPP_STATUS_ERROR_BAD_REQUEST) + goto cleanup; } /* @@ -1481,12 +1584,12 @@ main(int argc, /* I - Number of command-line args */ if (job_canceled) break; - request = new_request((num_files > 1 || create_job) ? IPP_CREATE_JOB : - IPP_PRINT_JOB, + request = new_request((num_files > 1 || create_job) ? IPP_OP_CREATE_JOB : + IPP_OP_PRINT_JOB, version, uri, argv[2], monitor.job_name, num_options, options, compression, copies_sup ? copies : 1, document_format, pc, ppd, media_col_sup, - doc_handling_sup, print_color_mode); + doc_handling_sup, print_color_mode_sup); /* * Do the request... @@ -1507,7 +1610,7 @@ main(int argc, /* I - Number of command-line args */ fputs("DEBUG: Sending file using HTTP/1.1 chunking...\n", stderr); http_status = cupsSendRequest(http, request, resource, length); - if (http_status == HTTP_CONTINUE && request->state == IPP_DATA) + if (http_status == HTTP_STATUS_CONTINUE && request->state == IPP_STATE_DATA) { if (compression && strcmp(compression, "none")) httpSetField(http, HTTP_FIELD_CONTENT_ENCODING, compression); @@ -1523,10 +1626,10 @@ main(int argc, /* I - Number of command-line args */ else { fd = 0; - http_status = cupsWriteRequestData(http, buffer, bytes); + http_status = cupsWriteRequestData(http, buffer, (size_t)bytes); } - while (http_status == HTTP_CONTINUE && + while (http_status == HTTP_STATUS_CONTINUE && (!job_canceled || compatsize > 0)) { /* @@ -1536,6 +1639,7 @@ main(int argc, /* I - Number of command-line args */ FD_ZERO(&input); FD_SET(fd, &input); FD_SET(snmp_fd, &input); + FD_SET(CUPS_SC_FD, &input); while (select(fd > snmp_fd ? fd + 1 : snmp_fd + 1, &input, NULL, NULL, NULL) <= 0 && !job_canceled); @@ -1549,8 +1653,8 @@ main(int argc, /* I - Number of command-line args */ { fprintf(stderr, "DEBUG: Read %d bytes...\n", (int)bytes); - if ((http_status = cupsWriteRequestData(http, buffer, bytes)) - != HTTP_CONTINUE) + if ((http_status = cupsWriteRequestData(http, buffer, (size_t)bytes)) + != HTTP_STATUS_CONTINUE) break; } else if (bytes == 0 || (errno != EINTR && errno != EAGAIN)) @@ -1558,7 +1662,7 @@ main(int argc, /* I - Number of command-line args */ } } - if (http_status == HTTP_ERROR) + if (http_status == HTTP_STATUS_ERROR) fprintf(stderr, "DEBUG: Error writing document data for " "Print-Job: %s\n", strerror(httpError(http))); @@ -1575,8 +1679,9 @@ main(int argc, /* I - Number of command-line args */ fprintf(stderr, "DEBUG: %s: %s (%s)\n", (num_files > 1 || create_job) ? "Create-Job" : "Print-Job", ippErrorString(ipp_status), cupsLastErrorString()); + debug_attributes(response); - if (ipp_status > IPP_OK_CONFLICT) + if (ipp_status > IPP_STATUS_OK_CONFLICTING) { job_id = 0; @@ -1628,7 +1733,7 @@ main(int argc, /* I - Number of command-line args */ else if (www_auth[0]) auth_info_required = "username,password"; } - else if (ipp_status == IPP_REQUEST_VALUE) + else if (ipp_status == IPP_STATUS_ERROR_REQUEST_VALUE) { /* * Print file is too large, abort this job... @@ -1684,9 +1789,8 @@ main(int argc, /* I - Number of command-line args */ * Send the next file in the job... */ - request = ippNewRequest(IPP_SEND_DOCUMENT); - request->request.op.version[0] = version / 10; - request->request.op.version[1] = version % 10; + request = ippNewRequest(IPP_OP_SEND_DOCUMENT); + ippSetVersion(request, version / 10, version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -1698,8 +1802,8 @@ main(int argc, /* I - Number of command-line args */ ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, argv[2]); - if ((i + 1) >= num_files) - ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", 1); + ippAddBoolean(request, IPP_TAG_OPERATION, "last-document", + (i + 1) >= num_files); if (document_format) ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, @@ -1710,8 +1814,11 @@ main(int argc, /* I - Number of command-line args */ "compression", NULL, compression); fprintf(stderr, "DEBUG: Sending file %d using chunking...\n", i + 1); + fprintf(stderr, "DEBUG: IPP/%d.%d %s #%d\n", version / 10, version % 10, ippOpString(ippGetOperation(request)), ippGetRequestId(request)); + debug_attributes(request); + http_status = cupsSendRequest(http, request, resource, 0); - if (http_status == HTTP_CONTINUE && request->state == IPP_DATA) + if (http_status == HTTP_STATUS_CONTINUE && request->state == IPP_STATE_DATA) { if (compression && strcmp(compression, "none")) httpSetField(http, HTTP_FIELD_CONTENT_ENCODING, compression); @@ -1719,7 +1826,7 @@ main(int argc, /* I - Number of command-line args */ if (num_files == 0) { fd = 0; - http_status = cupsWriteRequestData(http, buffer, bytes); + http_status = cupsWriteRequestData(http, buffer, (size_t)bytes); } else { @@ -1735,11 +1842,11 @@ main(int argc, /* I - Number of command-line args */ if (fd >= 0) { - while (!job_canceled && http_status == HTTP_CONTINUE && + while (!job_canceled && http_status == HTTP_STATUS_CONTINUE && (bytes = read(fd, buffer, sizeof(buffer))) > 0) { - if ((http_status = cupsWriteRequestData(http, buffer, bytes)) - != HTTP_CONTINUE) + if ((http_status = cupsWriteRequestData(http, buffer, (size_t)bytes)) + != HTTP_STATUS_CONTINUE) break; else { @@ -1755,26 +1862,36 @@ main(int argc, /* I - Number of command-line args */ close(fd); } - if (http_status == HTTP_ERROR) + if (http_status == HTTP_STATUS_ERROR) fprintf(stderr, "DEBUG: Error writing document data for " "Send-Document: %s\n", strerror(httpError(http))); - ippDelete(cupsGetResponse(http, resource)); + response = cupsGetResponse(http, resource); ippDelete(request); - fprintf(stderr, "DEBUG: Send-Document: %s (%s)\n", - ippErrorString(cupsLastError()), cupsLastErrorString()); + fprintf(stderr, "DEBUG: Send-Document: %s (%s)\n", ippErrorString(cupsLastError()), cupsLastErrorString()); + debug_attributes(response); - if (cupsLastError() > IPP_OK_CONFLICT) + if (cupsLastError() > IPP_STATUS_OK_CONFLICTING && !job_canceled) { + ipp_attribute_t *reasons = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD); + /* job-state-reasons values */ + ipp_status = cupsLastError(); - _cupsLangPrintFilter(stderr, "ERROR", - _("Unable to add document to print job.")); + if (ippContainsString(reasons, "document-format-error")) + ipp_status = IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR; + else if (ippContainsString(reasons, "document-unprintable")) + ipp_status = IPP_STATUS_ERROR_DOCUMENT_UNPRINTABLE; + + ippDelete(response); + _cupsLangPrintFilter(stderr, "ERROR", _("Unable to add document to print job.")); break; } else { + ippDelete(response); + password_tries = 0; if (num_files == 0 || fd < 0) @@ -1783,14 +1900,31 @@ main(int argc, /* I - Number of command-line args */ } } - if (ipp_status <= IPP_OK_CONFLICT && argc > 6) + if (job_canceled) + break; + + if (ipp_status <= IPP_STATUS_OK_CONFLICTING && argc > 6) { fprintf(stderr, "PAGE: 1 %d\n", copies_sup ? atoi(argv[4]) : 1); copies_remaining --; } - else if (ipp_status == IPP_SERVICE_UNAVAILABLE || - ipp_status == IPP_NOT_POSSIBLE || - ipp_status == IPP_PRINTER_BUSY) + else if ((ipp_status == IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED || ipp_status == IPP_STATUS_ERROR_DOCUMENT_FORMAT_ERROR || ipp_status == IPP_STATUS_ERROR_DOCUMENT_UNPRINTABLE) && + argc == 6 && + document_format && strcmp(document_format, "image/pwg-raster") && strcmp(document_format, "image/urf")) + { + /* + * Need to reprocess the job as raster... + */ + + fputs("JOBSTATE: cups-retry-as-raster\n", stderr); + if (job_id > 0) + cancel_job(http, uri, job_id, resource, argv[2], version); + + goto cleanup; + } + else if (ipp_status == IPP_STATUS_ERROR_SERVICE_UNAVAILABLE || + ipp_status == IPP_STATUS_ERROR_NOT_POSSIBLE || + ipp_status == IPP_STATUS_ERROR_BUSY) { if (argc == 6) { @@ -1806,14 +1940,14 @@ main(int argc, /* I - Number of command-line args */ } continue; } - else if (ipp_status == IPP_REQUEST_VALUE || - ipp_status == IPP_ERROR_JOB_CANCELED || - ipp_status == IPP_NOT_AUTHORIZED || + else if (ipp_status == IPP_STATUS_ERROR_REQUEST_VALUE || + ipp_status == IPP_STATUS_ERROR_JOB_CANCELED || + ipp_status == IPP_STATUS_ERROR_NOT_AUTHORIZED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_INFO_NEEDED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_CLOSED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_LIMIT_REACHED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED || - ipp_status == IPP_INTERNAL_ERROR) + ipp_status == IPP_STATUS_ERROR_INTERNAL) { /* * Print file is too large, job was canceled, we need new @@ -1843,7 +1977,7 @@ main(int argc, /* I - Number of command-line args */ goto cleanup; } - else if (ipp_status == IPP_NOT_FOUND) + else if (ipp_status == IPP_STATUS_ERROR_NOT_FOUND) { /* * Printer does not actually implement support for Create-Job/ @@ -1857,7 +1991,7 @@ main(int argc, /* I - Number of command-line args */ update_reasons(NULL, "+cups-ipp-conformance-failure-report," "cups-ipp-missing-send-document"); - ipp_status = IPP_INTERNAL_ERROR; /* Force queue to stop */ + ipp_status = IPP_STATUS_ERROR_INTERNAL; /* Force queue to stop */ goto cleanup; } @@ -1871,9 +2005,11 @@ main(int argc, /* I - Number of command-line args */ if (!job_id || !waitjob || !get_job_attrs) continue; + fputs("STATE: +cups-waiting-for-job-completed\n", stderr); + _cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete.")); - for (delay = _cupsNextDelay(0, &prev_delay); !job_canceled;) + for (delay = _cupsNextDelay(0, &prev_delay), waittime = time(NULL) + 30; !job_canceled;) { /* * Check for side-channel requests... @@ -1887,16 +2023,15 @@ main(int argc, /* I - Number of command-line args */ check_printer_state(http, uri, resource, argv[2], version); - if (cupsLastError() <= IPP_OK_CONFLICT) + if (cupsLastError() <= IPP_STATUS_OK_CONFLICTING) password_tries = 0; /* - * Build an IPP_GET_JOB_ATTRIBUTES request... + * Build an IPP_OP_GET_JOB_ATTRIBUTES request... */ - request = ippNewRequest(IPP_GET_JOB_ATTRIBUTES); - request->request.op.version[0] = version / 10; - request->request.op.version[1] = version % 10; + request = ippNewRequest(IPP_OP_GET_JOB_ATTRIBUTES); + ippSetVersion(request, version / 10, version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -1912,15 +2047,18 @@ main(int argc, /* I - Number of command-line args */ "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]), NULL, jattrs); + fprintf(stderr, "DEBUG: IPP/%d.%d %s #%d\n", version / 10, version % 10, ippOpString(ippGetOperation(request)), ippGetRequestId(request)); + debug_attributes(request); + /* * Do the request... */ - httpReconnect(http); + httpReconnect2(http, 30000, NULL); response = cupsDoRequest(http, request, resource); ipp_status = cupsLastError(); - if (ipp_status == IPP_NOT_FOUND || ipp_status == IPP_NOT_POSSIBLE) + if (ipp_status == IPP_STATUS_ERROR_NOT_FOUND || ipp_status == IPP_STATUS_ERROR_NOT_POSSIBLE) { /* * Job has gone away and/or the server has no job history... @@ -1930,32 +2068,33 @@ main(int argc, /* I - Number of command-line args */ "cups-ipp-missing-job-history"); ippDelete(response); - ipp_status = IPP_OK; + ipp_status = IPP_STATUS_OK; break; } fprintf(stderr, "DEBUG: Get-Job-Attributes: %s (%s)\n", ippErrorString(ipp_status), cupsLastErrorString()); + debug_attributes(response); - if (ipp_status <= IPP_OK_CONFLICT) + if (ipp_status <= IPP_STATUS_OK_CONFLICTING) password_tries = 0; else { - if (ipp_status != IPP_SERVICE_UNAVAILABLE && - ipp_status != IPP_PRINTER_BUSY) + if (ipp_status != IPP_STATUS_ERROR_SERVICE_UNAVAILABLE && + ipp_status != IPP_STATUS_ERROR_BUSY) { ippDelete(response); - ipp_status = IPP_OK; + ipp_status = IPP_STATUS_OK; break; } - else if (ipp_status == IPP_INTERNAL_ERROR) + else if (ipp_status == IPP_STATUS_ERROR_INTERNAL) { waitjob_tries ++; if (waitjob_tries > 4) { ippDelete(response); - ipp_status = IPP_OK; + ipp_status = IPP_STATUS_OK; break; } } @@ -1971,36 +2110,33 @@ main(int argc, /* I - Number of command-line args */ */ if (cups_version && - job_state->values[0].integer >= IPP_JOB_PENDING && - job_state->values[0].integer <= IPP_JOB_COMPLETED) + job_state->values[0].integer >= IPP_JSTATE_PENDING && + job_state->values[0].integer <= IPP_JSTATE_COMPLETED) update_reasons(NULL, remote_job_states[job_state->values[0].integer - - IPP_JOB_PENDING]); + IPP_JSTATE_PENDING]); - if ((job_sheets = ippFindAttribute(response, - "job-media-sheets-completed", - IPP_TAG_INTEGER)) == NULL) - job_sheets = ippFindAttribute(response, - "job-impressions-completed", - IPP_TAG_INTEGER); + if ((job_sheets = ippFindAttribute(response, "job-impressions-completed", IPP_TAG_INTEGER)) == NULL) + job_sheets = ippFindAttribute(response, "job-media-sheets-completed", IPP_TAG_INTEGER); if (job_sheets) fprintf(stderr, "PAGE: total %d\n", job_sheets->values[0].integer); /* - * Stop polling if the job is finished or pending-held... + * Stop polling if the job is finished or pending-held for 30 seconds... */ - if (job_state->values[0].integer > IPP_JOB_STOPPED) + if (job_state->values[0].integer > IPP_JSTATE_STOPPED || + (job_state->values[0].integer == IPP_JSTATE_HELD && time(NULL) > waittime)) { ippDelete(response); break; } } - else if (ipp_status != IPP_SERVICE_UNAVAILABLE && - ipp_status != IPP_NOT_POSSIBLE && - ipp_status != IPP_PRINTER_BUSY) + else if (ipp_status != IPP_STATUS_ERROR_SERVICE_UNAVAILABLE && + ipp_status != IPP_STATUS_ERROR_NOT_POSSIBLE && + ipp_status != IPP_STATUS_ERROR_BUSY) { /* * If the printer does not return a job-state attribute, it does not @@ -2010,7 +2146,7 @@ main(int argc, /* I - Number of command-line args */ update_reasons(NULL, "+cups-ipp-conformance-failure-report," "cups-ipp-missing-job-state"); - ipp_status = IPP_INTERNAL_ERROR; + ipp_status = IPP_STATUS_ERROR_INTERNAL; break; } } @@ -2021,7 +2157,7 @@ main(int argc, /* I - Number of command-line args */ * Wait before polling again... */ - sleep(delay); + sleep((unsigned)delay); delay = _cupsNextDelay(delay, &prev_delay); } @@ -2032,15 +2168,20 @@ main(int argc, /* I - Number of command-line args */ */ if (job_canceled > 0 && job_id > 0) + { cancel_job(http, uri, job_id, resource, argv[2], version); + if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) + _cupsLangPrintFilter(stderr, "ERROR", _("Unable to cancel print job.")); + } + /* * Check the printer state and report it if necessary... */ check_printer_state(http, uri, resource, argv[2], version); - if (cupsLastError() <= IPP_OK_CONFLICT) + if (cupsLastError() <= IPP_STATUS_OK_CONFLICTING) password_tries = 0; /* @@ -2087,9 +2228,9 @@ main(int argc, /* I - Number of command-line args */ * Return the queue status... */ - if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN || - ipp_status == IPP_AUTHENTICATION_CANCELED || - ipp_status <= IPP_OK_CONFLICT) + if (ipp_status == IPP_STATUS_ERROR_NOT_AUTHORIZED || ipp_status == IPP_STATUS_ERROR_FORBIDDEN || + ipp_status == IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED || + ipp_status <= IPP_STATUS_OK_CONFLICTING) fprintf(stderr, "ATTR: auth-info-required=%s\n", auth_info_required); if (ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_INFO_NEEDED) @@ -2101,25 +2242,26 @@ main(int argc, /* I - Number of command-line args */ else if (ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED) fputs("JOBSTATE: account-authorization-failed\n", stderr); - if (ipp_status == IPP_NOT_AUTHORIZED || ipp_status == IPP_FORBIDDEN || - ipp_status == IPP_AUTHENTICATION_CANCELED) + if (job_canceled) + return (CUPS_BACKEND_OK); + else if (ipp_status == IPP_STATUS_ERROR_NOT_AUTHORIZED || ipp_status == IPP_STATUS_ERROR_FORBIDDEN || ipp_status == IPP_STATUS_ERROR_CUPS_AUTHENTICATION_CANCELED) return (CUPS_BACKEND_AUTH_REQUIRED); else if (ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_LIMIT_REACHED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_INFO_NEEDED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_CLOSED || ipp_status == IPP_STATUS_ERROR_CUPS_ACCOUNT_AUTHORIZATION_FAILED) return (CUPS_BACKEND_HOLD); - else if (ipp_status == IPP_INTERNAL_ERROR) + else if (ipp_status == IPP_STATUS_ERROR_INTERNAL) return (CUPS_BACKEND_STOP); - else if (ipp_status == IPP_CONFLICT) + else if (ipp_status == IPP_STATUS_ERROR_CONFLICTING || ipp_status == IPP_STATUS_ERROR_REQUEST_ENTITY || ipp_status == IPP_STATUS_ERROR_REQUEST_VALUE) return (CUPS_BACKEND_FAILED); - else if (ipp_status == IPP_REQUEST_VALUE || + else if (ipp_status == IPP_STATUS_ERROR_REQUEST_VALUE || ipp_status == IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES || - ipp_status == IPP_DOCUMENT_FORMAT || job_canceled < 0) + ipp_status == IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED || job_canceled < 0) { - if (ipp_status == IPP_REQUEST_VALUE) + if (ipp_status == IPP_STATUS_ERROR_REQUEST_VALUE) _cupsLangPrintFilter(stderr, "ERROR", _("Print job too large.")); - else if (ipp_status == IPP_DOCUMENT_FORMAT) + else if (ipp_status == IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED) _cupsLangPrintFilter(stderr, "ERROR", _("Printer cannot print supplied content.")); else if (ipp_status == IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES) @@ -2130,7 +2272,7 @@ main(int argc, /* I - Number of command-line args */ return (CUPS_BACKEND_CANCEL); } - else if (ipp_status > IPP_OK_CONFLICT && ipp_status != IPP_ERROR_JOB_CANCELED) + else if (ipp_status > IPP_STATUS_OK_CONFLICTING && ipp_status != IPP_STATUS_ERROR_JOB_CANCELED) return (CUPS_BACKEND_RETRY_CURRENT); else return (CUPS_BACKEND_OK); @@ -2154,9 +2296,8 @@ cancel_job(http_t *http, /* I - HTTP connection */ _cupsLangPrintFilter(stderr, "INFO", _("Canceling print job.")); - request = ippNewRequest(IPP_CANCEL_JOB); - request->request.op.version[0] = version / 10; - request->request.op.version[1] = version % 10; + request = ippNewRequest(IPP_OP_CANCEL_JOB); + ippSetVersion(request, version / 10, version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -2171,9 +2312,6 @@ cancel_job(http_t *http, /* I - HTTP connection */ */ ippDelete(cupsDoRequest(http, request, resource)); - - if (cupsLastError() > IPP_OK_CONFLICT) - _cupsLangPrintFilter(stderr, "ERROR", _("Unable to cancel print job.")); } @@ -2192,7 +2330,7 @@ check_printer_state( ipp_t *request, /* IPP request */ *response; /* IPP response */ ipp_attribute_t *attr; /* Attribute in response */ - ipp_pstate_t printer_state = IPP_PRINTER_STOPPED; + ipp_pstate_t printer_state = IPP_PSTATE_STOPPED; /* Current printer-state */ @@ -2200,9 +2338,8 @@ check_printer_state( * Send a Get-Printer-Attributes request and log the results... */ - request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); - request->request.op.version[0] = version / 10; - request->request.op.version[1] = version % 10; + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippSetVersion(request, version / 10, version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); @@ -2215,6 +2352,9 @@ check_printer_state( "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); + fprintf(stderr, "DEBUG: IPP/%d.%d %s #%d\n", version / 10, version % 10, ippOpString(ippGetOperation(request)), ippGetRequestId(request)); + debug_attributes(request); + if ((response = cupsDoRequest(http, request, resource)) != NULL) { report_printer_state(response); @@ -2222,12 +2362,12 @@ check_printer_state( if ((attr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) != NULL) printer_state = (ipp_pstate_t)attr->values[0].integer; - - ippDelete(response); } fprintf(stderr, "DEBUG: Get-Printer-Attributes: %s (%s)\n", ippErrorString(cupsLastError()), cupsLastErrorString()); + debug_attributes(response); + ippDelete(response); /* * Return the printer-state value... @@ -2237,6 +2377,51 @@ check_printer_state( } +/* + * 'debug_attributes()' - Print out the request or response attributes as DEBUG + * messages... + */ + +static void +debug_attributes(ipp_t *ipp) /* I - Request or response message */ +{ + ipp_tag_t group; /* Current group */ + ipp_attribute_t *attr; /* Current attribute */ + char buffer[1024]; /* Value buffer */ + + + for (group = IPP_TAG_ZERO, attr = ippFirstAttribute(ipp); + attr; + attr = ippNextAttribute(ipp)) + { + const char *name = ippGetName(attr); + + if (!name) + { + group = IPP_TAG_ZERO; + continue; + } + + if (group != ippGetGroupTag(attr)) + { + group = ippGetGroupTag(attr); + fprintf(stderr, "DEBUG: ---- %s ----\n", ippTagString(group)); + } + + if (!strcmp(name, "job-password")) + strlcpy(buffer, "---", sizeof(buffer)); + else + ippAttributeString(attr, buffer, sizeof(buffer)); + + fprintf(stderr, "DEBUG: %s %s%s %s\n", name, + ippGetCount(attr) > 1 ? "1setOf " : "", + ippTagString(ippGetValueTag(attr)), buffer); + } + + fprintf(stderr, "DEBUG: ---- %s ----\n", ippTagString(IPP_TAG_END)); +} + + /* * 'monitor_printer()' - Monitor the printer state. */ @@ -2279,13 +2464,16 @@ monitor_printer( monitor->job_reasons = 0; - while (monitor->job_state < IPP_JOB_CANCELED && !job_canceled) + while (monitor->job_state < IPP_JSTATE_CANCELED && !job_canceled) { /* - * Reconnect to the printer... + * Reconnect to the printer as needed... */ - if (!httpReconnect(http)) + if (httpGetFd(http) < 0) + httpReconnect2(http, 30000, NULL); + + if (httpGetFd(http) >= 0) { /* * Connected, so check on the printer state... @@ -2295,22 +2483,30 @@ monitor_printer( monitor->resource, monitor->user, monitor->version); - if (cupsLastError() <= IPP_OK_CONFLICT) + if (cupsLastError() <= IPP_STATUS_OK_CONFLICTING) password_tries = 0; + if (monitor->job_id == 0 && monitor->create_job) + { + /* + * No job-id yet, so continue... + */ + + goto monitor_sleep; + } + /* * Check the status of the job itself... */ job_op = (monitor->job_id > 0 && monitor->get_job_attrs) ? - IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS; + IPP_OP_GET_JOB_ATTRIBUTES : IPP_OP_GET_JOBS; request = ippNewRequest(job_op); - request->request.op.version[0] = monitor->version / 10; - request->request.op.version[1] = monitor->version % 10; + ippSetVersion(request, monitor->version / 10, monitor->version % 10); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, monitor->uri); - if (job_op == IPP_GET_JOB_ATTRIBUTES) + if (job_op == IPP_OP_GET_JOB_ATTRIBUTES) ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "job-id", monitor->job_id); @@ -2331,16 +2527,16 @@ monitor_printer( fprintf(stderr, "DEBUG: (monitor) %s: %s (%s)\n", ippOpString(job_op), ippErrorString(cupsLastError()), cupsLastErrorString()); - if (cupsLastError() <= IPP_OK_CONFLICT) + if (cupsLastError() <= IPP_STATUS_OK_CONFLICTING) password_tries = 0; - if (job_op == IPP_GET_JOB_ATTRIBUTES) + if (job_op == IPP_OP_GET_JOB_ATTRIBUTES) { if ((attr = ippFindAttribute(response, "job-state", IPP_TAG_ENUM)) != NULL) monitor->job_state = (ipp_jstate_t)attr->values[0].integer; else - monitor->job_state = IPP_JOB_COMPLETED; + monitor->job_state = IPP_JSTATE_COMPLETED; } else if (response) { @@ -2348,7 +2544,7 @@ monitor_printer( { job_id = 0; job_name = NULL; - job_state = IPP_JOB_PENDING; + job_state = IPP_JSTATE_PENDING; job_user = NULL; while (attr && attr->group_tag != IPP_TAG_JOB) @@ -2368,7 +2564,7 @@ monitor_printer( job_name = attr->values[0].string.text; else if (!strcmp(attr->name, "job-state") && attr->value_tag == IPP_TAG_ENUM) - job_state = attr->values[0].integer; + job_state = (ipp_jstate_t)attr->values[0].integer; else if (!strcmp(attr->name, "job-originating-user-name") && (attr->value_tag == IPP_TAG_NAME || attr->value_tag == IPP_TAG_NAMELANG)) @@ -2390,6 +2586,16 @@ monitor_printer( } } + fprintf(stderr, "DEBUG: (monitor) job-state = %s\n", ippEnumString("job-state", (int)monitor->job_state)); + + if (!job_canceled && + (monitor->job_state == IPP_JSTATE_CANCELED || + monitor->job_state == IPP_JSTATE_ABORTED)) + { + job_canceled = -1; + fprintf(stderr, "DEBUG: (monitor) job_canceled = -1\n"); + } + if ((attr = ippFindAttribute(response, "job-state-reasons", IPP_TAG_KEYWORD)) != NULL) { @@ -2397,20 +2603,25 @@ monitor_printer( for (i = 0; i < attr->num_values; i ++) { - if (!strcmp(attr->values[i].string.text, - "account-authorization-failed")) + if (!strcmp(attr->values[i].string.text, "account-authorization-failed")) new_reasons |= _CUPS_JSR_ACCOUNT_AUTHORIZATION_FAILED; else if (!strcmp(attr->values[i].string.text, "account-closed")) new_reasons |= _CUPS_JSR_ACCOUNT_CLOSED; else if (!strcmp(attr->values[i].string.text, "account-info-needed")) new_reasons |= _CUPS_JSR_ACCOUNT_INFO_NEEDED; - else if (!strcmp(attr->values[i].string.text, - "account-limit-reached")) + else if (!strcmp(attr->values[i].string.text, "account-limit-reached")) new_reasons |= _CUPS_JSR_ACCOUNT_LIMIT_REACHED; else if (!strcmp(attr->values[i].string.text, "job-password-wait")) new_reasons |= _CUPS_JSR_JOB_PASSWORD_WAIT; else if (!strcmp(attr->values[i].string.text, "job-release-wait")) new_reasons |= _CUPS_JSR_JOB_RELEASE_WAIT; + else if (!strcmp(attr->values[i].string.text, "document-format-error")) + new_reasons |= _CUPS_JSR_DOCUMENT_FORMAT_ERROR; + else if (!strcmp(attr->values[i].string.text, "document-unprintable")) + new_reasons |= _CUPS_JSR_DOCUMENT_UNPRINTABLE; + + if (!job_canceled && (!strncmp(attr->values[i].string.text, "job-canceled-", 13) || !strcmp(attr->values[i].string.text, "aborted-by-system"))) + job_canceled = 1; } if (new_reasons != monitor->job_reasons) @@ -2427,6 +2638,26 @@ monitor_printer( fputs("JOBSTATE: job-password-wait\n", stderr); else if (new_reasons & _CUPS_JSR_JOB_RELEASE_WAIT) fputs("JOBSTATE: job-release-wait\n", stderr); + else if (new_reasons & (_CUPS_JSR_DOCUMENT_FORMAT_ERROR | _CUPS_JSR_DOCUMENT_UNPRINTABLE)) + { + if (monitor->retryable) + { + /* + * Can't print this, so retry as raster... + */ + + job_canceled = 1; + fputs("JOBSTATE: cups-retry-as-raster\n", stderr); + } + else if (new_reasons & _CUPS_JSR_DOCUMENT_FORMAT_ERROR) + { + fputs("JOBSTATE: document-format-error\n", stderr); + } + else + { + fputs("JOBSTATE: document-unprintable\n", stderr); + } + } else fputs("JOBSTATE: job-printing\n", stderr); @@ -2436,26 +2667,21 @@ monitor_printer( ippDelete(response); - fprintf(stderr, "DEBUG: (monitor) job-state=%s\n", - ippEnumString("job-state", monitor->job_state)); + fprintf(stderr, "DEBUG: (monitor) job-state = %s\n", ippEnumString("job-state", (int)monitor->job_state)); if (!job_canceled && - (monitor->job_state == IPP_JOB_CANCELED || - monitor->job_state == IPP_JOB_ABORTED)) + (monitor->job_state == IPP_JSTATE_CANCELED || + monitor->job_state == IPP_JSTATE_ABORTED)) job_canceled = -1; - - /* - * Disconnect from the printer - we'll reconnect on the next poll... - */ - - _httpDisconnect(http); } /* * Sleep for N seconds... */ - sleep(delay); + monitor_sleep: + + sleep((unsigned)delay); delay = _cupsNextDelay(delay, &prev_delay); } @@ -2465,10 +2691,23 @@ monitor_printer( */ if (job_canceled > 0 && monitor->job_id > 0) - if (!httpReconnect(http)) + { + if (httpGetFd(http) < 0) + httpReconnect2(http, 30000, NULL); + + if (httpGetFd(http) >= 0) + { cancel_job(http, monitor->uri, monitor->job_id, monitor->resource, monitor->user, monitor->version); + if (cupsLastError() > IPP_STATUS_OK_CONFLICTING) + { + fprintf(stderr, "DEBUG: (monitor) cancel_job() = %s\n", cupsLastErrorString()); + _cupsLangPrintFilter(stderr, "ERROR", _("Unable to cancel print job.")); + } + } + } + /* * Cleanup and return... */ @@ -2499,31 +2738,19 @@ new_request( ppd_file_t *ppd, /* I - PPD file data */ ipp_attribute_t *media_col_sup, /* I - media-col-supported values */ ipp_attribute_t *doc_handling_sup, /* I - multiple-document-handling-supported values */ - int print_color_mode) /* I - Printer supports print-color-mode */ + ipp_attribute_t *print_color_mode_sup) + /* I - Printer supports print-color-mode */ { - int i; /* Looping var */ ipp_t *request; /* Request data */ const char *keyword; /* PWG keyword */ - _pwg_size_t *size; /* PWG media size */ - ipp_t *media_col, /* media-col value */ - *media_size; /* media-size value */ - const char *media_source, /* media-source value */ - *media_type, /* media-type value */ - *collate_str, /* multiple-document-handling value */ - *mandatory; /* Mandatory attributes */ - ipp_tag_t group; /* Current group */ - ipp_attribute_t *attr; /* Current attribute */ - const char *color_attr_name; /* Supported color attribute */ - char buffer[1024]; /* Value buffer */ /* * Create the IPP request... */ - request = ippNewRequest(op); - request->request.op.version[0] = version / 10; - request->request.op.version[1] = version % 10; + request = ippNewRequest(op); + ippSetVersion(request, version / 10, version % 10); fprintf(stderr, "DEBUG: %s IPP/%d.%d\n", ippOpString(request->request.op.operation_id), @@ -2534,36 +2761,31 @@ new_request( * Add standard attributes... */ - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", - NULL, uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); fprintf(stderr, "DEBUG: printer-uri=\"%s\"\n", uri); if (user && *user) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, - "requesting-user-name", NULL, user); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, user); fprintf(stderr, "DEBUG: requesting-user-name=\"%s\"\n", user); } if (title && *title) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, - title); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL, title); fprintf(stderr, "DEBUG: job-name=\"%s\"\n", title); } - if (format && op != IPP_CREATE_JOB) + if (format && op != IPP_OP_CREATE_JOB) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, - "document-format", NULL, format); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, format); fprintf(stderr, "DEBUG: document-format=\"%s\"\n", format); } #ifdef HAVE_LIBZ if (compression && op != IPP_OP_CREATE_JOB && op != IPP_OP_VALIDATE_JOB) { - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "compression", NULL, compression); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "compression", NULL, compression); fprintf(stderr, "DEBUG: compression=\"%s\"\n", compression); } #endif /* HAVE_LIBZ */ @@ -2576,287 +2798,13 @@ new_request( { if (pc) { - int num_finishings = 0, /* Number of finishing values */ - finishings[10]; /* Finishing enum values */ - ppd_choice_t *choice; /* Marked choice */ - /* * Send standard IPP attributes... */ fputs("DEBUG: Adding standard IPP operation/job attributes.\n", stderr); - if (pc->password && - (keyword = cupsGetOption("job-password", num_options, - options)) != NULL) - { - ippAddOctetString(request, IPP_TAG_OPERATION, "job-password", - keyword, strlen(keyword)); - - if ((keyword = cupsGetOption("job-password-encryption", num_options, - options)) == NULL) - keyword = "none"; - - ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, - "job-password-encryption", NULL, keyword); - } - - if (pc->account_id && - (keyword = cupsGetOption("job-account-id", num_options, - options)) != NULL) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, "job-account-id", - NULL, keyword); - - if (pc->accounting_user_id && - (keyword = cupsGetOption("job-accounting-user-id", num_options, - options)) != NULL) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_NAME, - "job-accounting-user-id", NULL, keyword); - - for (mandatory = (char *)cupsArrayFirst(pc->mandatory); - mandatory; - mandatory = (char *)cupsArrayNext(pc->mandatory)) - { - if (strcmp(mandatory, "copies") && - strcmp(mandatory, "destination-uris") && - strcmp(mandatory, "finishings") && - strcmp(mandatory, "job-account-id") && - strcmp(mandatory, "job-accounting-user-id") && - strcmp(mandatory, "job-password") && - strcmp(mandatory, "job-password-encryption") && - strcmp(mandatory, "media") && - strncmp(mandatory, "media-col", 9) && - strcmp(mandatory, "multiple-document-handling") && - strcmp(mandatory, "output-bin") && - strcmp(mandatory, "print-color-mode") && - strcmp(mandatory, "print-quality") && - strcmp(mandatory, "sides") && - (keyword = cupsGetOption(mandatory, num_options, options)) != NULL) - { - _ipp_option_t *opt = _ippFindOption(mandatory); - /* Option type */ - ipp_tag_t value_tag = opt ? opt->value_tag : IPP_TAG_NAME; - /* Value type */ - - switch (value_tag) - { - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - ippAddInteger(request, IPP_TAG_JOB, value_tag, mandatory, - atoi(keyword)); - break; - case IPP_TAG_BOOLEAN : - ippAddBoolean(request, IPP_TAG_JOB, mandatory, - !_cups_strcasecmp(keyword, "true")); - break; - case IPP_TAG_RANGE : - { - int lower, upper; /* Range */ - - if (sscanf(keyword, "%d-%d", &lower, &upper) != 2) - lower = upper = atoi(keyword); - - ippAddRange(request, IPP_TAG_JOB, mandatory, lower, upper); - } - break; - case IPP_TAG_STRING : - ippAddOctetString(request, IPP_TAG_JOB, mandatory, keyword, - strlen(keyword)); - break; - default : - ippAddString(request, IPP_TAG_JOB, value_tag, mandatory, - NULL, keyword); - break; - } - } - } - - if ((keyword = cupsGetOption("PageSize", num_options, options)) == NULL) - keyword = cupsGetOption("media", num_options, options); - - if ((size = _ppdCacheGetSize(pc, keyword)) != NULL) - { - /* - * Add a media-col value... - */ - - media_size = ippNew(); - ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "x-dimension", size->width); - ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "y-dimension", size->length); - - media_col = ippNew(); - ippAddCollection(media_col, IPP_TAG_ZERO, "media-size", media_size); - - media_source = _ppdCacheGetSource(pc, cupsGetOption("InputSlot", - num_options, - options)); - media_type = _ppdCacheGetType(pc, cupsGetOption("MediaType", - num_options, - options)); - - for (i = 0; i < media_col_sup->num_values; i ++) - { - if (!strcmp(media_col_sup->values[i].string.text, - "media-left-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-left-margin", size->left); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-bottom-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-bottom-margin", size->bottom); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-right-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-right-margin", size->right); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-top-margin")) - ippAddInteger(media_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, - "media-top-margin", size->top); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-source") && media_source) - ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, - "media-source", NULL, media_source); - else if (!strcmp(media_col_sup->values[i].string.text, - "media-type") && media_type) - ippAddString(media_col, IPP_TAG_ZERO, IPP_TAG_KEYWORD, - "media-type", NULL, media_type); - } - - ippAddCollection(request, IPP_TAG_JOB, "media-col", media_col); - } - - if ((keyword = cupsGetOption("output-bin", num_options, - options)) == NULL) - { - if ((choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL) - keyword = _ppdCacheGetBin(pc, choice->choice); - } - - if (keyword) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "output-bin", - NULL, keyword); - - color_attr_name = print_color_mode ? "print-color-mode" : "output-mode"; - - if ((keyword = cupsGetOption("print-color-mode", num_options, - options)) != NULL) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, color_attr_name, - NULL, keyword); - else if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL) - { - if (!_cups_strcasecmp(choice->choice, "Gray")) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, - color_attr_name, NULL, "monochrome"); - else - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, - color_attr_name, NULL, "color"); - } - - if ((keyword = cupsGetOption("print-quality", num_options, - options)) != NULL) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - atoi(keyword)); - else if ((choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality")) != NULL) - { - if (!_cups_strcasecmp(choice->choice, "draft")) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - IPP_QUALITY_DRAFT); - else if (!_cups_strcasecmp(choice->choice, "normal")) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - IPP_QUALITY_NORMAL); - else if (!_cups_strcasecmp(choice->choice, "high")) - ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_ENUM, "print-quality", - IPP_QUALITY_HIGH); - } - - if ((keyword = cupsGetOption("sides", num_options, options)) != NULL) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, keyword); - else if (pc->sides_option && - (choice = ppdFindMarkedChoice(ppd, pc->sides_option)) != NULL) - { - if (!_cups_strcasecmp(choice->choice, pc->sides_1sided)) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, "one-sided"); - else if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_long)) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, "two-sided-long-edge"); - if (!_cups_strcasecmp(choice->choice, pc->sides_2sided_short)) - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "sides", - NULL, "two-sided-short-edge"); - } - - if ((keyword = cupsGetOption("multiple-document-handling", - num_options, options)) != NULL) - { - if (strstr(keyword, "uncollated")) - keyword = "false"; - else - keyword = "true"; - } - else if ((keyword = cupsGetOption("collate", num_options, - options)) == NULL) - keyword = "true"; - - if (format) - { - if (!_cups_strcasecmp(format, "image/gif") || - !_cups_strcasecmp(format, "image/jp2") || - !_cups_strcasecmp(format, "image/jpeg") || - !_cups_strcasecmp(format, "image/png") || - !_cups_strcasecmp(format, "image/tiff") || - !_cups_strncasecmp(format, "image/x-", 8)) - { - /* - * Collation makes no sense for single page image formats... - */ - - keyword = "false"; - } - else if (!_cups_strncasecmp(format, "image/", 6) || - !_cups_strcasecmp(format, "application/vnd.cups-raster")) - { - /* - * Multi-page image formats will have copies applied by the upstream - * filters... - */ - - copies = 1; - } - } - - if (doc_handling_sup) - { - if (!_cups_strcasecmp(keyword, "true")) - collate_str = "separate-documents-collated-copies"; - else - collate_str = "separate-documents-uncollated-copies"; - - for (i = 0; i < doc_handling_sup->num_values; i ++) - if (!strcmp(doc_handling_sup->values[i].string.text, collate_str)) - { - ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "multiple-document-handling", NULL, collate_str); - break; - } - - if (i >= doc_handling_sup->num_values) - copies = 1; - } - - /* - * Map finishing options... - */ - - num_finishings = _ppdCacheGetFinishingValues(pc, num_options, options, - (int)(sizeof(finishings) / - sizeof(finishings[0])), - finishings); - if (num_finishings > 0) - ippAddIntegers(request, IPP_TAG_JOB, IPP_TAG_ENUM, "finishings", - num_finishings, finishings); + copies = _cupsConvertOptions(request, ppd, pc, media_col_sup, doc_handling_sup, print_color_mode_sup, user, format, copies, num_options, options); /* * Map FaxOut options... @@ -2865,19 +2813,41 @@ new_request( if ((keyword = cupsGetOption("phone", num_options, options)) != NULL) { ipp_t *destination; /* destination collection */ - char tel_uri[1024]; /* tel: URI */ + char phone[1024], /* Phone number string */ + *ptr, /* Pointer into string */ + tel_uri[1024]; /* tel: URI */ + static const char * const allowed = "0123456789#*-+.()pw"; + /* Allowed characters */ destination = ippNew(); - httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel", - NULL, NULL, 0, keyword); - ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri", - NULL, tel_uri); + /* + * Unescape and filter out spaces and other characters that are not + * allowed in a tel: URI. + */ + + _httpDecodeURI(phone, keyword, sizeof(phone)); + for (ptr = phone; *ptr;) + { + if (*ptr == ',') + *ptr = 'p'; + else if (!strchr(allowed, *ptr)) + _cups_strcpy(ptr, ptr + 1); + else + ptr ++; + } + + httpAssembleURI(HTTP_URI_CODING_ALL, tel_uri, sizeof(tel_uri), "tel", NULL, NULL, 0, phone); + ippAddString(destination, IPP_TAG_JOB, IPP_TAG_URI, "destination-uri", NULL, tel_uri); if ((keyword = cupsGetOption("faxPrefix", num_options, options)) != NULL && *keyword) - ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT, - "pre-dial-string", NULL, keyword); + { + char predial[1024]; /* Pre-dial string */ + + _httpDecodeURI(predial, keyword, sizeof(predial)); + ippAddString(destination, IPP_TAG_JOB, IPP_TAG_TEXT, "pre-dial-string", NULL, predial); + } ippAddCollection(request, IPP_TAG_JOB, "destination-uris", destination); ippDelete(destination); @@ -2898,33 +2868,8 @@ new_request( ippAddInteger(request, IPP_TAG_JOB, IPP_TAG_INTEGER, "copies", copies); } - fprintf(stderr, "DEBUG: IPP/%d.%d %s #%d\n", version / 10, version % 10, - ippOpString(ippGetOperation(request)), ippGetRequestId(request)); - for (group = IPP_TAG_ZERO, attr = ippFirstAttribute(request); - attr; - attr = ippNextAttribute(request)) - { - const char *name = ippGetName(attr); - - if (!name) - { - group = IPP_TAG_ZERO; - continue; - } - - if (group != ippGetGroupTag(attr)) - { - group = ippGetGroupTag(attr); - fprintf(stderr, "DEBUG: ---- %s ----\n", ippTagString(group)); - } - - ippAttributeString(attr, buffer, sizeof(buffer)); - fprintf(stderr, "DEBUG: %s %s%s %s\n", name, - ippGetCount(attr) > 1 ? "1setOf " : "", - ippTagString(ippGetValueTag(attr)), buffer); - } - - fprintf(stderr, "DEBUG: ---- %s ----\n", ippTagString(IPP_TAG_END)); + fprintf(stderr, "DEBUG: IPP/%d.%d %s #%d\n", version / 10, version % 10, ippOpString(ippGetOperation(request)), ippGetRequestId(request)); + debug_attributes(request); return (request); } @@ -2953,26 +2898,31 @@ password_cb(const char *prompt, /* I - Prompt (not used) */ (void)method; (void)resource; - /* - * Remember that we need to authenticate... - */ + if (!uri_credentials) + { + /* + * Remember that we need to authenticate... + */ - auth_info_required = "username,password"; + auth_info_required = "username,password"; - if (httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "username", - def_username)) - { - char quoted[HTTP_MAX_VALUE * 2 + 4]; - /* Quoted string */ + if (httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "username", + def_username)) + { + char quoted[HTTP_MAX_VALUE * 2 + 4]; + /* Quoted string */ - fprintf(stderr, "ATTR: auth-info-default=%s,\n", - quote_string(def_username, quoted, sizeof(quoted))); + fprintf(stderr, "ATTR: auth-info-default=%s,\n", + quote_string(def_username, quoted, sizeof(quoted))); + } } if (password && *password && *password_tries < 3) { (*password_tries) ++; + cupsSetUser(username); + return (password); } else @@ -3015,7 +2965,7 @@ quote_string(const char *s, /* I - String */ { if (*s == '\\' || *s == '\"' || *s == '\'') { - if (q < (qend - 3)) + if (qptr < (qend - 4)) { *qptr++ = '\\'; *qptr++ = '\\'; @@ -3064,16 +3014,14 @@ report_attr(ipp_attribute_t *attr) /* I - Attribute */ { case IPP_TAG_INTEGER : case IPP_TAG_ENUM : - snprintf(valptr, sizeof(value) - (valptr - value), "%d", - attr->values[i].integer); + snprintf(valptr, sizeof(value) - (size_t)(valptr - value), "%d", attr->values[i].integer); valptr += strlen(valptr); break; case IPP_TAG_TEXT : case IPP_TAG_NAME : case IPP_TAG_KEYWORD : - quote_string(attr->values[i].string.text, valptr, - value + sizeof(value) - valptr); + quote_string(attr->values[i].string.text, valptr, (size_t)(value + sizeof(value) - valptr)); valptr += strlen(valptr); break; @@ -3115,6 +3063,7 @@ report_printer_state(ipp_t *ipp) /* I - IPP response */ { ipp_attribute_t *pa, /* printer-alert */ *pam, /* printer-alert-message */ + *pmja, /* printer-mandatory-job-attributes */ *psm, /* printer-state-message */ *reasons, /* printer-state-reasons */ *marker; /* marker-* attributes */ @@ -3135,6 +3084,26 @@ report_printer_state(ipp_t *ipp) /* I - IPP response */ IPP_TAG_TEXT)) != NULL) report_attr(pam); + if ((pmja = ippFindAttribute(ipp, "printer-mandatory-job-attributes", IPP_TAG_KEYWORD)) != NULL) + { + int i, /* Looping var */ + count = ippGetCount(pmja); /* Number of values */ + + for (i = 0, valptr = value; i < count; i ++, valptr += strlen(valptr)) + { + if (i) + snprintf(valptr, sizeof(value) - (size_t)(valptr - value), " %s", ippGetString(pmja, i, NULL)); + else + strlcpy(value, ippGetString(pmja, i, NULL), sizeof(value)); + } + + if (strcmp(value, mandatory_attrs)) + { + strlcpy(mandatory_attrs, value, sizeof(mandatory_attrs)); + fprintf(stderr, "PPD: cupsMandatory=\"%s\"\n", value); + } + } + if ((psm = ippFindAttribute(ipp, "printer-state-message", IPP_TAG_TEXT)) != NULL) { @@ -3324,12 +3293,12 @@ run_as_user(char *argv[], /* I - Command-line arguments */ if (response) { - child_pid = xpc_dictionary_get_int64(response, "child-pid"); + child_pid = (pid_t)xpc_dictionary_get_int64(response, "child-pid"); xpc_release(response); if (child_pid) - fprintf(stderr, "DEBUG: Child PID=%d.\n", child_pid); + fprintf(stderr, "DEBUG: Child PID=%d.\n", (int)child_pid); else { _cupsLangPrintFilter(stderr, "ERROR", @@ -3375,7 +3344,7 @@ run_as_user(char *argv[], /* I - Command-line arguments */ if (response) { - status = xpc_dictionary_get_int64(response, "status"); + status = (int)xpc_dictionary_get_int64(response, "status"); if (status == SIGTERM || status == SIGKILL || status == SIGPIPE) { @@ -3403,7 +3372,6 @@ run_as_user(char *argv[], /* I - Command-line arguments */ if (conn) { - xpc_connection_suspend(conn); xpc_connection_cancel(conn); xpc_release(conn); } @@ -3438,7 +3406,7 @@ sigterm_handler(int sig) /* I - Signal */ * Flag that the job should be canceled... */ - write(2, "DEBUG: job_canceled = 1.\n", 25); + write(2, "DEBUG: sigterm_handler: job_canceled = 1.\n", 25); job_canceled = 1; return; @@ -3452,7 +3420,7 @@ sigterm_handler(int sig) /* I - Signal */ if (tmpfilename[0]) unlink(tmpfilename); - exit(1); + _exit(1); } @@ -3575,8 +3543,7 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ temp = (char *)cupsArrayNext(state_reasons)) if (!strncmp(temp, "cups-remote-", 12)) { - snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix, - temp); + snprintf(remptr, sizeof(rem) - (size_t)(remptr - rem), "%s%s", remprefix, temp); remptr += strlen(remptr); remprefix = ","; @@ -3589,8 +3556,7 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ cupsArrayAdd(state_reasons, reason); - snprintf(addptr, sizeof(add) - (addptr - add), "%s%s", addprefix, - reason); + snprintf(addptr, sizeof(add) - (size_t)(addptr - add), "%s%s", addprefix, reason); addptr += strlen(addptr); addprefix = ","; } @@ -3608,8 +3574,7 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ { if (cupsArrayFind(state_reasons, reason)) { - snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix, - reason); + snprintf(remptr, sizeof(rem) - (size_t)(remptr - rem), "%s%s", remprefix, reason); remptr += strlen(remptr); remprefix = ","; @@ -3629,8 +3594,7 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ { if (strncmp(reason, "cups-", 5) && !cupsArrayFind(new_reasons, reason)) { - snprintf(remptr, sizeof(rem) - (remptr - rem), "%s%s", remprefix, - reason); + snprintf(remptr, sizeof(rem) - (size_t)(remptr - rem), "%s%s", remprefix, reason); remptr += strlen(remptr); remprefix = ","; @@ -3646,14 +3610,15 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ { cupsArrayAdd(state_reasons, reason); - snprintf(addptr, sizeof(add) - (addptr - add), "%s%s", addprefix, - reason); + snprintf(addptr, sizeof(add) - (size_t)(addptr - add), "%s%s", addprefix, reason); addptr += strlen(addptr); addprefix = ","; } } } + cupsArrayDelete(new_reasons); + _cupsMutexUnlock(&report_mutex); /* @@ -3667,7 +3632,3 @@ update_reasons(ipp_attribute_t *attr, /* I - printer-state-reasons or NULL */ else if (rem[0]) fprintf(stderr, "%s\n", rem); } - -/* - * End of "$Id: ipp.c 9759 2011-05-11 03:24:33Z mike $". - */