X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fipp.c;h=c771f77f807473124f9d3238a4e5b41002bf1966;hb=72a213482651d42f2fe67dc2689322b2f6a88f0b;hp=0d5e1eacea616ee04be0910443c8ac1b0af62185;hpb=22c9029b44a790ba1ee894027431dcea1ec2aeab;p=thirdparty%2Fcups.git diff --git a/scheduler/ipp.c b/scheduler/ipp.c index 0d5e1eace..c771f77f8 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,109 +1,14 @@ /* - * "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $" + * IPP routines for the CUPS scheduler. * - * IPP routines for the CUPS scheduler. + * Copyright © 2007-2018 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2011 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * This file contains Kerberos support code, copyright 2006 by + * Jelmer Vernooij. * - * This file contains Kerberos support code, copyright 2006 by - * Jelmer Vernooij. - * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * Contents: - * - * cupsdProcessIPPRequest() - Process an incoming IPP request. - * cupsdTimeoutJob() - Timeout a job waiting on job files. - * accept_jobs() - Accept print jobs to a printer. - * add_class() - Add a class to the system. - * add_file() - Add a file to a job. - * add_job() - Add a job to a print queue. - * add_job_state_reasons() - Add the "job-state-reasons" attribute based - * upon the job and printer state... - * add_job_subscriptions() - Add any subscriptions for a job. - * add_job_uuid() - Add job-uuid attribute to a job. - * add_printer() - Add a printer to the system. - * add_printer_state_reasons() - Add the "printer-state-reasons" attribute - * based upon the printer state... - * add_queued_job_count() - Add the "queued-job-count" attribute for the - * specified printer or class. - * apple_init_profile() - Initialize a color profile. - * apple_register_profiles() - Register color profiles for a printer. - * apple_unregister_profiles() - Remove color profiles for the specified - * printer. - * apply_printer_defaults() - Apply printer default options to a job. - * authenticate_job() - Set job authentication info. - * cancel_all_jobs() - Cancel all or selected print jobs. - * cancel_job() - Cancel a print job. - * cancel_subscription() - Cancel a subscription. - * check_rss_recipient() - Check that we do not have a duplicate RSS - * feed URI. - * check_quotas() - Check quotas for a printer and user. - * close_job() - Close a multi-file job. - * copy_attribute() - Copy a single attribute. - * copy_attrs() - Copy attributes from one request to another. - * copy_banner() - Copy a banner file to the requests directory - * for the specified job. - * copy_file() - Copy a PPD file or interface script... - * copy_model() - Copy a PPD model file, substituting default - * values as needed... - * copy_job_attrs() - Copy job attributes. - * copy_printer_attrs() - Copy printer attributes. - * copy_subscription_attrs() - Copy subscription attributes. - * create_job() - Print a file to a printer or class. - * create_requested_array() - Create an array for the requested-attributes. - * create_subscription() - Create a notification subscription. - * delete_printer() - Remove a printer or class from the system. - * get_default() - Get the default destination. - * get_devices() - Get the list of available devices on the - * local system. - * get_document() - Get a copy of a job file. - * get_job_attrs() - Get job attributes. - * get_jobs() - Get a list of jobs for the specified printer. - * get_notifications() - Get events for a subscription. - * get_ppd() - Get a named PPD from the local system. - * get_ppds() - Get the list of PPD files on the local - * system. - * get_printer_attrs() - Get printer attributes. - * get_printer_supported() - Get printer supported values. - * get_printers() - Get a list of printers or classes. - * get_subscription_attrs() - Get subscription attributes. - * get_subscriptions() - Get subscriptions. - * get_username() - Get the username associated with a request. - * hold_job() - Hold a print job. - * hold_new_jobs() - Hold pending/new jobs on a printer or class. - * move_job() - Move a job to a new destination. - * ppd_parse_line() - Parse a PPD default line. - * print_job() - Print a file to a printer or class. - * read_job_ticket() - Read a job ticket embedded in a print file. - * reject_jobs() - Reject print jobs to a printer. - * release_held_new_jobs() - Release pending/new jobs on a printer or - * class. - * release_job() - Release a held print job. - * renew_subscription() - Renew an existing subscription... - * restart_job() - Restart an old print job. - * save_auth_info() - Save authentication information for a job. - * send_document() - Send a file to a printer or class. - * send_http_error() - Send a HTTP error back to the IPP client. - * send_ipp_status() - Send a status back to the IPP client. - * set_default() - Set the default destination... - * set_job_attrs() - Set job attributes. - * set_printer_attrs() - Set printer attributes. - * set_printer_defaults() - Set printer default options from a request. - * start_printer() - Start a printer. - * stop_printer() - Stop a printer. - * url_encode_attr() - URL-encode a string attribute. - * url_encode_string() - URL-encode a string. - * user_allowed() - See if a user is allowed to print to a queue. - * validate_job() - Validate printer options and destination. - * validate_name() - Make sure the printer name only contains - * valid chars. - * validate_user() - Validate the user for the request. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -114,11 +19,9 @@ #include #ifdef __APPLE__ -# include -# ifdef HAVE_COLORSYNCREGISTERDEVICE +/*# include extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ -# include +# include */ # ifdef HAVE_MEMBERSHIP_H # include # endif /* HAVE_MEMBERSHIP_H */ @@ -142,25 +45,12 @@ static int add_file(cupsd_client_t *con, cupsd_job_t *job, mime_type_t *filetype, int compression); static cupsd_job_t *add_job(cupsd_client_t *con, cupsd_printer_t *printer, mime_type_t *filetype); -static void add_job_state_reasons(cupsd_client_t *con, cupsd_job_t *job); static void add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job); -static void add_job_uuid(cupsd_client_t *con, cupsd_job_t *job); +static void add_job_uuid(cupsd_job_t *job); static void add_printer(cupsd_client_t *con, ipp_attribute_t *uri); static void add_printer_state_reasons(cupsd_client_t *con, cupsd_printer_t *p); static void add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p); -#ifdef __APPLE__ -static void apple_init_profile(ppd_file_t *ppd, cups_array_t *languages, -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFMutableDictionaryRef profile, -# else - CMDeviceProfileInfo *profile, -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - unsigned id, const char *name, - const char *text, const char *iccfile); -static void apple_register_profiles(cupsd_printer_t *p); -static void apple_unregister_profiles(cupsd_printer_t *p); -#endif /* __APPLE__ */ static void apply_printer_defaults(cupsd_printer_t *printer, cupsd_job_t *job); static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri); @@ -169,15 +59,13 @@ static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri); static void cancel_subscription(cupsd_client_t *con, int id); static int check_rss_recipient(const char *recipient); static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p); -static ipp_attribute_t *copy_attribute(ipp_t *to, ipp_attribute_t *attr, - int quickcopy); static void close_job(cupsd_client_t *con, ipp_attribute_t *uri); static void copy_attrs(ipp_t *to, ipp_t *from, cups_array_t *ra, ipp_tag_t group, int quickcopy, cups_array_t *exclude); static int copy_banner(cupsd_client_t *con, cupsd_job_t *job, const char *name); -static int copy_file(const char *from, const char *to); +static int copy_file(const char *from, const char *to, mode_t mode); static int copy_model(cupsd_client_t *con, const char *from, const char *to); static void copy_job_attrs(cupsd_client_t *con, @@ -191,8 +79,9 @@ static void copy_subscription_attrs(cupsd_client_t *con, cups_array_t *ra, cups_array_t *exclude); static void create_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void create_local_printer(cupsd_client_t *con); static cups_array_t *create_requested_array(ipp_t *request); -static void create_subscription(cupsd_client_t *con, ipp_attribute_t *uri); +static void create_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri); static void delete_printer(cupsd_client_t *con, ipp_attribute_t *uri); static void get_default(cupsd_client_t *con); static void get_devices(cupsd_client_t *con); @@ -226,28 +115,19 @@ static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job, static void send_document(cupsd_client_t *con, ipp_attribute_t *uri); static void send_http_error(cupsd_client_t *con, http_status_t status, cupsd_printer_t *printer); -static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, - const char *message, ...) -# ifdef __GNUC__ -__attribute__ ((__format__ (__printf__, 3, 4))) -# endif /* __GNUC__ */ -; +static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4); static void set_default(cupsd_client_t *con, ipp_attribute_t *uri); static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri); static void set_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri); -static void set_printer_defaults(cupsd_client_t *con, - cupsd_printer_t *printer); +static int set_printer_defaults(cupsd_client_t *con, cupsd_printer_t *printer); static void start_printer(cupsd_client_t *con, ipp_attribute_t *uri); static void stop_printer(cupsd_client_t *con, ipp_attribute_t *uri); -static void url_encode_attr(ipp_attribute_t *attr, char *buffer, - int bufsize); -static char *url_encode_string(const char *s, char *buffer, int bufsize); +static void url_encode_attr(ipp_attribute_t *attr, char *buffer, size_t bufsize); +static char *url_encode_string(const char *s, char *buffer, size_t bufsize); static int user_allowed(cupsd_printer_t *p, const char *username); static void validate_job(cupsd_client_t *con, ipp_attribute_t *uri); static int validate_name(const char *name); -static int validate_user(cupsd_job_t *job, cupsd_client_t *con, - const char *owner, char *username, - int userlen); +static int validate_user(cupsd_job_t *job, cupsd_client_t *con, const char *owner, char *username, size_t userlen); /* @@ -265,11 +145,33 @@ cupsdProcessIPPRequest( ipp_attribute_t *uri = NULL; /* Printer or job URI attribute */ ipp_attribute_t *username; /* requesting-user-name attr */ int sub_id; /* Subscription ID */ + int valid = 1; /* Valid request? */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdProcessIPPRequest(%p[%d]): operation_id = %04x", - con, con->http.fd, con->request->request.op.operation_id); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id=%04x(%s)", con, con->number, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id)); + + if (LogLevel >= CUPSD_LOG_DEBUG2) + { + for (group = IPP_TAG_ZERO, attr = ippFirstAttribute(con->request); attr; attr = ippNextAttribute(con->request)) + { + const char *name; /* Attribute name */ + char value[1024]; /* Attribute value */ + + if (group != ippGetGroupTag(attr)) + { + group = ippGetGroupTag(attr); + if (group != IPP_TAG_ZERO) + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s", ippTagString(group)); + } + + if ((name = ippGetName(attr)) == NULL) + continue; + + ippAttributeString(attr, value, sizeof(value)); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest: %s %s%s '%s'", name, ippGetCount(attr) > 1 ? "1setOf " : "", ippTagString(ippGetValueTag(attr)), value); + } + } /* * First build an empty response message for this request... @@ -277,34 +179,23 @@ cupsdProcessIPPRequest( con->response = ippNew(); - con->response->request.status.version[0] = - con->request->request.op.version[0]; - con->response->request.status.version[1] = - con->request->request.op.version[1]; - con->response->request.status.request_id = - con->request->request.op.request_id; + con->response->request.status.version[0] = con->request->request.op.version[0]; + con->response->request.status.version[1] = con->request->request.op.version[1]; + con->response->request.status.request_id = con->request->request.op.request_id; /* * Then validate the request header and required attributes... */ - if (con->request->request.any.version[0] != 1 && - con->request->request.any.version[0] != 2) + if (con->request->request.any.version[0] != 1 && con->request->request.any.version[0] != 2) { /* * Return an error, since we only support IPP 1.x and 2.x. */ - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Bad request version number %d.%d", - IPP_VERSION_NOT_SUPPORTED, con->http.hostname, - con->request->request.any.version[0], - con->request->request.any.version[1]); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request version number %d.%d.", IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, con->http->hostname, con->request->request.any.version[0], con->request->request.any.version[1]); - send_ipp_status(con, IPP_VERSION_NOT_SUPPORTED, - _("Bad request version number %d.%d."), - con->request->request.any.version[0], - con->request->request.any.version[1]); + send_ipp_status(con, IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED, _("Bad request version number %d.%d."), con->request->request.any.version[0], con->request->request.any.version[1]); } else if (con->request->request.any.request_id < 1) { @@ -312,21 +203,15 @@ cupsdProcessIPPRequest( * Return an error, since request IDs must be between 1 and 2^31-1 */ - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Bad request ID %d", - IPP_BAD_REQUEST, con->http.hostname, - con->request->request.any.request_id); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request ID %d.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname, con->request->request.any.request_id); - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad request ID %d."), - con->request->request.any.request_id); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Bad request ID %d."), con->request->request.any.request_id); } else if (!con->request->attrs) { - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s No attributes in request", - IPP_BAD_REQUEST, con->http.hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s No attributes in request.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); - send_ipp_status(con, IPP_BAD_REQUEST, _("No attributes in request.")); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("No attributes in request.")); } else { @@ -344,13 +229,9 @@ cupsdProcessIPPRequest( * Out of order; return an error... */ - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Attribute groups are out of order", - IPP_BAD_REQUEST, con->http.hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Attribute groups are out of order", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); - send_ipp_status(con, IPP_BAD_REQUEST, - _("Attribute groups are out of order (%x < %x)."), - attr->group_tag, group); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute groups are out of order (%x < %x)."), attr->group_tag, group); break; } else @@ -367,9 +248,7 @@ cupsdProcessIPPRequest( */ attr = con->request->attrs; - if (attr && attr->name && - !strcmp(attr->name, "attributes-charset") && - (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET) + if (attr && attr->name && !strcmp(attr->name, "attributes-charset") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET && attr->group_tag == IPP_TAG_OPERATION) charset = attr; else charset = NULL; @@ -377,43 +256,44 @@ cupsdProcessIPPRequest( if (attr) attr = attr->next; - if (attr && attr->name && - !strcmp(attr->name, "attributes-natural-language") && - (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE) + if (attr && attr->name && !strcmp(attr->name, "attributes-natural-language") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE && attr->group_tag == IPP_TAG_OPERATION) + { language = attr; + + /* + * Reset language for this request if different from Accept-Language. + */ + + if (!con->language || + strcmp(attr->values[0].string.text, con->language->language)) + { + cupsLangFree(con->language); + con->language = cupsLangGet(attr->values[0].string.text); + } + } else language = NULL; - if ((attr = ippFindAttribute(con->request, "printer-uri", - IPP_TAG_URI)) != NULL) + if ((attr = ippFindAttribute(con->request, "printer-uri", IPP_TAG_URI)) != NULL && attr->group_tag == IPP_TAG_OPERATION) uri = attr; - else if ((attr = ippFindAttribute(con->request, "job-uri", - IPP_TAG_URI)) != NULL) + else if ((attr = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI)) != NULL && attr->group_tag == IPP_TAG_OPERATION) uri = attr; - else if (con->request->request.op.operation_id == CUPS_GET_PPD) - uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME); + else if (con->request->request.op.operation_id == CUPS_GET_PPD && (attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL && attr->group_tag == IPP_TAG_OPERATION) + uri = attr; else uri = NULL; if (charset) - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, - charset->values[0].string.text); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, charset->values[0].string.text); else - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, "utf-8"); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8"); if (language) - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, - "attributes-natural-language", NULL, - language->values[0].string.text); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->values[0].string.text); else - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, - "attributes-natural-language", NULL, DefaultLanguage); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, DefaultLanguage); - if (charset && - strcasecmp(charset->values[0].string.text, "us-ascii") && - strcasecmp(charset->values[0].string.text, "utf-8")) + if (charset && _cups_strcasecmp(charset->values[0].string.text, "us-ascii") && _cups_strcasecmp(charset->values[0].string.text, "utf-8")) { /* * Bad character set... @@ -421,13 +301,8 @@ cupsdProcessIPPRequest( cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported character set \"%s\"", charset->values[0].string.text); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Unsupported attributes-charset value \"%s\"", - IPP_CHARSET, con->http.hostname, - charset->values[0].string.text); - send_ipp_status(con, IPP_BAD_REQUEST, - _("Unsupported character set \"%s\"."), - charset->values[0].string.text); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Unsupported attributes-charset value \"%s\".", IPP_STATUS_ERROR_CHARSET, con->http->hostname, charset->values[0].string.text); + send_ipp_status(con, IPP_STATUS_ERROR_CHARSET, _("Unsupported character set \"%s\"."), charset->values[0].string.text); } else if (!charset || !language || (!uri && @@ -445,33 +320,24 @@ cupsdProcessIPPRequest( if (!charset) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing attributes-charset attribute"); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing attributes-charset attribute."); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Missing attributes-charset attribute", - IPP_BAD_REQUEST, con->http.hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-charset attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); } if (!language) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing attributes-natural-language attribute"); + "Missing attributes-natural-language attribute."); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Missing attributes-natural-language attribute", - IPP_BAD_REQUEST, con->http.hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-natural-language attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); } if (!uri) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing printer-uri, job-uri, or ppd-name " - "attribute"); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing printer-uri, job-uri, or ppd-name attribute."); - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Missing printer-uri, job-uri, or ppd-name " - "attribute", IPP_BAD_REQUEST, con->http.hostname); + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing printer-uri, job-uri, or ppd-name attribute.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); } cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow..."); @@ -490,235 +356,265 @@ cupsdProcessIPPRequest( else { /* - * OK, all the checks pass so far; make sure requesting-user-name is - * not "root" from a remote host... + * OK, all the checks pass so far; validate "requesting-user-name" + * attribute value... */ - if ((username = ippFindAttribute(con->request, "requesting-user-name", - IPP_TAG_NAME)) != NULL) - { - /* - * Check for root user... - */ + if ((username = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_ZERO)) != NULL) + { + /* + * Validate "requesting-user-name"... + */ + + if (username->group_tag != IPP_TAG_OPERATION && StrictConformance) + { + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute in wrong group.", IPP_STATUS_ERROR_BAD_REQUEST, con->http->hostname); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("\"requesting-user-name\" attribute in wrong group.")); + valid = 0; + } + else if (username->value_tag != IPP_TAG_NAME && username->value_tag != IPP_TAG_NAMELANG) + { + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with wrong syntax.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname); + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax.")); + if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + valid = 0; + } + else if (!ippValidateAttribute(username)) + { + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s \"requesting-user-name\" attribute with bad value.", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, con->http->hostname); + + if (StrictConformance) + { + /* + * Throw an error... + */ + + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("\"requesting-user-name\" attribute with wrong syntax.")); + if ((attr = ippCopyAttribute(con->response, username, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + valid = 0; + } + else + { + /* + * Map bad "requesting-user-name" to 'anonymous'... + */ - if (!strcmp(username->values[0].string.text, "root") && - strcasecmp(con->http.hostname, "localhost") && - strcmp(con->username, "root")) + ippSetString(con->request, &username, 0, "anonymous"); + } + } + else if (!strcmp(username->values[0].string.text, "root") && _cups_strcasecmp(con->http->hostname, "localhost") && strcmp(con->username, "root")) { /* * Remote unauthenticated user masquerading as local root... */ - _cupsStrFree(username->values[0].string.text); - username->values[0].string.text = _cupsStrAlloc(RemoteRoot); + ippSetString(con->request, &username, 0, RemoteRoot); } } - if ((attr = ippFindAttribute(con->request, "notify-subscription-id", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(con->request, "notify-subscription-id", IPP_TAG_INTEGER)) != NULL) sub_id = attr->values[0].integer; else sub_id = 0; - /* - * Then try processing the operation... - */ - - if (uri) - cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s", - ippOpString(con->request->request.op.operation_id), - uri->values[0].string.text); - else - cupsdLogMessage(CUPSD_LOG_DEBUG, "%s", - ippOpString(con->request->request.op.operation_id)); - - switch (con->request->request.op.operation_id) - { - case IPP_PRINT_JOB : - print_job(con, uri); - break; - - case IPP_VALIDATE_JOB : - validate_job(con, uri); - break; - - case IPP_CREATE_JOB : - create_job(con, uri); - break; - - case IPP_SEND_DOCUMENT : - send_document(con, uri); - break; - - case IPP_CANCEL_JOB : - cancel_job(con, uri); - break; - - case IPP_GET_JOB_ATTRIBUTES : - get_job_attrs(con, uri); - break; - - case IPP_GET_JOBS : - get_jobs(con, uri); - break; - - case IPP_GET_PRINTER_ATTRIBUTES : - get_printer_attrs(con, uri); - break; - - case IPP_GET_PRINTER_SUPPORTED_VALUES : - get_printer_supported(con, uri); - break; - - case IPP_HOLD_JOB : - hold_job(con, uri); - break; - - case IPP_RELEASE_JOB : - release_job(con, uri); - break; - - case IPP_RESTART_JOB : - restart_job(con, uri); - break; - - case IPP_PAUSE_PRINTER : - stop_printer(con, uri); - break; - - case IPP_RESUME_PRINTER : - start_printer(con, uri); - break; - - case IPP_PURGE_JOBS : - case IPP_CANCEL_JOBS : - case IPP_CANCEL_MY_JOBS : - cancel_all_jobs(con, uri); - break; - - case IPP_SET_JOB_ATTRIBUTES : - set_job_attrs(con, uri); - break; - - case IPP_SET_PRINTER_ATTRIBUTES : - set_printer_attrs(con, uri); - break; - - case IPP_HOLD_NEW_JOBS : - hold_new_jobs(con, uri); - break; - - case IPP_RELEASE_HELD_NEW_JOBS : - release_held_new_jobs(con, uri); - break; - - case IPP_CLOSE_JOB : - close_job(con, uri); - break; - - case CUPS_GET_DEFAULT : - get_default(con); - break; - - case CUPS_GET_PRINTERS : - get_printers(con, 0); - break; - - case CUPS_GET_CLASSES : - get_printers(con, CUPS_PRINTER_CLASS); - break; - - case CUPS_ADD_PRINTER : - add_printer(con, uri); - break; - - case CUPS_DELETE_PRINTER : - delete_printer(con, uri); - break; - - case CUPS_ADD_CLASS : - add_class(con, uri); - break; - - case CUPS_DELETE_CLASS : - delete_printer(con, uri); - break; + if (valid) + { + /* + * Try processing the operation... + */ - case CUPS_ACCEPT_JOBS : - case IPP_ENABLE_PRINTER : - accept_jobs(con, uri); - break; + if (uri) + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s %s", ippOpString(con->request->request.op.operation_id), uri->values[0].string.text); + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s", ippOpString(con->request->request.op.operation_id)); - case CUPS_REJECT_JOBS : - case IPP_DISABLE_PRINTER : - reject_jobs(con, uri); - break; + switch (con->request->request.op.operation_id) + { + case IPP_OP_PRINT_JOB : + print_job(con, uri); + break; + + case IPP_OP_VALIDATE_JOB : + validate_job(con, uri); + break; + + case IPP_OP_CREATE_JOB : + create_job(con, uri); + break; + + case IPP_OP_SEND_DOCUMENT : + send_document(con, uri); + break; + + case IPP_OP_CANCEL_JOB : + cancel_job(con, uri); + break; + + case IPP_OP_GET_JOB_ATTRIBUTES : + get_job_attrs(con, uri); + break; + + case IPP_OP_GET_JOBS : + get_jobs(con, uri); + break; + + case IPP_OP_GET_PRINTER_ATTRIBUTES : + get_printer_attrs(con, uri); + break; + + case IPP_OP_GET_PRINTER_SUPPORTED_VALUES : + get_printer_supported(con, uri); + break; + + case IPP_OP_HOLD_JOB : + hold_job(con, uri); + break; + + case IPP_OP_RELEASE_JOB : + release_job(con, uri); + break; + + case IPP_OP_RESTART_JOB : + restart_job(con, uri); + break; + + case IPP_OP_PAUSE_PRINTER : + stop_printer(con, uri); + break; + + case IPP_OP_RESUME_PRINTER : + start_printer(con, uri); + break; + + case IPP_OP_PURGE_JOBS : + case IPP_OP_CANCEL_JOBS : + case IPP_OP_CANCEL_MY_JOBS : + cancel_all_jobs(con, uri); + break; + + case IPP_OP_SET_JOB_ATTRIBUTES : + set_job_attrs(con, uri); + break; + + case IPP_OP_SET_PRINTER_ATTRIBUTES : + set_printer_attrs(con, uri); + break; + + case IPP_OP_HOLD_NEW_JOBS : + hold_new_jobs(con, uri); + break; + + case IPP_OP_RELEASE_HELD_NEW_JOBS : + release_held_new_jobs(con, uri); + break; + + case IPP_OP_CLOSE_JOB : + close_job(con, uri); + break; + + case IPP_OP_CUPS_GET_DEFAULT : + get_default(con); + break; + + case IPP_OP_CUPS_GET_PRINTERS : + get_printers(con, 0); + break; + + case IPP_OP_CUPS_GET_CLASSES : + get_printers(con, CUPS_PRINTER_CLASS); + break; + + case IPP_OP_CUPS_ADD_MODIFY_PRINTER : + add_printer(con, uri); + break; + + case IPP_OP_CUPS_DELETE_PRINTER : + delete_printer(con, uri); + break; + + case IPP_OP_CUPS_ADD_MODIFY_CLASS : + add_class(con, uri); + break; + + case IPP_OP_CUPS_DELETE_CLASS : + delete_printer(con, uri); + break; + + case IPP_OP_CUPS_ACCEPT_JOBS : + case IPP_OP_ENABLE_PRINTER : + accept_jobs(con, uri); + break; + + case IPP_OP_CUPS_REJECT_JOBS : + case IPP_OP_DISABLE_PRINTER : + reject_jobs(con, uri); + break; - case CUPS_SET_DEFAULT : - set_default(con, uri); - break; + case IPP_OP_CUPS_SET_DEFAULT : + set_default(con, uri); + break; - case CUPS_GET_DEVICES : - get_devices(con); - break; + case IPP_OP_CUPS_GET_DEVICES : + get_devices(con); + break; - case CUPS_GET_DOCUMENT : - get_document(con, uri); - break; + case IPP_OP_CUPS_GET_DOCUMENT : + get_document(con, uri); + break; - case CUPS_GET_PPD : - get_ppd(con, uri); - break; + case IPP_OP_CUPS_GET_PPD : + get_ppd(con, uri); + break; - case CUPS_GET_PPDS : - get_ppds(con); - break; + case IPP_OP_CUPS_GET_PPDS : + get_ppds(con); + break; - case CUPS_MOVE_JOB : - move_job(con, uri); - break; + case IPP_OP_CUPS_MOVE_JOB : + move_job(con, uri); + break; - case CUPS_AUTHENTICATE_JOB : - authenticate_job(con, uri); - break; + case IPP_OP_CUPS_AUTHENTICATE_JOB : + authenticate_job(con, uri); + break; - case IPP_CREATE_PRINTER_SUBSCRIPTION : - case IPP_CREATE_JOB_SUBSCRIPTION : - create_subscription(con, uri); - break; + case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS : + case IPP_OP_CREATE_JOB_SUBSCRIPTIONS : + create_subscriptions(con, uri); + break; + + case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES : + get_subscription_attrs(con, sub_id); + break; + + case IPP_OP_GET_SUBSCRIPTIONS : + get_subscriptions(con, uri); + break; - case IPP_GET_SUBSCRIPTION_ATTRIBUTES : - get_subscription_attrs(con, sub_id); - break; + case IPP_OP_RENEW_SUBSCRIPTION : + renew_subscription(con, sub_id); + break; - case IPP_GET_SUBSCRIPTIONS : - get_subscriptions(con, uri); - break; + case IPP_OP_CANCEL_SUBSCRIPTION : + cancel_subscription(con, sub_id); + break; - case IPP_RENEW_SUBSCRIPTION : - renew_subscription(con, sub_id); - break; + case IPP_OP_GET_NOTIFICATIONS : + get_notifications(con); + break; - case IPP_CANCEL_SUBSCRIPTION : - cancel_subscription(con, sub_id); - break; + case IPP_OP_CUPS_CREATE_LOCAL_PRINTER : + create_local_printer(con); + break; - case IPP_GET_NOTIFICATIONS : - get_notifications(con); - break; + default : + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Operation %04X (%s) not supported.", IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, con->http->hostname, con->request->request.op.operation_id, ippOpString(con->request->request.op.operation_id)); - default : - cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, - "%04X %s Operation %04X (%s) not supported", - IPP_OPERATION_NOT_SUPPORTED, con->http.hostname, - con->request->request.op.operation_id, - ippOpString(con->request->request.op.operation_id)); - - send_ipp_status(con, IPP_OPERATION_NOT_SUPPORTED, - _("%s not supported."), - ippOpString( - con->request->request.op.operation_id)); - break; + send_ipp_status(con, IPP_STATUS_ERROR_OPERATION_NOT_SUPPORTED, _("%s not supported."), ippOpString(con->request->request.op.operation_id)); + break; + } } } } @@ -730,82 +626,52 @@ cupsdProcessIPPRequest( * Sending data from the scheduler... */ - cupsdLogMessage(con->response->request.status.status_code - >= IPP_BAD_REQUEST && - con->response->request.status.status_code - != IPP_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, - "Returning IPP %s for %s (%s) from %s", - ippErrorString(con->response->request.status.status_code), - ippOpString(con->request->request.op.operation_id), - uri ? uri->values[0].string.text : "no URI", - con->http.hostname); + cupsdLogClient(con, con->response->request.status.status_code >= IPP_STATUS_ERROR_BAD_REQUEST && con->response->request.status.status_code != IPP_STATUS_ERROR_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, "Returning IPP %s for %s (%s) from %s.", ippErrorString(con->response->request.status.status_code), ippOpString(con->request->request.op.operation_id), uri ? uri->values[0].string.text : "no URI", con->http->hostname); - if (LogLevel == CUPSD_LOG_DEBUG2) - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdProcessIPPRequest: ippLength(response)=%ld", - (long)ippLength(con->response)); + httpClearFields(con->http); - if (cupsdSendHeader(con, HTTP_OK, "application/ipp", CUPSD_AUTH_NONE)) - { #ifdef CUPSD_USE_CHUNKING - /* - * Because older versions of CUPS (1.1.17 and older) and some IPP - * clients do not implement chunking properly, we cannot use - * chunking by default. This may become the default in future - * CUPS releases, or we might add a configuration directive for - * it. - */ - - if (con->http.version == HTTP_1_1) - { - if (httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n") < 0) - return (0); - - if (cupsdFlushHeader(con) < 0) - return (0); + /* + * Because older versions of CUPS (1.1.17 and older) and some IPP + * clients do not implement chunking properly, we cannot use + * chunking by default. This may become the default in future + * CUPS releases, or we might add a configuration directive for + * it. + */ - con->http.data_encoding = HTTP_ENCODE_CHUNKED; - } - else + if (con->http->version == HTTP_1_1) + { + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Transfer-Encoding: chunked"); + cupsdSetLength(con->http, 0); + } + else #endif /* CUPSD_USE_CHUNKING */ - { - size_t length; /* Length of response */ - - - length = ippLength(con->response); - - if (con->file >= 0 && !con->pipe_pid) - { - struct stat fileinfo; /* File information */ - - - if (!fstat(con->file, &fileinfo)) - length += fileinfo.st_size; - } + { + size_t length; /* Length of response */ - if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n", - CUPS_LLCAST length) < 0) - return (0); - if (cupsdFlushHeader(con) < 0) - return (0); + length = ippLength(con->response); - con->http.data_encoding = HTTP_ENCODE_LENGTH; - con->http.data_remaining = length; + if (con->file >= 0 && !con->pipe_pid) + { + struct stat fileinfo; /* File information */ - if (con->http.data_remaining <= INT_MAX) - con->http._data_remaining = con->http.data_remaining; - else - con->http._data_remaining = INT_MAX; + if (!fstat(con->file, &fileinfo)) + length += (size_t)fileinfo.st_size; } - cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient, - (cupsd_selfunc_t)cupsdWriteClient, con); + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Content-Length: " CUPS_LLFMT, CUPS_LLCAST length); + httpSetLength(con->http, length); + } + if (cupsdSendHeader(con, HTTP_OK, "application/ipp", CUPSD_AUTH_NONE)) + { /* * Tell the caller the response header was sent successfully... */ + cupsdAddSelect(httpGetFd(con->http), (cupsd_selfunc_t)cupsdReadClient, (cupsd_selfunc_t)cupsdWriteClient, con); + return (1); } else @@ -853,8 +719,7 @@ cupsdTimeoutJob(cupsd_job_t *job) /* I - Job to timeout */ printer = cupsdFindDest(job->dest); attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); - if (printer && - !(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) && + if (printer && !(printer->type & CUPS_PRINTER_REMOTE) && attr && attr->num_values > 1) { /* @@ -888,7 +753,7 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -969,12 +834,11 @@ add_class(cupsd_client_t *con, /* I - Client connection */ cups_ptype_t dtype; /* Destination type */ ipp_attribute_t *attr; /* Printer attribute */ int modify; /* Non-zero if we just modified */ - char newname[IPP_MAX_NAME]; /* New class name */ int need_restart_job; /* Need to restart job? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Do we have a valid URI? @@ -1023,8 +887,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ * Class doesn't exist; see if we have a printer of the same name... */ - if ((pclass = cupsdFindPrinter(resource + 9)) != NULL && - !(pclass->type & CUPS_PRINTER_DISCOVERED)) + if ((pclass = cupsdFindPrinter(resource + 9)) != NULL) { /* * Yes, return an error... @@ -1048,56 +911,8 @@ add_class(cupsd_client_t *con, /* I - Client connection */ pclass = cupsdAddClass(resource + 9); modify = 0; - } - else if (pclass->type & CUPS_PRINTER_IMPLICIT) - { - /* - * Check the default policy, then rename the implicit class to "AnyClass" - * or remove it... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - if (ImplicitAnyClasses) - { - snprintf(newname, sizeof(newname), "Any%s", resource + 9); - cupsdRenamePrinter(pclass, newname); - } - else - cupsdDeletePrinter(pclass, 1); - - /* - * Add the class as a new local class... - */ - - pclass = cupsdAddClass(resource + 9); - modify = 0; - } - else if (pclass->type & CUPS_PRINTER_DISCOVERED) - { - /* - * Check the default policy, then rename the remote class to "Class"... - */ - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - snprintf(newname, sizeof(newname), "%s@%s", resource + 9, pclass->hostname); - cupsdRenamePrinter(pclass, newname); - - /* - * Add the class as a new local class... - */ - - pclass = cupsdAddClass(resource + 9); - modify = 0; + pclass->printer_id = NextPrinterId ++; } else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con, NULL)) != HTTP_OK) @@ -1114,10 +929,18 @@ add_class(cupsd_client_t *con, /* I - Client connection */ need_restart_job = 0; - if ((attr = ippFindAttribute(con->request, "printer-location", - IPP_TAG_TEXT)) != NULL) + if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL) cupsdSetString(&pclass->location, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4)) + cupsdSetString(&pclass->geo_location, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&pclass->organization, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&pclass->organizational_unit, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) cupsdSetString(&pclass->info, attr->values[0].string.text); @@ -1136,17 +959,29 @@ add_class(cupsd_client_t *con, /* I - Client connection */ pclass->accepting ? "Now" : "No longer"); } - if ((attr = ippFindAttribute(con->request, "printer-is-shared", - IPP_TAG_BOOLEAN)) != NULL) + if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL) { - if (pclass->shared && !attr->values[0].boolean) + if (pclass->type & CUPS_PRINTER_REMOTE) + { + /* + * Cannot re-share remote printers. + */ + + send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues.")); + if (!modify) + cupsdDeletePrinter(pclass, 0); + + return; + } + + if (pclass->shared && !ippGetBoolean(attr, 0)) cupsdDeregisterPrinter(pclass, 1); cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-shared to %d (was %d.)", pclass->name, attr->values[0].boolean, pclass->shared); - pclass->shared = attr->values[0].boolean; + pclass->shared = ippGetBoolean(attr, 0); } if ((attr = ippFindAttribute(con->request, "printer-state", @@ -1158,6 +993,9 @@ add_class(cupsd_client_t *con, /* I - Client connection */ send_ipp_status(con, IPP_BAD_REQUEST, _("Attempt to set %s printer-state to bad value %d."), pclass->name, attr->values[0].integer); + if (!modify) + cupsdDeletePrinter(pclass, 0); + return; } @@ -1214,12 +1052,18 @@ add_class(cupsd_client_t *con, /* I - Client connection */ send_ipp_status(con, IPP_NOT_FOUND, _("The printer or class does not exist.")); + if (!modify) + cupsdDeletePrinter(pclass, 0); + return; } else if (dtype & CUPS_PRINTER_CLASS) { send_ipp_status(con, IPP_BAD_REQUEST, _("Nested classes are not allowed.")); + if (!modify) + cupsdDeletePrinter(pclass, 0); + return; } @@ -1231,12 +1075,20 @@ add_class(cupsd_client_t *con, /* I - Client connection */ } } - set_printer_defaults(con, pclass); + if (!set_printer_defaults(con, pclass)) + { + if (!modify) + cupsdDeletePrinter(pclass, 0); + + return; + } if ((attr = ippFindAttribute(con->request, "auth-info-required", IPP_TAG_KEYWORD)) != NULL) cupsdSetAuthInfoRequired(pclass, NULL, attr); + pclass->config_time = time(NULL); + /* * Update the printer class attributes and return... */ @@ -1295,7 +1147,7 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_file(con=%p[%d], job=%d, filetype=%s/%s, " - "compression=%d)", con, con ? con->http.fd : -1, job->id, + "compression=%d)", con, con ? con->number : -1, job->id, filetype->super, filetype->type, compression); /* @@ -1310,12 +1162,18 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ else { compressions = (int *)realloc(job->compressions, - (job->num_files + 1) * sizeof(int)); + (size_t)(job->num_files + 1) * sizeof(int)); filetypes = (mime_type_t **)realloc(job->filetypes, - (job->num_files + 1) * + (size_t)(job->num_files + 1) * sizeof(mime_type_t *)); } + if (compressions) + job->compressions = compressions; + + if (filetypes) + job->filetypes = filetypes; + if (!compressions || !filetypes) { cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE, @@ -1328,9 +1186,7 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ return (-1); } - job->compressions = compressions; job->compressions[job->num_files] = compression; - job->filetypes = filetypes; job->filetypes[job->num_files] = filetype; job->num_files ++; @@ -1354,6 +1210,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ http_status_t status; /* Policy status */ ipp_attribute_t *attr, /* Current attribute */ *auth_info; /* auth-info attribute */ + const char *mandatory; /* Current mandatory job attribute */ const char *val; /* Default option value */ int priority; /* Job priority */ cupsd_job_t *job; /* Current job */ @@ -1365,10 +1222,35 @@ add_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *media_col, /* media-col attribute */ *media_margin; /* media-*-margin attribute */ ipp_t *unsup_col; /* media-col in unsupported response */ + static const char * const readonly[] =/* List of read-only attributes */ + { + "date-time-at-completed", + "date-time-at-creation", + "date-time-at-processing", + "job-detailed-status-messages", + "job-document-access-errors", + "job-id", + "job-impressions-completed", + "job-k-octets-completed", + "job-media-sheets-completed", + "job-pages-completed", + "job-printer-up-time", + "job-printer-uri", + "job-state", + "job-state-message", + "job-state-reasons", + "job-uri", + "number-of-documents", + "number-of-intervening-jobs", + "output-device-assigned", + "time-at-completed", + "time-at-creation", + "time-at-processing" + }; cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))", - con, con->http.fd, printer, printer->name, + con, con->number, printer, printer->name, filetype, filetype ? filetype->super : "none", filetype ? filetype->type : "none"); @@ -1377,8 +1259,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ */ if (!printer->shared && - strcasecmp(con->http.hostname, "localhost") && - strcasecmp(con->http.hostname, ServerName)) + _cups_strcasecmp(con->http->hostname, "localhost") && + _cups_strcasecmp(con->http->hostname, ServerName)) { send_ipp_status(con, IPP_NOT_AUTHORIZED, _("The printer or class is not shared.")); @@ -1404,8 +1286,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ return (NULL); } #ifdef HAVE_SSL - else if (auth_info && !con->http.tls && - !httpAddrLocalhost(con->http.hostaddr)) + else if (auth_info && !con->http->tls && + !httpAddrLocalhost(con->http->hostaddr)) { /* * Require encryption of auth-info over non-local connections... @@ -1430,9 +1312,46 @@ add_job(cupsd_client_t *con, /* I - Client connection */ /* * Validate job template attributes; for now just document-format, - * copies, number-up, and page-ranges... + * copies, job-sheets, number-up, page-ranges, mandatory attributes, and + * media... */ + for (i = 0; i < (int)(sizeof(readonly) / sizeof(readonly[0])); i ++) + { + if ((attr = ippFindAttribute(con->request, readonly[i], IPP_TAG_ZERO)) != NULL) + { + ippDeleteAttribute(con->request, attr); + + if (StrictConformance) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("The '%s' Job Status attribute cannot be supplied in a job creation request."), readonly[i]); + return (NULL); + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Unexpected '%s' Job Status attribute in a job creation request.", readonly[i]); + } + } + + if (printer->pc) + { + for (mandatory = (char *)cupsArrayFirst(printer->pc->mandatory); + mandatory; + mandatory = (char *)cupsArrayNext(printer->pc->mandatory)) + { + if (!ippFindAttribute(con->request, mandatory, IPP_TAG_ZERO)) + { + /* + * Missing a required attribute... + */ + + send_ipp_status(con, IPP_CONFLICT, + _("The \"%s\" attribute is required for print jobs."), + mandatory); + return (NULL); + } + } + } + if (filetype && printer->filetypes && !cupsArrayFind(printer->filetypes, filetype)) { @@ -1618,9 +1537,43 @@ add_job(cupsd_client_t *con, /* I - Client connection */ priority); } - if (!ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) - ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, - "Untitled"); + if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) == NULL) + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); + else if ((attr->value_tag != IPP_TAG_NAME && + attr->value_tag != IPP_TAG_NAMELANG) || + attr->num_values != 1) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("Bad job-name value: Wrong type or count.")); + if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + + if (StrictConformance) + return (NULL); + + /* Don't use invalid attribute */ + ippDeleteAttribute(con->request, attr); + + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); + } + else if (!ippValidateAttribute(attr)) + { + send_ipp_status(con, IPP_ATTRIBUTES, _("Bad job-name value: %s"), + cupsLastErrorString()); + + if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + + if (StrictConformance) + return (NULL); + + /* Don't use invalid attribute */ + ippDeleteAttribute(con->request, attr); + + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); + } + + attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME); if ((job = cupsdAddJob(priority, printer->name)) == NULL) { @@ -1630,25 +1583,22 @@ add_job(cupsd_client_t *con, /* I - Client connection */ return (NULL); } - job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | - CUPS_PRINTER_REMOTE); + job->dtype = printer->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE); job->attrs = con->request; job->dirty = 1; con->request = ippNewRequest(job->attrs->request.op.operation_id); cupsdMarkDirty(CUPSD_DIRTY_JOBS); - add_job_uuid(con, job); + add_job_uuid(job); apply_printer_defaults(printer, job); - attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME); - if (con->username[0]) { cupsdSetString(&job->username, con->username); if (attr) - cupsdSetString(&attr->values[0].string.text, con->username); + ippSetString(job->attrs, &attr, 0, con->username); } else if (attr) { @@ -1666,9 +1616,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ "job-originating-user-name", NULL, job->username); else { - attr->group_tag = IPP_TAG_JOB; - _cupsStrFree(attr->name); - attr->name = _cupsStrAlloc("job-originating-user-name"); + ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB); + ippSetName(job->attrs, &attr, "job-originating-user-name"); } if (con->username[0] || auth_info) @@ -1683,6 +1632,9 @@ add_job(cupsd_client_t *con, /* I - Client connection */ ippDeleteAttribute(job->attrs, auth_info); } + if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL) + cupsdSetString(&(job->name), attr->values[0].string.text); + if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name", IPP_TAG_ZERO)) != NULL) { @@ -1692,55 +1644,18 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (attr->value_tag != IPP_TAG_NAME || attr->num_values != 1 || - strcmp(con->http.hostname, "localhost")) + strcmp(con->http->hostname, "localhost")) { /* * Can't override the value if we aren't connected via localhost. * Also, we can only have 1 value and it must be a name value. */ - switch (attr->value_tag) - { - case IPP_TAG_STRING : - case IPP_TAG_TEXTLANG : - case IPP_TAG_NAMELANG : - case IPP_TAG_TEXT : - case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - case IPP_TAG_CHARSET : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - /* - * Free old strings... - */ - - for (i = 0; i < attr->num_values; i ++) - { - _cupsStrFree(attr->values[i].string.text); - attr->values[i].string.text = NULL; - if (attr->values[i].string.charset) - { - _cupsStrFree(attr->values[i].string.charset); - attr->values[i].string.charset = NULL; - } - } - - default : - break; - } - - /* - * Use the default connection hostname instead... - */ - - attr->value_tag = IPP_TAG_NAME; - attr->num_values = 1; - attr->values[0].string.text = _cupsStrAlloc(con->http.hostname); + ippDeleteAttribute(job->attrs, attr); + ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-host-name", NULL, con->http->hostname); } - - attr->group_tag = IPP_TAG_JOB; + else + ippSetGroupTag(job->attrs, &attr, IPP_TAG_JOB); } else { @@ -1750,17 +1665,15 @@ add_job(cupsd_client_t *con, /* I - Client connection */ */ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, - "job-originating-host-name", NULL, con->http.hostname); + "job-originating-host-name", NULL, con->http->hostname); } - ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", - time(NULL)); - attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, - "time-at-processing", 0); - attr->value_tag = IPP_TAG_NOVALUE; - attr = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, - "time-at-completed", 0); - attr->value_tag = IPP_TAG_NOVALUE; + ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-completed"); + ippAddDate(job->attrs, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(time(NULL))); + ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "date-time-at-processing"); + ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "time-at-completed"); + ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", time(NULL)); + ippAddOutOfBand(job->attrs, IPP_TAG_JOB, IPP_TAG_NOVALUE, "time-at-processing"); /* * Add remaining job attributes... @@ -1770,13 +1683,15 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->state = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", IPP_JOB_STOPPED); job->state_value = (ipp_jstate_t)job->state->values[0].integer; + job->reasons = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, + "job-state-reasons", NULL, "job-incoming"); + job->impressions = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", 0); job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-media-sheets-completed", 0); ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, printer->uri); - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer = 0; else ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", 0); @@ -1793,7 +1708,24 @@ add_job(cupsd_client_t *con, /* I - Client connection */ attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-hold-until", NULL, val); } - if (attr && strcmp(attr->values[0].string.text, "no-hold")) + + if (printer->holding_new_jobs) + { + /* + * Hold all new jobs on this printer... + */ + + if (attr && strcmp(attr->values[0].string.text, "no-hold")) + cupsdSetJobHoldUntil(job, ippGetString(attr, 0, NULL), 0); + else + cupsdSetJobHoldUntil(job, "indefinite", 0); + + job->state->values[0].integer = IPP_JOB_HELD; + job->state_value = IPP_JOB_HELD; + + ippSetString(job->attrs, &job->reasons, 0, "job-held-on-create"); + } + else if (attr && strcmp(attr->values[0].string.text, "no-hold")) { /* * Hold job until specified time... @@ -1803,6 +1735,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; + + ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified"); } else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB) { @@ -1814,10 +1748,11 @@ add_job(cupsd_client_t *con, /* I - Client connection */ { job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } - if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) || - Classification) + if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification) { /* * Add job sheets options... @@ -1832,8 +1767,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ attr = ippAddStrings(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-sheets", 2, NULL, NULL); - attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]); - attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]); + ippSetString(job->attrs, &attr, 0, printer->job_sheets[0]); + ippSetString(job->attrs, &attr, 1, printer->job_sheets[1]); } job->job_sheets = attr; @@ -1859,7 +1794,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * Force the leading banner to have the classification on it... */ - cupsdSetString(&attr->values[0].string.text, Classification); + ippSetString(job->attrs, &attr, 0, Classification); cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED " "job-sheets=\"%s,none\", " @@ -1876,7 +1811,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * Can't put two different security markings on the same document! */ - cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text); + ippSetString(job->attrs, &attr, 1, attr->values[0].string.text); cupsdLogJob(job, CUPSD_LOG_NOTICE, "CLASSIFICATION FORCED " "job-sheets=\"%s,%s\", " @@ -1916,18 +1851,18 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (attr->num_values > 1 && !strcmp(attr->values[0].string.text, attr->values[1].string.text)) { - cupsdSetString(&(attr->values[0].string.text), Classification); - cupsdSetString(&(attr->values[1].string.text), Classification); + ippSetString(job->attrs, &attr, 0, Classification); + ippSetString(job->attrs, &attr, 1, Classification); } else { if (attr->num_values == 1 || strcmp(attr->values[0].string.text, "none")) - cupsdSetString(&(attr->values[0].string.text), Classification); + ippSetString(job->attrs, &attr, 0, Classification); if (attr->num_values > 1 && strcmp(attr->values[1].string.text, "none")) - cupsdSetString(&(attr->values[1].string.text), Classification); + ippSetString(job->attrs, &attr, 1, Classification); } if (attr->num_values > 1) @@ -1950,7 +1885,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * See if we need to add the starting sheet... */ - if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + if (!(printer->type & CUPS_PRINTER_REMOTE)) { cupsdLogJob(job, CUPSD_LOG_INFO, "Adding start banner page \"%s\".", attr->values[0].string.text); @@ -1974,9 +1909,8 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * Fill in the response info... */ - snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName, - LocalPort, job->id); - + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, + con->clientname, con->clientport, "/jobs/%d", job->id); ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); @@ -1984,7 +1918,9 @@ add_job(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state_value); - add_job_state_reasons(con, job); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_TEXT, "job-state-message", NULL, ""); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", + NULL, job->reasons->values[0].string.text); con->response->request.status.status_code = IPP_OK; @@ -2016,82 +1952,13 @@ add_job(cupsd_client_t *con, /* I - Client connection */ /* - * 'add_job_state_reasons()' - Add the "job-state-reasons" attribute based - * upon the job and printer state... + * 'add_job_subscriptions()' - Add any subscriptions for a job. */ static void -add_job_state_reasons( +add_job_subscriptions( cupsd_client_t *con, /* I - Client connection */ - cupsd_job_t *job) /* I - Job info */ -{ - cupsd_printer_t *dest; /* Destination printer */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job_state_reasons(%p[%d], %d)", - con, con->http.fd, job ? job->id : 0); - - switch (job ? job->state_value : IPP_JOB_CANCELED) - { - case IPP_JOB_PENDING : - dest = cupsdFindDest(job->dest); - - if (dest && dest->state == IPP_PRINTER_STOPPED) - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "printer-stopped"); - else - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "none"); - break; - - case IPP_JOB_HELD : - if (ippFindAttribute(job->attrs, "job-hold-until", - IPP_TAG_KEYWORD) != NULL || - ippFindAttribute(job->attrs, "job-hold-until", - IPP_TAG_NAME) != NULL) - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-hold-until-specified"); - else - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-incoming"); - break; - - case IPP_JOB_PROCESSING : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-printing"); - break; - - case IPP_JOB_STOPPED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-stopped"); - break; - - case IPP_JOB_CANCELED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-canceled-by-user"); - break; - - case IPP_JOB_ABORTED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "aborted-by-system"); - break; - - case IPP_JOB_COMPLETED : - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, - "job-state-reasons", NULL, "job-completed-successfully"); - break; - } -} - - -/* - * 'add_job_subscriptions()' - Add any subscriptions for a job. - */ - -static void -add_job_subscriptions( - cupsd_client_t *con, /* I - Client connection */ - cupsd_job_t *job) /* I - Newly created job */ + cupsd_job_t *job) /* I - Newly created job */ { int i; /* Looping var */ ipp_attribute_t *prev, /* Previous attribute */ @@ -2145,7 +2012,7 @@ add_job_subscriptions( host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ - + struct stat info; /* File information */ recipient = attr->values[0].string.text; @@ -2161,9 +2028,8 @@ add_job_subscriptions( return; } - snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, - scheme); - if (access(notifier, X_OK)) + snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, scheme); + if (access(notifier, X_OK) || stat(notifier, &info) || !S_ISREG(info.st_mode)) { send_ipp_status(con, IPP_NOT_POSSIBLE, _("notify-recipient-uri URI \"%s\" uses unknown " @@ -2267,7 +2133,7 @@ add_job_subscriptions( { sub->user_data_len = user_data->values[0].unknown.length; memcpy(sub->user_data, user_data->values[0].unknown.data, - sub->user_data_len); + (size_t)sub->user_data_len); } ippAddSeparator(con->response); @@ -2302,7 +2168,7 @@ add_job_subscriptions( * Free and remove this attribute... */ - _ippFreeAttr(attr); + ippDeleteAttribute(NULL, attr); if (prev) prev->next = next; @@ -2325,8 +2191,7 @@ add_job_subscriptions( */ static void -add_job_uuid(cupsd_client_t *con, /* I - Client connection */ - cupsd_job_t *job) /* I - Job */ +add_job_uuid(cupsd_job_t *job) /* I - Job */ { char uuid[64]; /* job-uuid string */ @@ -2337,8 +2202,8 @@ add_job_uuid(cupsd_client_t *con, /* I - Client connection */ if (!ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI)) ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, - _httpAssembleUUID(ServerName, RemotePort, job->dest, job->id, - uuid, sizeof(uuid))); + httpAssembleUUID(ServerName, RemotePort, job->dest, job->id, + uuid, sizeof(uuid))); } @@ -2364,15 +2229,14 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ char srcfile[1024], /* Source Script/PPD file */ dstfile[1024]; /* Destination Script/PPD file */ int modify; /* Non-zero if we are modifying */ - char newname[IPP_MAX_NAME]; /* New printer name */ - int changed_driver, /* Changed the PPD/interface script? */ + int changed_driver, /* Changed the PPD? */ need_restart_job, /* Need to restart job? */ set_device_uri, /* Did we set the device URI? */ set_port_monitor; /* Did we set the port monitor? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Do we have a valid URI? @@ -2420,8 +2284,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * Printer doesn't exist; see if we have a class of the same name... */ - if ((printer = cupsdFindClass(resource + 10)) != NULL && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if ((printer = cupsdFindClass(resource + 10)) != NULL) { /* * Yes, return an error... @@ -2445,58 +2308,8 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer = cupsdAddPrinter(resource + 10); modify = 0; - } - else if (printer->type & CUPS_PRINTER_IMPLICIT) - { - /* - * Check the default policy, then rename the implicit printer to - * "AnyPrinter" or delete it... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - if (ImplicitAnyClasses) - { - snprintf(newname, sizeof(newname), "Any%s", resource + 10); - cupsdRenamePrinter(printer, newname); - } - else - cupsdDeletePrinter(printer, 1); - - /* - * Add the printer as a new local printer... - */ - - printer = cupsdAddPrinter(resource + 10); - modify = 0; - } - else if (printer->type & CUPS_PRINTER_DISCOVERED) - { - /* - * Check the default policy, then rename the remote printer to - * "Printer@server"... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - snprintf(newname, sizeof(newname), "%s@%s", resource + 10, - printer->hostname); - cupsdRenamePrinter(printer, newname); - - /* - * Add the printer as a new local printer... - */ - printer = cupsdAddPrinter(resource + 10); - modify = 0; + printer->printer_id = NextPrinterId ++; } else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) @@ -2514,10 +2327,22 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ changed_driver = 0; need_restart_job = 0; + if ((attr = ippFindAttribute(con->request, "printer-is-temporary", IPP_TAG_BOOLEAN)) != NULL) + printer->temporary = ippGetBoolean(attr, 0); + if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL) cupsdSetString(&printer->location, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4)) + cupsdSetString(&printer->geo_location, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&printer->organization, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&printer->organizational_unit, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) cupsdSetString(&printer->info, attr->values[0].string.text); @@ -2535,7 +2360,6 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ char old_device_uri[1024]; /* Old device URI */ - need_restart_job = 1; uri_status = httpSeparateURI(HTTP_URI_CODING_ALL, @@ -2545,12 +2369,15 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ host, sizeof(host), &port, resource, sizeof(resource)); + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s device-uri: %s", printer->name, httpURIStatusString(uri_status)); + if (uri_status < HTTP_URI_OK) { send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"."), attr->values[0].string.text); - cupsdLogMessage(CUPSD_LOG_DEBUG, - "add_printer: httpSeparateURI returned %d", uri_status); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } @@ -2569,8 +2396,11 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ send_ipp_status(con, IPP_NOT_POSSIBLE, _("File device URIs have been disabled. " "To enable, see the FileDevice directive in " - "\"%s/cupsd.conf\"."), + "\"%s/cups-files.conf\"."), ServerRoot); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } } @@ -2589,6 +2419,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri scheme \"%s\"."), scheme); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } } @@ -2633,6 +2466,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ { send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"."), attr->values[0].string.text); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } @@ -2664,26 +2500,43 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer->accepting ? "Now" : "No longer"); } - if ((attr = ippFindAttribute(con->request, "printer-is-shared", - IPP_TAG_BOOLEAN)) != NULL) + if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL) { - if (attr->values[0].boolean && + if (ippGetBoolean(attr, 0) && printer->num_auth_info_required == 1 && !strcmp(printer->auth_info_required[0], "negotiate")) { send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot share a remote Kerberized printer.")); + if (!modify) + cupsdDeletePrinter(printer, 0); + + return; + } + + if (printer->type & CUPS_PRINTER_REMOTE) + { + /* + * Cannot re-share remote printers. + */ + + send_ipp_status(con, IPP_BAD_REQUEST, _("Cannot change printer-is-shared for remote queues.")); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } - if (printer->shared && !attr->values[0].boolean) + if (printer->shared && !ippGetBoolean(attr, 0)) cupsdDeregisterPrinter(printer, 1); cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-shared to %d (was %d.)", printer->name, attr->values[0].boolean, printer->shared); - printer->shared = attr->values[0].boolean; + printer->shared = ippGetBoolean(attr, 0); + if (printer->shared && printer->temporary) + printer->temporary = 0; } if ((attr = ippFindAttribute(con->request, "printer-state", @@ -2694,6 +2547,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ { send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d."), attr->values[0].integer); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } @@ -2730,6 +2586,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ attr->num_values, (int)(sizeof(printer->reasons) / sizeof(printer->reasons[0]))); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } @@ -2763,7 +2622,13 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ "Printer \"%s\" state changed.", printer->name); } - set_printer_defaults(con, printer); + if (!set_printer_defaults(con, printer)) + { + if (!modify) + cupsdDeletePrinter(printer, 0); + + return; + } if ((attr = ippFindAttribute(con->request, "auth-info-required", IPP_TAG_KEYWORD)) != NULL) @@ -2777,7 +2642,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ cupsdSetString(&printer->device_uri, "file:///dev/null"); /* - * See if we have an interface script or PPD file attached to the request... + * See if we have a PPD file attached to the request... */ if (con->filename) @@ -2801,90 +2666,59 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * Then see what kind of file it is... */ - snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot, - printer->name); - - if (!strncmp(line, "*PPD-Adobe", 10)) - { - /* - * The new file is a PPD file, so remove any old interface script - * that might be lying around... - */ - - unlink(dstfile); - } - else + if (strncmp(line, "*PPD-Adobe", 10)) { - /* - * This must be an interface script, so move the file over to the - * interfaces directory and make it executable... - */ - - if (copy_file(srcfile, dstfile)) - { - send_ipp_status(con, IPP_INTERNAL_ERROR, - _("Unable to copy interface script - %s"), - strerror(errno)); - return; - } + send_ipp_status(con, IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED, _("Bad PPD file.")); + if (!modify) + cupsdDeletePrinter(printer, 0); - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Copied interface script successfully"); - chmod(dstfile, 0755); + return; } snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, printer->name); - if (!strncmp(line, "*PPD-Adobe", 10)) - { - /* - * The new file is a PPD file, so move the file over to the - * ppd directory and make it readable by all... - */ - - if (copy_file(srcfile, dstfile)) - { - send_ipp_status(con, IPP_INTERNAL_ERROR, - _("Unable to copy PPD file - %s"), - strerror(errno)); - return; - } + /* + * The new file is a PPD file, so move the file over to the ppd + * directory... + */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Copied PPD file successfully"); - chmod(dstfile, 0644); - } - else + if (copy_file(srcfile, dstfile, ConfigFilePerm)) { - /* - * This must be an interface script, so remove any old PPD file that - * may be lying around... - */ + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file - %s"), strerror(errno)); + if (!modify) + cupsdDeletePrinter(printer, 0); - unlink(dstfile); + return; } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Copied PPD file successfully"); } } - else if ((attr = ippFindAttribute(con->request, "ppd-name", - IPP_TAG_NAME)) != NULL) + else if ((attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL) { + const char *ppd_name = ippGetString(attr, 0, NULL); + /* ppd-name value */ + need_restart_job = 1; changed_driver = 1; - if (!strcmp(attr->values[0].string.text, "raw")) + if (!strcmp(ppd_name, "raw")) { /* - * Raw driver, remove any existing PPD or interface script files. + * Raw driver, remove any existing PPD file. */ - snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot, - printer->name); + snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, printer->name); unlink(dstfile); + } + else if (strstr(ppd_name, "../")) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Invalid ppd-name value.")); + if (!modify) + cupsdDeletePrinter(printer, 0); - snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, - printer->name); - unlink(dstfile); + return; } else { @@ -2892,51 +2726,40 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * PPD model file... */ - snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot, - printer->name); - unlink(dstfile); - - snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, - printer->name); + snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, printer->name); - if (copy_model(con, attr->values[0].string.text, dstfile)) + if (copy_model(con, ppd_name, dstfile)) { send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file.")); + if (!modify) + cupsdDeletePrinter(printer, 0); + return; } - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Copied PPD file successfully"); - chmod(dstfile, 0644); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Copied PPD file successfully"); } } if (changed_driver) { /* - * If we changed the PPD/interface script, then remove the printer's cache - * file and clear the printer-state-reasons... + * If we changed the PPD, then remove the printer's cache file and clear the + * printer-state-reasons... */ char cache_name[1024]; /* Cache filename for printer attrs */ - snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, - printer->name); + snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, printer->name); unlink(cache_name); cupsdSetPrinterReasons(printer, "none"); -#ifdef __APPLE__ /* * (Re)register color profiles... */ - if (!RunUser) - { - apple_unregister_profiles(printer); - apple_register_profiles(printer); - } -#endif /* __APPLE__ */ + cupsdRegisterColor(printer); } /* @@ -2956,7 +2779,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ snprintf(srcfile, sizeof(srcfile), "%s/ppd/%s.ppd", ServerRoot, printer->name); - if ((ppd = ppdOpenFile(srcfile)) != NULL) + if ((ppd = _ppdOpenFile(srcfile, _PPD_LOCALIZATION_NONE)) != NULL) { for (ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); ppdattr; @@ -2977,974 +2800,106 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ break; } - ppdClose(ppd); - } - } - - /* - * Update the printer attributes and return... - */ - - cupsdSetPrinterAttrs(printer); - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); - - if (need_restart_job && printer->job) - { - /* - * Restart the current job... - */ - - cupsdSetJobState(printer->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE, - "Job restarted because the printer was modified."); - } - - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); - - if (modify) - { - cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, - printer, NULL, "Printer \"%s\" modified by \"%s\".", - printer->name, get_username(con)); - - cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".", - printer->name, get_username(con)); - } - else - { - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, - printer, NULL, "New printer \"%s\" added by \"%s\".", - printer->name, get_username(con)); - - cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".", - printer->name, get_username(con)); - } - - con->response->request.status.status_code = IPP_OK; -} - - -/* - * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute - * based upon the printer state... - */ - -static void -add_printer_state_reasons( - cupsd_client_t *con, /* I - Client connection */ - cupsd_printer_t *p) /* I - Printer info */ -{ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "add_printer_state_reasons(%p[%d], %p[%s])", - con, con->http.fd, p, p->name); - - if (p->num_reasons == 0) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", NULL, "none"); - else - ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", p->num_reasons, NULL, - (const char * const *)p->reasons); -} - - -/* - * 'add_queued_job_count()' - Add the "queued-job-count" attribute for - * the specified printer or class. - */ - -static void -add_queued_job_count( - cupsd_client_t *con, /* I - Client connection */ - cupsd_printer_t *p) /* I - Printer or class */ -{ - int count; /* Number of jobs on destination */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])", - con, con->http.fd, p, p->name); - - count = cupsdGetPrinterJobCount(p->name); - - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "queued-job-count", count); -} - - -#ifdef __APPLE__ -/* - * 'apple_init_profile()' - Initialize a color profile. - */ - -static void -apple_init_profile( - ppd_file_t *ppd, /* I - PPD file */ - cups_array_t *languages, /* I - Languages in the PPD file */ -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFMutableDictionaryRef profile, /* I - Profile dictionary */ -# else - CMDeviceProfileInfo *profile, /* I - Profile record */ -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - unsigned id, /* I - Profile ID */ - const char *name, /* I - Profile name */ - const char *text, /* I - Profile UI text */ - const char *iccfile) /* I - ICC filename */ -{ -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFURLRef url; /* URL for profile filename */ -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - CFMutableDictionaryRef dict; /* Dictionary for name */ - char *language; /* Current language */ - ppd_attr_t *attr; /* Profile attribute */ - CFStringRef cflang, /* Language string */ - cftext; /* Localized text */ - - - /* - * Build the profile name dictionary... - */ - - dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!dict) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize profile \"%s\".", - iccfile); - return; - } - - cftext = CFStringCreateWithCString(kCFAllocatorDefault, text, - kCFStringEncodingUTF8); - - if (cftext) - { - CFDictionarySetValue(dict, CFSTR("en_US"), cftext); - CFRelease(cftext); - } - - if (languages) - { - /* - * Find localized names for the color profiles... - */ - - cupsArraySave(ppd->sorted_attrs); - - for (language = (char *)cupsArrayFirst(languages); - language; - language = (char *)cupsArrayNext(languages)) - { - if (iccfile) - { - if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name, - language)) == NULL) - attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language); - } - else - attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language); - - if (attr && attr->text[0]) - { - cflang = CFStringCreateWithCString(kCFAllocatorDefault, language, - kCFStringEncodingUTF8); - cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text, - kCFStringEncodingUTF8); - - if (cflang && cftext) - CFDictionarySetValue(dict, cflang, cftext); - - if (cflang) - CFRelease(cflang); - - if (cftext) - CFRelease(cftext); - } - } - - cupsArrayRestore(ppd->sorted_attrs); - } - - /* - * Fill in the profile data... - */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - if (iccfile) - { - url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, - (const UInt8 *)iccfile, - strlen(iccfile), false); - - if (url) - { - CFDictionarySetValue(profile, kColorSyncDeviceProfileURL, url); - CFRelease(url); - } - } - - CFDictionarySetValue(profile, kColorSyncDeviceModeDescriptions, dict); - CFRelease(dict); - -# else - profile->dataVersion = cmDeviceProfileInfoVersion1; - profile->profileID = id; - profile->profileLoc.locType = iccfile ? cmPathBasedProfile : cmNoProfileBase; - profile->profileName = dict; - - if (iccfile) - strlcpy(profile->profileLoc.u.pathLoc.path, iccfile, - sizeof(profile->profileLoc.u.pathLoc.path)); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ -} - - -/* - * 'apple_register_profiles()' - Register color profiles for a printer. - */ - -static void -apple_register_profiles( - cupsd_printer_t *p) /* I - Printer */ -{ - int i; /* Looping var */ - char ppdfile[1024], /* PPD filename */ - iccfile[1024], /* ICC filename */ - selector[PPD_MAX_NAME]; - /* Profile selection string */ - ppd_file_t *ppd; /* PPD file */ - ppd_attr_t *attr, /* Profile attributes */ - *profileid_attr,/* cupsProfileID attribute */ - *q1_attr, /* ColorModel (or other) qualifier */ - *q2_attr, /* MediaType (or other) qualifier */ - *q3_attr; /* Resolution (or other) qualifier */ - char q_keyword[PPD_MAX_NAME]; - /* Qualifier keyword */ - const char *q1_choice, /* ColorModel (or other) choice */ - *q2_choice, /* MediaType (or other) choice */ - *q3_choice; /* Resolution (or other) choice */ - const char *profile_key; /* Profile keyword */ - ppd_option_t *cm_option; /* Color model option */ - ppd_choice_t *cm_choice; /* Color model choice */ - int num_profiles; /* Number of profiles */ - OSStatus error = 0; /* Last error */ - unsigned device_id, /* Printer device ID */ - profile_id, /* Profile ID */ - default_profile_id = 0; - /* Default profile ID */ - CFMutableDictionaryRef device_name; /* Printer device name dictionary */ - CFStringRef printer_name; /* Printer name string */ - cups_array_t *languages; /* Languages array */ -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFMutableDictionaryRef profiles, /* Dictionary of profiles */ - profile; /* Current profile info dictionary */ - CFStringRef dict_key; /* Key in factory profile dictionary */ -# else - CMDeviceScope scope = /* Scope of the registration */ - { - kCFPreferencesAnyUser, - kCFPreferencesCurrentHost - }; - CMDeviceProfileArrayPtr profiles; /* Profiles */ - CMDeviceProfileInfo *profile; /* Current profile */ -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - - /* - * Make sure ColorSync is available... - */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - if (ColorSyncRegisterDevice == NULL) - return; - -# else - if (CMRegisterColorDevice == NULL) - return; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * Try opening the PPD file for this printer... - */ - - snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); - if ((ppd = ppdOpenFile(ppdfile)) == NULL) - return; - - /* - * See if we have any profiles... - */ - - if ((attr = ppdFindAttr(ppd, "APTiogaProfile", NULL)) != NULL) - profile_key = "APTiogaProfile"; - else - { - attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); - profile_key = "cupsICCProfile"; - } - - for (num_profiles = 0; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL)) - if (attr->spec[0] && attr->value && attr->value[0]) - { - if (attr->value[0] != '/') - snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, - attr->value); - else - strlcpy(iccfile, attr->value, sizeof(iccfile)); - - if (access(iccfile, 0)) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "%s: ICC Profile \"%s\" does not exist.", p->name, - iccfile); - continue; - } - - num_profiles ++; - } - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - /* - * Create a dictionary for the factory profiles... - */ - - profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!profiles) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * If we have profiles, add them... - */ - - if (num_profiles > 0) - { - if (profile_key[0] == 'A') - { - /* - * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile - * attribute... - */ - - if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL && - attr->value) - default_profile_id = atoi(attr->value); - - q1_choice = q2_choice = q3_choice = NULL; - } - else - { - /* - * For CUPS PPDs, figure out the default profile selector values... - */ - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q1_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL) - q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); - - if (q1_attr && q1_attr->value && q1_attr->value[0]) - q1_choice = q1_attr->value; - else - q1_choice = ""; - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q2_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else - q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL); - - if (q2_attr && q2_attr->value && q2_attr->value[0]) - q2_choice = q2_attr->value; - else - q2_choice = NULL; - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q3_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else - q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL); - - if (q3_attr && q3_attr->value && q3_attr->value[0]) - q3_choice = q3_attr->value; - else - q3_choice = NULL; - } - -# ifndef HAVE_COLORSYNCREGISTERDEVICE - /* - * Build the array of profiles... - * - * Note: This calloc actually requests slightly more memory than needed. - */ - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - profile = profiles->profiles; -# endif /* !HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * Loop through the profiles listed in the PPD... - */ - - languages = _ppdGetLanguages(ppd); - - for (attr = ppdFindAttr(ppd, profile_key, NULL); - attr; - attr = ppdFindNextAttr(ppd, profile_key, NULL)) - if (attr->spec[0] && attr->value && attr->value[0]) - { - /* - * Add this profile... - */ - - if (attr->value[0] != '/') - snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, - attr->value); - else - strlcpy(iccfile, attr->value, sizeof(iccfile)); - - if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser, - cupsdLogFCMessage, p)) - continue; - - if (profile_key[0] == 'c') - { - cupsArraySave(ppd->sorted_attrs); - - if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID", - attr->spec)) != NULL && - profileid_attr->value && isdigit(profileid_attr->value[0] & 255)) - profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10); - else - profile_id = _ppdHashName(attr->spec); - - cupsArrayRestore(ppd->sorted_attrs); - } - else - profile_id = atoi(attr->spec); - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - apple_init_profile(ppd, languages, profile, profile_id, attr->spec, - attr->text[0] ? attr->text : attr->spec, iccfile); - - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%u"), profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - - CFRelease(profile); - -# else - apple_init_profile(ppd, languages, profile, profile_id, attr->spec, - attr->text[0] ? attr->text : attr->spec, iccfile); - - profile ++; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * See if this is the default profile... - */ - - if (!default_profile_id && q1_choice && q2_choice && q3_choice) - { - snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice, - q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q1_choice && q2_choice) - { - snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q1_choice && q3_choice) - { - snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q1_choice) - { - snprintf(selector, sizeof(selector), "%s..", q1_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q2_choice && q3_choice) - { - snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q2_choice) - { - snprintf(selector, sizeof(selector), ".%s.", q2_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - - if (!default_profile_id && q3_choice) - { - snprintf(selector, sizeof(selector), "..%s", q3_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - } - - _ppdFreeLanguages(languages); - } - else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL) - { - /* - * Extract profiles from ColorModel option... - */ - - const char *profile_name; /* Name of generic profile */ - - - num_profiles = cm_option->num_choices; - -# ifndef HAVE_COLORSYNCREGISTERDEVICE - /* - * Create an array for the factory profiles... - */ - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - profile = profiles->profiles; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - for (i = cm_option->num_choices, cm_choice = cm_option->choices; - i > 0; - i --, cm_choice ++) - { - if (!strcmp(cm_choice->choice, "Gray") || - !strcmp(cm_choice->choice, "Black")) - profile_name = "Gray"; - else if (!strcmp(cm_choice->choice, "RGB") || - !strcmp(cm_choice->choice, "CMY")) - profile_name = "RGB"; - else if (!strcmp(cm_choice->choice, "CMYK") || - !strcmp(cm_choice->choice, "KCMY")) - profile_name = "CMYK"; - else - profile_name = "DeviceN"; - - snprintf(selector, sizeof(selector), "%s..", profile_name); - profile_id = _ppdHashName(selector); - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, - cm_choice->text, NULL); - - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%u"), profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - - CFRelease(profile); - -# else - apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, - cm_choice->text, NULL); - profile ++; -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - if (cm_choice->marked) - default_profile_id = profile_id; - } - } - else - { - /* - * Use the default colorspace... - */ - - attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); - - num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2; - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - /* - * Add the grayscale profile first. We always have a grayscale profile. - */ - - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - profile_id = _ppdHashName("Gray.."); - apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL); - - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), - profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - - CFRelease(profile); - - /* - * Then add the RGB/CMYK/DeviceN color profile... - */ - - profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (!profile) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for color profile."); - CFRelease(profiles); - ppdClose(ppd); - return; - } - - switch (ppd->colorspace) - { - case PPD_CS_RGB : - case PPD_CS_CMY : - profile_id = _ppdHashName("RGB.."); - apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB", - NULL); - break; - case PPD_CS_RGBK : - case PPD_CS_CMYK : - profile_id = _ppdHashName("CMYK.."); - apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK", - NULL); - break; - - case PPD_CS_GRAY : - if (attr) - break; - - case PPD_CS_N : - profile_id = _ppdHashName("DeviceN.."); - apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN", - "DeviceN", NULL); - break; - } - - if (CFDictionaryGetCount(profile) > 0) - { - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("%u"), profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, dict_key, profile); - CFRelease(dict_key); - } - } - - CFRelease(profile); - -# else - /* - * Create an array for the factory profiles... - */ - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for factory profiles."); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - - /* - * Add the grayscale profile first. We always have a grayscale profile. - */ - - profile_id = _ppdHashName("Gray.."); - apple_init_profile(ppd, NULL, profiles->profiles, profile_id, "Gray", - "Gray", NULL); - - /* - * Then add the RGB/CMYK/DeviceN color profile... - */ - - switch (ppd->colorspace) - { - case PPD_CS_RGB : - case PPD_CS_CMY : - profile_id = _ppdHashName("RGB.."); - apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id, - "RGB", "RGB", NULL); - break; - case PPD_CS_RGBK : - case PPD_CS_CMYK : - profile_id = _ppdHashName("CMYK.."); - apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id, - "CMYK", "CMYK", NULL); - break; - - case PPD_CS_GRAY : - if (attr) - break; - - case PPD_CS_N : - profile_id = _ppdHashName("DeviceN.."); - apple_init_profile(ppd, NULL, profiles->profiles + 1, profile_id, - "DeviceN", "DeviceN", NULL); - break; - } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - } - - if (num_profiles > 0) - { - /* - * Make sure we have a default profile ID... - */ - - if (!default_profile_id) - default_profile_id = profile_id; /* Last profile */ - -# ifdef HAVE_COLORSYNCREGISTERDEVICE - dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), - default_profile_id); - if (dict_key) - { - CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID, - dict_key); - CFRelease(dict_key); - } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - - /* - * Get the device ID hash and pathelogical name dictionary. - */ - - cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"", - p->name); - - device_id = _ppdHashName(p->name); - device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - printer_name = CFStringCreateWithCString(kCFAllocatorDefault, - p->name, kCFStringEncodingUTF8); - - if (device_name && printer_name) - { - CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name); + ppdClose(ppd); + } + } - /* - * Register the device with ColorSync... - */ + printer->config_time = time(NULL); -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFTypeRef deviceDictKeys[] = - { /* Device keys */ - kColorSyncDeviceDescriptions, - kColorSyncFactoryProfiles, - kColorSyncDeviceUserScope, - kColorSyncDeviceHostScope - }; - CFTypeRef deviceDictVals[] = - { /* Device values */ - device_name, - profiles, - kCFPreferencesAnyUser, - kCFPreferencesCurrentHost - }; - CFDictionaryRef deviceDict; /* Device dictionary */ - CFUUIDRef deviceUUID; /* Device UUID */ - - deviceDict = CFDictionaryCreate(kCFAllocatorDefault, - (const void **)deviceDictKeys, - (const void **)deviceDictVals, - sizeof(deviceDictKeys) / - sizeof(deviceDictKeys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id); - - if (!deviceDict || !deviceUUID || - !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID, - deviceDict)) - error = 1001; - - if (deviceUUID) - CFRelease(deviceUUID); - - if (deviceDict) - CFRelease(deviceDict); + /* + * Update the printer attributes and return... + */ -# else - error = CMRegisterColorDevice(cmPrinterDeviceClass, device_id, - device_name, &scope); + if (!printer->temporary) + { + if (!printer->printer_id) + printer->printer_id = NextPrinterId ++; - /* - * Register the profiles... - */ + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + } - if (error == noErr) - error = CMSetDeviceFactoryProfiles(cmPrinterDeviceClass, device_id, - default_profile_id, profiles); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - } - else - error = 1000; + cupsdSetPrinterAttrs(printer); + if (need_restart_job && printer->job) + { /* - * Clean up... + * Restart the current job... */ - if (error != noErr) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to register ICC color profiles for \"%s\": %d", - p->name, (int)error); - - if (printer_name) - CFRelease(printer_name); - - if (device_name) - CFRelease(device_name); + cupsdSetJobState(printer->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE, + "Job restarted because the printer was modified."); } - /* - * Free any memory we used... - */ + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); -# ifdef HAVE_COLORSYNCREGISTERDEVICE - CFRelease(profiles); + if (modify) + { + cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, + printer, NULL, "Printer \"%s\" modified by \"%s\".", + printer->name, get_username(con)); -# else - if (num_profiles > 0) + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".", + printer->name, get_username(con)); + } + else { - for (profile = profiles->profiles; - num_profiles > 0; - profile ++, num_profiles --) - CFRelease(profile->profileName); + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, + printer, NULL, "New printer \"%s\" added by \"%s\".", + printer->name, get_username(con)); - free(profiles); + cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".", + printer->name, get_username(con)); } -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ - ppdClose(ppd); + con->response->request.status.status_code = IPP_OK; } /* - * 'apple_unregister_profiles()' - Remove color profiles for the specified - * printer. + * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute + * based upon the printer state... */ static void -apple_unregister_profiles( - cupsd_printer_t *p) /* I - Printer */ +add_printer_state_reasons( + cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *p) /* I - Printer info */ { - /* - * Make sure ColorSync is available... - */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_state_reasons(%p[%d], %p[%s])", + con, con->number, p, p->name); -# ifdef HAVE_COLORSYNCREGISTERDEVICE - if (ColorSyncUnregisterDevice != NULL) - { - /* - * Because we may have registered the printer profiles using a prior device - * ID-based UUID, remove both the old style UUID and current UUID for the - * printer. - */ + if (p->num_reasons == 0) + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", NULL, "none"); + else + ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", p->num_reasons, NULL, + (const char * const *)p->reasons); +} - CFUUIDRef deviceUUID; /* Device UUID */ - deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name)); - if (deviceUUID) - { - ColorSyncUnregisterDevice(kColorSyncPrinterDeviceClass, deviceUUID); - CFRelease(deviceUUID); - } - } +/* + * 'add_queued_job_count()' - Add the "queued-job-count" attribute for + * the specified printer or class. + */ -# else - if (CMUnregisterColorDevice != NULL) - CMUnregisterColorDevice(cmPrinterDeviceClass, _ppdHashName(p->name)); -# endif /* HAVE_COLORSYNCREGISTERDEVICE */ +static void +add_queued_job_count( + cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *p) /* I - Printer or class */ +{ + int count; /* Number of jobs on destination */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])", + con, con->number, p, p->name); + + count = cupsdGetPrinterJobCount(p->name); + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "queued-job-count", count); } -#endif /* __APPLE__ */ /* @@ -3962,6 +2917,8 @@ apply_printer_defaults( *option; /* Current option */ + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Applying default options..."); + /* * Collect all of the default options and add the missing ones to the * job object... @@ -3973,8 +2930,12 @@ apply_printer_defaults( i --, option ++) if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO)) { - num_options = cupsAddOption(option->name, option->value, num_options, - &options); + if (!strcmp(option->name, "print-quality") && ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_NAME)) + continue; /* Don't override cupsPrintQuality */ + + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Adding default %s=%s", option->name, option->value); + + num_options = cupsAddOption(option->name, option->value, num_options, &options); } /* @@ -4010,7 +2971,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)", - con, con->http.fd, uri->values[0].string.text); + con, con->number, uri->values[0].string.text); /* * Start with "everything is OK" status... @@ -4102,7 +3063,6 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ { cupsd_printer_t *printer; /* Job destination */ - /* * No auth data. If we need to authenticate via Kerberos, send a * HTTP auth challenge, otherwise just return an IPP error... @@ -4146,8 +3106,8 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ if (attr) { - attr->value_tag = IPP_TAG_KEYWORD; - cupsdSetString(&(attr->values[0].string.text), "no-hold"); + ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD); + ippSetString(job->attrs, &attr, 0, "no-hold"); } /* @@ -4190,7 +3150,7 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Get the jobs to cancel/purge... @@ -4297,8 +3257,12 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ { for (i = 0; i < job_ids->num_values; i ++) { - if (!cupsdFindJob(job_ids->values[i].integer)) + if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL) break; + + if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS && + _cups_strcasecmp(job->username, username)) + break; } if (i < job_ids->num_values) @@ -4352,8 +3316,12 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ for (i = 0; i < job_ids->num_values; i ++) { if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL || - strcasecmp(job->dest, printer->name)) + _cups_strcasecmp(job->dest, printer->name)) break; + + if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS && + _cups_strcasecmp(job->username, username)) + break; } if (i < job_ids->num_values) @@ -4392,6 +3360,8 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ } con->response->request.status.status_code = IPP_OK; + + cupsdCheckJobs(); } @@ -4417,7 +3387,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -4462,7 +3432,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) if (job->state_value <= IPP_JOB_PROCESSING && - !strcasecmp(job->dest, printer->name)) + !_cups_strcasecmp(job->dest, printer->name)) break; if (job) @@ -4477,7 +3447,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) if (job->state_value == IPP_JOB_STOPPED && - !strcasecmp(job->dest, printer->name)) + !_cups_strcasecmp(job->dest, printer->name)) break; if (job) @@ -4617,7 +3587,7 @@ cancel_subscription( cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_subscription(con=%p[%d], sub_id=%d)", - con, con->http.fd, sub_id); + con, con->number, sub_id); /* * Is the subscription ID valid? @@ -4723,7 +3693,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])", - con, con->http.fd, p, p->name); + con, con->number, p, p->name); /* * Figure out who is printing... @@ -4731,6 +3701,9 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ strlcpy(username, get_username(con), sizeof(username)); + if ((name = strchr(username, '@')) != NULL) + *name = '\0'; /* Strip @REALM */ + /* * Check global active job limits for printers and users... */ @@ -4883,7 +3856,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ break; } #else - else if (!strcasecmp(username, name)) + else if (!_cups_strcasecmp(username, name)) break; #endif /* HAVE_MBR_UID_TO_UUID */ @@ -4943,7 +3916,7 @@ close_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -5026,8 +3999,8 @@ close_job(cupsd_client_t *con, /* I - Client connection */ * Fill in the response info... */ - snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName, - LocalPort, job->id); + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, + con->clientname, con->clientport, "/jobs/%d", job->id); ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); @@ -5036,8 +4009,6 @@ close_job(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state_value); - add_job_state_reasons(con, job); - con->response->request.status.status_code = IPP_OK; /* @@ -5048,192 +4019,6 @@ close_job(cupsd_client_t *con, /* I - Client connection */ } -/* - * 'copy_attribute()' - Copy a single attribute. - */ - -static ipp_attribute_t * /* O - New attribute */ -copy_attribute( - ipp_t *to, /* O - Destination request/response */ - ipp_attribute_t *attr, /* I - Attribute to copy */ - int quickcopy) /* I - Do a quick copy? */ -{ - int i; /* Looping var */ - ipp_attribute_t *toattr; /* Destination attribute */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "copy_attribute(%p, %p[%s,%x,%x])", to, attr, - attr->name ? attr->name : "(null)", attr->group_tag, - attr->value_tag); - - switch (attr->value_tag & ~IPP_TAG_COPY) - { - case IPP_TAG_ZERO : - toattr = ippAddSeparator(to); - break; - - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].integer = attr->values[i].integer; - break; - - case IPP_TAG_BOOLEAN : - toattr = ippAddBooleans(to, attr->group_tag, attr->name, - attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].boolean = attr->values[i].boolean; - break; - - case IPP_TAG_STRING : - case IPP_TAG_TEXT : - case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - case IPP_TAG_CHARSET : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - toattr = ippAddStrings(to, attr->group_tag, - (ipp_tag_t)(attr->value_tag | quickcopy), - attr->name, attr->num_values, NULL, NULL); - - if (quickcopy) - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = attr->values[i].string.text; - } - else if (attr->value_tag & IPP_TAG_COPY) - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = - _cupsStrAlloc(attr->values[i].string.text); - } - else - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = - _cupsStrRetain(attr->values[i].string.text); - } - break; - - case IPP_TAG_DATE : - toattr = ippAddDate(to, attr->group_tag, attr->name, - attr->values[0].date); - break; - - case IPP_TAG_RESOLUTION : - toattr = ippAddResolutions(to, attr->group_tag, attr->name, - attr->num_values, IPP_RES_PER_INCH, - NULL, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].resolution.xres = attr->values[i].resolution.xres; - toattr->values[i].resolution.yres = attr->values[i].resolution.yres; - toattr->values[i].resolution.units = attr->values[i].resolution.units; - } - break; - - case IPP_TAG_RANGE : - toattr = ippAddRanges(to, attr->group_tag, attr->name, - attr->num_values, NULL, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].range.lower = attr->values[i].range.lower; - toattr->values[i].range.upper = attr->values[i].range.upper; - } - break; - - case IPP_TAG_TEXTLANG : - case IPP_TAG_NAMELANG : - toattr = ippAddStrings(to, attr->group_tag, - (ipp_tag_t)(attr->value_tag | quickcopy), - attr->name, attr->num_values, NULL, NULL); - - if (quickcopy) - { - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].string.charset = attr->values[i].string.charset; - toattr->values[i].string.text = attr->values[i].string.text; - } - } - else if (attr->value_tag & IPP_TAG_COPY) - { - for (i = 0; i < attr->num_values; i ++) - { - if (!i) - toattr->values[i].string.charset = - _cupsStrAlloc(attr->values[i].string.charset); - else - toattr->values[i].string.charset = - toattr->values[0].string.charset; - - toattr->values[i].string.text = - _cupsStrAlloc(attr->values[i].string.text); - } - } - else - { - for (i = 0; i < attr->num_values; i ++) - { - if (!i) - toattr->values[i].string.charset = - _cupsStrRetain(attr->values[i].string.charset); - else - toattr->values[i].string.charset = - toattr->values[0].string.charset; - - toattr->values[i].string.text = - _cupsStrRetain(attr->values[i].string.text); - } - } - break; - - case IPP_TAG_BEGIN_COLLECTION : - toattr = ippAddCollections(to, attr->group_tag, attr->name, - attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].collection = attr->values[i].collection; - attr->values[i].collection->use ++; - } - break; - - default : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].unknown.length = attr->values[i].unknown.length; - - if (toattr->values[i].unknown.length > 0) - { - if ((toattr->values[i].unknown.data = - malloc(toattr->values[i].unknown.length)) == NULL) - toattr->values[i].unknown.length = 0; - else - memcpy(toattr->values[i].unknown.data, - attr->values[i].unknown.data, - toattr->values[i].unknown.length); - } - } - break; /* anti-compiler-warning-code */ - } - - return (toattr); -} - - /* * 'copy_attrs()' - Copy attributes from one request to another. */ @@ -5266,20 +4051,28 @@ copy_attrs(ipp_t *to, /* I - Destination request */ fromattr->group_tag != IPP_TAG_ZERO) || !fromattr->name) continue; + if (!strcmp(fromattr->name, "document-password") || + !strcmp(fromattr->name, "job-authorization-uri") || + !strcmp(fromattr->name, "job-password") || + !strcmp(fromattr->name, "job-password-encryption") || + !strcmp(fromattr->name, "job-printer-uri")) + continue; + if (exclude && (cupsArrayFind(exclude, fromattr->name) || cupsArrayFind(exclude, "all"))) { /* * We need to exclude this attribute for security reasons; we require the - * job-id and job-printer-uri attributes regardless of the security - * settings for IPP conformance. + * job-id attribute regardless of the security settings for IPP + * conformance. + * + * The job-printer-uri attribute is handled by copy_job_attrs(). * * Subscription attribute security is handled by copy_subscription_attrs(). */ - if (strcmp(fromattr->name, "job-id") && - strcmp(fromattr->name, "job-printer-uri")) + if (strcmp(fromattr->name, "job-id")) continue; } @@ -5297,7 +4090,7 @@ copy_attrs(ipp_t *to, /* I - Destination request */ !strcmp(fromattr->name, "media-col-database"))) continue; - copy_attribute(to, fromattr, quickcopy); + ippCopyAttribute(to, fromattr, quickcopy); } } } @@ -5327,7 +4120,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_banner(con=%p[%d], job=%p[%d], name=\"%s\")", - con, con ? con->http.fd : -1, job, job->id, + con, con ? con->number : -1, job, job->id, name ? name : "(null)"); /* @@ -5372,8 +4165,8 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ */ attrname[2] = '_'; - attrname[3] = toupper(attrname[3] & 255); - attrname[4] = toupper(attrname[4] & 255); + attrname[3] = (char)toupper(attrname[3] & 255); + attrname[4] = (char)toupper(attrname[4] & 255); } snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir, @@ -5427,7 +4220,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ if (!isalpha(ch & 255) && ch != '-' && ch != '?') break; else if (s < (attrname + sizeof(attrname) - 1)) - *s++ = ch; + *s++ = (char)ch; else break; @@ -5518,7 +4311,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ cupsFilePrintf(out, "%dx%d%s", attr->values[i].resolution.xres, attr->values[i].resolution.yres, attr->values[i].resolution.units == IPP_RES_PER_INCH ? - "dpi" : "dpc"); + "dpi" : "dpcm"); break; case IPP_TAG_URI : @@ -5528,7 +4321,7 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : - if (!strcasecmp(banner->filetype->type, "postscript")) + if (!_cups_strcasecmp(banner->filetype->type, "postscript")) { /* * Need to quote strings for PS banners... @@ -5574,8 +4367,9 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ kbytes = (cupsFileTell(out) + 1023) / 1024; - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + job->koctets += kbytes; + + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer += kbytes; cupsFileClose(out); @@ -5585,12 +4379,13 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ /* - * 'copy_file()' - Copy a PPD file or interface script... + * 'copy_file()' - Copy a PPD file... */ static int /* O - 0 = success, -1 = error */ copy_file(const char *from, /* I - Source file */ - const char *to) /* I - Destination file */ + const char *to, /* I - Destination file */ + mode_t mode) /* I - Permissions */ { cups_file_t *src, /* Source file */ *dst; /* Destination file */ @@ -5607,7 +4402,7 @@ copy_file(const char *from, /* I - Source file */ if ((src = cupsFileOpen(from, "rb")) == NULL) return (-1); - if ((dst = cupsFileOpen(to, "wb")) == NULL) + if ((dst = cupsdCreateConfFile(to, mode)) == NULL) { cupsFileClose(src); return (-1); @@ -5618,7 +4413,7 @@ copy_file(const char *from, /* I - Source file */ */ while ((bytes = cupsFileRead(src, buffer, sizeof(buffer))) > 0) - if (cupsFileWrite(dst, buffer, bytes) < bytes) + if (cupsFileWrite(dst, buffer, (size_t)bytes) < bytes) { cupsFileClose(src); cupsFileClose(dst); @@ -5631,7 +4426,7 @@ copy_file(const char *from, /* I - Source file */ cupsFileClose(src); - return (cupsFileClose(dst)); + return (cupsdCloseCreatedConfFile(dst, to)); } @@ -5670,9 +4465,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ /* cupsProtocol attribute */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "copy_model(con=%p, from=\"%s\", to=\"%s\")", - con, from, to); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_model(con=%p, from=\"%s\", to=\"%s\")", con, from, to); /* * Run cups-driverd to get the PPD file... @@ -5686,13 +4479,11 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); snprintf(buffer, sizeof(buffer), "%s/daemon/cups-driverd", ServerBin); - snprintf(tempfile, sizeof(tempfile), "%s/%d.ppd", TempDir, con->http.fd); + snprintf(tempfile, sizeof(tempfile), "%s/%d.ppd", TempDir, con->number); tempfd = open(tempfile, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (tempfd < 0) + if (tempfd < 0 || cupsdOpenPipe(temppipe)) return (-1); - cupsdOpenPipe(temppipe); - cupsdLogMessage(CUPSD_LOG_DEBUG, "copy_model: Running \"cups-driverd cat %s\"...", from); @@ -5755,7 +4546,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ if ((bytes = read(temppipe[0], buffer, sizeof(buffer))) > 0) { - if (write(tempfd, buffer, bytes) < bytes) + if (write(tempfd, buffer, (size_t)bytes) < bytes) break; total += bytes; @@ -5782,12 +4573,23 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ return (-1); } + /* + * Open the source file for a copy... + */ + + if ((src = cupsFileOpen(tempfile, "rb")) == NULL) + { + unlink(tempfile); + return (-1); + } + /* * Read the source file and see what page sizes are supported... */ - if ((ppd = ppdOpenFile(tempfile)) == NULL) + if ((ppd = _ppdOpen(src, _PPD_LOCALIZATION_NONE)) == NULL) { + cupsFileClose(src); unlink(tempfile); return (-1); } @@ -5854,22 +4656,11 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ ppdClose(ppd); - /* - * Open the source file for a copy... - */ - - if ((src = cupsFileOpen(tempfile, "rb")) == NULL) - { - cupsFreeOptions(num_defaults, defaults); - unlink(tempfile); - return (-1); - } - /* * Open the destination file for a copy... */ - if ((dst = cupsFileOpen(to, "wb")) == NULL) + if ((dst = cupsdCreateConfFile(to, ConfigFilePerm)) == NULL) { cupsFreeOptions(num_defaults, defaults); cupsFileClose(src); @@ -5881,6 +4672,8 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ * Copy the source file to the destination... */ + cupsFileRewind(src); + while (cupsFileGets(src, buffer, sizeof(buffer))) { if (!strncmp(buffer, "*Default", 8)) @@ -5922,7 +4715,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ unlink(tempfile); - return (cupsFileClose(dst)); + return (cupsdCloseCreatedConfFile(dst, to)); } @@ -5943,47 +4736,115 @@ copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Send the requested attributes for each job... */ - httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, - con->servername, con->serverport, "/jobs/%d", - job->id); - if (!cupsArrayFind(exclude, "all")) { - if ((!exclude || !cupsArrayFind(exclude, "document-count")) && - (!ra || cupsArrayFind(ra, "document-count"))) + if ((!exclude || !cupsArrayFind(exclude, "number-of-documents")) && + (!ra || cupsArrayFind(ra, "number-of-documents"))) ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "document-count", job->num_files); + "number-of-documents", job->num_files); if ((!exclude || !cupsArrayFind(exclude, "job-media-progress")) && (!ra || cupsArrayFind(ra, "job-media-progress"))) ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-media-progress", job->progress); - if ((!exclude || !cupsArrayFind(exclude, "job-more-info")) && - (!ra || cupsArrayFind(ra, "job-more-info"))) - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, - "job-more-info", NULL, job_uri); + if ((!exclude || !cupsArrayFind(exclude, "job-more-info")) && + (!ra || cupsArrayFind(ra, "job-more-info"))) + { + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "http", + NULL, con->clientname, con->clientport, "/jobs/%d", + job->id); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, + "job-more-info", NULL, job_uri); + } + + if (job->state_value > IPP_JOB_PROCESSING && + (!exclude || !cupsArrayFind(exclude, "job-preserved")) && + (!ra || cupsArrayFind(ra, "job-preserved"))) + ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved", + job->num_files > 0); + + if ((!exclude || !cupsArrayFind(exclude, "job-printer-up-time")) && + (!ra || cupsArrayFind(ra, "job-printer-up-time"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, + "job-printer-up-time", time(NULL)); + } + + if (!ra || cupsArrayFind(ra, "job-printer-uri")) + { + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, + con->clientname, con->clientport, + (job->dtype & CUPS_PRINTER_CLASS) ? "/classes/%s" : + "/printers/%s", + job->dest); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, + "job-printer-uri", NULL, job_uri); + } + + if (!ra || cupsArrayFind(ra, "job-uri")) + { + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, + con->clientname, con->clientport, "/jobs/%d", + job->id); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, + "job-uri", NULL, job_uri); + } + + if (job->attrs) + { + copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude); + } + else + { + /* + * Generate attributes from the job structure... + */ + + if (job->completed_time && (!ra || cupsArrayFind(ra, "date-time-at-completed"))) + ippAddDate(con->response, IPP_TAG_JOB, "date-time-at-completed", ippTimeToDate(job->completed_time)); + + if (job->creation_time && (!ra || cupsArrayFind(ra, "date-time-at-creation"))) + ippAddDate(con->response, IPP_TAG_JOB, "date-time-at-creation", ippTimeToDate(job->creation_time)); + + if (!ra || cupsArrayFind(ra, "job-id")) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); + + if (!ra || cupsArrayFind(ra, "job-k-octets")) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", job->koctets); + + if (job->name && (!ra || cupsArrayFind(ra, "job-name"))) + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, job->name); - if (job->state_value > IPP_JOB_PROCESSING && - (!exclude || !cupsArrayFind(exclude, "job-preserved")) && - (!ra || cupsArrayFind(ra, "job-preserved"))) - ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved", - job->num_files > 0); + if (job->username && (!ra || cupsArrayFind(ra, "job-originating-user-name"))) + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); - if ((!exclude || !cupsArrayFind(exclude, "job-printer-up-time")) && - (!ra || cupsArrayFind(ra, "job-printer-up-time"))) - ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "job-printer-up-time", time(NULL)); - } + if (!ra || cupsArrayFind(ra, "job-state")) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value); - if (!ra || cupsArrayFind(ra, "job-state-reasons")) - add_job_state_reasons(con, job); + if (!ra || cupsArrayFind(ra, "job-state-reasons")) + { + switch (job->state_value) + { + default : /* Should never get here for processing, pending, held, or stopped jobs since they don't get unloaded... */ + break; + case IPP_JSTATE_ABORTED : + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-aborted-by-system"); + break; + case IPP_JSTATE_CANCELED : + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-canceled-by-user"); + break; + case IPP_JSTATE_COMPLETED : + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-completed-successfully"); + break; + } + } - if (!ra || cupsArrayFind(ra, "job-uri")) - ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, - "job-uri", NULL, job_uri); + if (job->completed_time && (!ra || cupsArrayFind(ra, "time-at-completed"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-completed", (int)job->completed_time); - copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude); + if (job->creation_time && (!ra || cupsArrayFind(ra, "time-at-creation"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)job->creation_time); + } } @@ -5997,12 +4858,11 @@ copy_printer_attrs( cupsd_printer_t *printer, /* I - Printer */ cups_array_t *ra) /* I - Requested attributes array */ { - char printer_uri[HTTP_MAX_URI]; - /* Printer URI */ - char printer_icons[HTTP_MAX_URI]; - /* Printer icons */ - time_t curtime; /* Current time */ - int i; /* Looping var */ + char uri[HTTP_MAX_URI]; /* URI value */ + time_t curtime; /* Current time */ + int i; /* Looping var */ + int is_encrypted = httpIsEncrypted(con->http); + /* Is the connection encrypted? */ /* @@ -6010,146 +4870,133 @@ copy_printer_attrs( * and document-format attributes that may be provided by the client. */ + _cupsRWLockRead(&printer->lock); + curtime = time(NULL); if (!ra || cupsArrayFind(ra, "marker-change-time")) - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "marker-change-time", printer->marker_time); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "marker-change-time", printer->marker_time); - if (printer->num_printers > 0 && - (!ra || cupsArrayFind(ra, "member-uris"))) + if (printer->num_printers > 0 && (!ra || cupsArrayFind(ra, "member-uris"))) { ipp_attribute_t *member_uris; /* member-uris attribute */ cupsd_printer_t *p2; /* Printer in class */ ipp_attribute_t *p2_uri; /* printer-uri-supported for class printer */ - if ((member_uris = ippAddStrings(con->response, IPP_TAG_PRINTER, - IPP_TAG_URI, "member-uris", - printer->num_printers, NULL, - NULL)) != NULL) + if ((member_uris = ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "member-uris", printer->num_printers, NULL, NULL)) != NULL) { for (i = 0; i < printer->num_printers; i ++) { p2 = printer->printers[i]; - if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported", - IPP_TAG_URI)) != NULL) - member_uris->values[i].string.text = - _cupsStrRetain(p2_uri->values[0].string.text); + if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported", IPP_TAG_URI)) != NULL) + { + member_uris->values[i].string.text = _cupsStrRetain(p2_uri->values[0].string.text); + } else { - httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, - sizeof(printer_uri), "ipp", NULL, con->servername, - con->serverport, - (p2->type & CUPS_PRINTER_CLASS) ? - "/classes/%s" : "/printers/%s", p2->name); - member_uris->values[i].string.text = _cupsStrAlloc(printer_uri); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (p2->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", p2->name); + member_uris->values[i].string.text = _cupsStrAlloc(uri); } } } } if (printer->alert && (!ra || cupsArrayFind(ra, "printer-alert"))) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_STRING, - "printer-alert", NULL, printer->alert); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_STRING, "printer-alert", NULL, printer->alert); + + if (printer->alert_description && (!ra || cupsArrayFind(ra, "printer-alert-description"))) + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-alert-description", NULL, printer->alert_description); - if (printer->alert_description && - (!ra || cupsArrayFind(ra, "printer-alert-description"))) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-alert-description", NULL, - printer->alert_description); + if (!ra || cupsArrayFind(ra, "printer-config-change-date-time")) + ippAddDate(con->response, IPP_TAG_PRINTER, "printer-config-change-date-time", ippTimeToDate(printer->config_time)); + + if (!ra || cupsArrayFind(ra, "printer-config-change-time")) + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-config-change-time", printer->config_time); if (!ra || cupsArrayFind(ra, "printer-current-time")) - ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", - ippTimeToDate(curtime)); + ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", ippTimeToDate(curtime)); -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (!ra || cupsArrayFind(ra, "printer-dns-sd-name")) { if (printer->reg_name) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, - "printer-dns-sd-name", NULL, printer->reg_name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-dns-sd-name", NULL, printer->reg_name); else - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, - "printer-dns-sd-name", 0); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_NOVALUE, "printer-dns-sd-name", 0); } -#endif /* HAVE_DNSSD */ +#endif /* HAVE_DNSSD || HAVE_AVAHI */ if (!ra || cupsArrayFind(ra, "printer-error-policy")) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, - "printer-error-policy", NULL, printer->error_policy); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-error-policy", NULL, printer->error_policy); if (!ra || cupsArrayFind(ra, "printer-error-policy-supported")) { static const char * const errors[] =/* printer-error-policy-supported values */ - { - "abort-job", - "retry-current-job", - "retry-job", - "stop-printer" - }; - - if (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, - "printer-error-policy-supported", NULL, "retry-current-job"); + { + "abort-job", + "retry-current-job", + "retry-job", + "stop-printer" + }; + + if (printer->type & CUPS_PRINTER_CLASS) + ippAddString(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", NULL, "retry-current-job"); else - ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, - "printer-error-policy-supported", - sizeof(errors) / sizeof(errors[0]), NULL, errors); + ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_NAME), "printer-error-policy-supported", sizeof(errors) / sizeof(errors[0]), NULL, errors); } if (!ra || cupsArrayFind(ra, "printer-icons")) { - httpAssembleURIf(HTTP_URI_CODING_ALL, printer_icons, sizeof(printer_icons), - "http", NULL, con->servername, con->serverport, - "/icons/%s.png", printer->name); - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons", - NULL, printer_icons); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-icons=\"%s\"", printer_icons); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/icons/%s.png", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-icons", NULL, uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-icons=\"%s\"", uri); } if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs")) - ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", - printer->accepting); + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting); if (!ra || cupsArrayFind(ra, "printer-is-shared")) - ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", - printer->shared); + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", (char)printer->shared); - if ((!ra || cupsArrayFind(ra, "printer-more-info")) && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if (!ra || cupsArrayFind(ra, "printer-is-temporary")) + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-temporary", (char)printer->temporary); + + if (!ra || cupsArrayFind(ra, "printer-more-info")) { - httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), - "http", NULL, con->servername, con->serverport, - (printer->type & CUPS_PRINTER_CLASS) ? - "/classes/%s" : "/printers/%s", printer->name); - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-more-info", NULL, printer_uri); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", NULL, uri); } if (!ra || cupsArrayFind(ra, "printer-op-policy")) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, - "printer-op-policy", NULL, printer->op_policy); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-op-policy", NULL, printer->op_policy); if (!ra || cupsArrayFind(ra, "printer-state")) - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", - printer->state); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state); + + if (!ra || cupsArrayFind(ra, "printer-state-change-date-time")) + ippAddDate(con->response, IPP_TAG_PRINTER, "printer-state-change-date-time", ippTimeToDate(printer->state_time)); if (!ra || cupsArrayFind(ra, "printer-state-change-time")) - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "printer-state-change-time", printer->state_time); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-state-change-time", printer->state_time); if (!ra || cupsArrayFind(ra, "printer-state-message")) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "printer-state-message", NULL, printer->state_message); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message", NULL, printer->state_message); if (!ra || cupsArrayFind(ra, "printer-state-reasons")) add_printer_state_reasons(con, printer); + if (!ra || cupsArrayFind(ra, "printer-strings-uri")) + { + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "https" : "http", NULL, con->clientname, con->clientport, "/strings/%s.strings", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-strings-uri", NULL, uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-strings-uri=\"%s\"", uri); + } + if (!ra || cupsArrayFind(ra, "printer-type")) { - int type; /* printer-type value */ + cups_ptype_t type; /* printer-type value */ /* * Add the CUPS-specific printer-type attribute... @@ -6166,25 +5013,17 @@ copy_printer_attrs( if (!printer->shared) type |= CUPS_PRINTER_NOT_SHARED; - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", - type); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", (int)type); } if (!ra || cupsArrayFind(ra, "printer-up-time")) - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "printer-up-time", curtime); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-up-time", curtime); - if ((!ra || cupsArrayFind(ra, "printer-uri-supported")) && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if (!ra || cupsArrayFind(ra, "printer-uri-supported")) { - httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), - "ipp", NULL, con->servername, con->serverport, - (printer->type & CUPS_PRINTER_CLASS) ? - "/classes/%s" : "/printers/%s", printer->name); - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, - "printer-uri-supported", NULL, printer_uri); - cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", - printer_uri); + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), is_encrypted ? "ipps" : "ipp", NULL, con->clientname, con->clientport, (printer->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", uri); } if (!ra || cupsArrayFind(ra, "queued-job-count")) @@ -6194,6 +5033,8 @@ copy_printer_attrs( if (printer->ppd_attrs) copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0, NULL); copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY, NULL); + + _cupsRWUnlock(&printer->lock); } @@ -6238,9 +5079,7 @@ copy_subscription_attrs( * Simple event list... */ - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, - (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), - "notify-events", NULL, name); + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", NULL, name); } else { @@ -6252,15 +5091,12 @@ copy_subscription_attrs( if (sub->mask & mask) count ++; - attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION, - (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), - "notify-events", count, NULL, NULL); + attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION, IPP_CONST_TAG(IPP_TAG_KEYWORD), "notify-events", count, NULL, NULL); for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) if (sub->mask & mask) { - attr->values[count].string.text = - (char *)cupsdEventName((cupsd_eventmask_t)mask); + attr->values[count].string.text = (char *)cupsdEventName((cupsd_eventmask_t)mask); count ++; } @@ -6305,7 +5141,7 @@ copy_subscription_attrs( if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri"))) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), - "ipp", NULL, con->servername, con->serverport, + "ipp", NULL, con->clientname, con->clientport, "/printers/%s", sub->dest->name); ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, "notify-printer-uri", NULL, printer_uri); @@ -6325,12 +5161,20 @@ static void create_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { + int i; /* Looping var */ cupsd_printer_t *printer; /* Printer */ cupsd_job_t *job; /* New job */ + static const char * const forbidden_attrs[] = + { /* List of forbidden attributes */ + "compression", + "document-format", + "document-name", + "document-natural-language" + }; cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -6347,6 +5191,29 @@ create_job(cupsd_client_t *con, /* I - Client connection */ return; } + /* + * Check for invalid Create-Job attributes and log a warning or error depending + * on whether cupsd is running in "strict conformance" mode... + */ + + for (i = 0; + i < (int)(sizeof(forbidden_attrs) / sizeof(forbidden_attrs[0])); + i ++) + if (ippFindAttribute(con->request, forbidden_attrs[i], IPP_TAG_ZERO)) + { + if (StrictConformance) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("The '%s' operation attribute cannot be supplied in a " + "Create-Job request."), forbidden_attrs[i]); + return; + } + + cupsdLogMessage(CUPSD_LOG_WARN, + "Unexpected '%s' operation attribute in a Create-Job " + "request.", forbidden_attrs[i]); + } + /* * Create the job object... */ @@ -6366,197 +5233,329 @@ create_job(cupsd_client_t *con, /* I - Client connection */ /* - * 'create_requested_array()' - Create an array for the requested-attributes. + * 'create_local_bg_thread()' - Background thread for creating a local print queue. */ -static cups_array_t * /* O - Array of attributes or NULL */ -create_requested_array(ipp_t *request) /* I - IPP request */ +static void * /* O - Exit status */ +create_local_bg_thread( + cupsd_printer_t *printer) /* I - Printer */ { - int i; /* Looping var */ - ipp_attribute_t *requested; /* requested-attributes attribute */ - cups_array_t *ra; /* Requested attributes array */ - char *value; /* Current value */ + cups_file_t *from, /* Source file */ + *to; /* Destination file */ + char fromppd[1024], /* Source PPD */ + toppd[1024], /* Destination PPD */ + scheme[32], /* URI scheme */ + userpass[256], /* User:pass */ + host[256], /* Hostname */ + resource[1024], /* Resource path */ + line[1024]; /* Line from PPD */ + int port; /* Port number */ + http_encryption_t encryption; /* Type of encryption to use */ + http_t *http; /* Connection to printer */ + ipp_t *request, /* Request to printer */ + *response; /* Response from printer */ + ipp_attribute_t *attr; /* Attribute in response */ + ipp_status_t status; /* Status code */ /* - * Get the requested-attributes attribute, and return NULL if we don't - * have one... + * Try connecting to the printer... */ - if ((requested = ippFindAttribute(request, "requested-attributes", - IPP_TAG_KEYWORD)) == NULL) + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri); + + if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri); + return (NULL); + } + + if (!strcmp(scheme, "ipps") || port == 443) + encryption = HTTP_ENCRYPTION_ALWAYS; + else + encryption = HTTP_ENCRYPTION_IF_REQUESTED; + + if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsLastErrorString()); return (NULL); + } /* - * If the attribute contains a single "all" keyword, return NULL... + * Query the printer for its capabilities... */ - if (requested->num_values == 1 && - !strcmp(requested->values[0].string.text, "all")) - return (NULL); + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Connected to %s:%d, sending Get-Printer-Attributes request...", printer->name, host, port); + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippSetVersion(request, 2, 0); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all"); + + response = cupsDoRequest(http, request, resource); + status = cupsLastError(); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString()); + + if (status == IPP_STATUS_ERROR_BAD_REQUEST || status == IPP_STATUS_ERROR_VERSION_NOT_SUPPORTED) + { + /* + * Try request using IPP/1.1, in case we are talking to an old CUPS server or + * printer... + */ + + ippDelete(response); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Re-sending Get-Printer-Attributes request using IPP/1.1...", printer->name); + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + ippSetVersion(request, 1, 1); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, printer->device_uri); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", NULL, "all"); + + response = cupsDoRequest(http, request, resource); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: IPP/1.1 Get-Printer-Attributes returned %s (%s)", printer->name, ippErrorString(cupsLastError()), cupsLastErrorString()); + } + + // TODO: Grab printer icon file... + httpClose(http); /* - * Create an array using "strcmp" as the comparison function... - */ - - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - - for (i = 0; i < requested->num_values; i ++) - { - value = requested->values[i].string.text; - - if (!strcmp(value, "job-template")) - { - cupsArrayAdd(ra, "copies"); - cupsArrayAdd(ra, "copies-default"); - cupsArrayAdd(ra, "copies-supported"); - cupsArrayAdd(ra, "finishings"); - cupsArrayAdd(ra, "finishings-default"); - cupsArrayAdd(ra, "finishings-supported"); - cupsArrayAdd(ra, "job-hold-until"); - cupsArrayAdd(ra, "job-hold-until-default"); - cupsArrayAdd(ra, "job-hold-until-supported"); - cupsArrayAdd(ra, "job-priority"); - cupsArrayAdd(ra, "job-priority-default"); - cupsArrayAdd(ra, "job-priority-supported"); - cupsArrayAdd(ra, "job-sheets"); - cupsArrayAdd(ra, "job-sheets-default"); - cupsArrayAdd(ra, "job-sheets-supported"); - cupsArrayAdd(ra, "media"); - cupsArrayAdd(ra, "media-default"); - cupsArrayAdd(ra, "media-supported"); - cupsArrayAdd(ra, "multiple-document-handling"); - cupsArrayAdd(ra, "multiple-document-handling-default"); - cupsArrayAdd(ra, "multiple-document-handling-supported"); - cupsArrayAdd(ra, "number-up"); - cupsArrayAdd(ra, "number-up-default"); - cupsArrayAdd(ra, "number-up-supported"); - cupsArrayAdd(ra, "orientation-requested"); - cupsArrayAdd(ra, "orientation-requested-default"); - cupsArrayAdd(ra, "orientation-requested-supported"); - cupsArrayAdd(ra, "page-ranges"); - cupsArrayAdd(ra, "page-ranges-supported"); - cupsArrayAdd(ra, "printer-resolution"); - cupsArrayAdd(ra, "printer-resolution-default"); - cupsArrayAdd(ra, "printer-resolution-supported"); - cupsArrayAdd(ra, "print-quality"); - cupsArrayAdd(ra, "print-quality-default"); - cupsArrayAdd(ra, "print-quality-supported"); - cupsArrayAdd(ra, "sides"); - cupsArrayAdd(ra, "sides-default"); - cupsArrayAdd(ra, "sides-supported"); - } - else if (!strcmp(value, "job-description")) - { - cupsArrayAdd(ra, "date-time-at-completed"); - cupsArrayAdd(ra, "date-time-at-creation"); - cupsArrayAdd(ra, "date-time-at-processing"); - cupsArrayAdd(ra, "job-detailed-status-message"); - cupsArrayAdd(ra, "job-document-access-errors"); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-impressions"); - cupsArrayAdd(ra, "job-impressions-completed"); - cupsArrayAdd(ra, "job-k-octets"); - cupsArrayAdd(ra, "job-k-octets-processed"); - cupsArrayAdd(ra, "job-media-progress"); - cupsArrayAdd(ra, "job-media-sheets"); - cupsArrayAdd(ra, "job-media-sheets-completed"); - cupsArrayAdd(ra, "job-message-from-operator"); - cupsArrayAdd(ra, "job-more-info"); - cupsArrayAdd(ra, "job-name"); - cupsArrayAdd(ra, "job-originating-user-name"); - cupsArrayAdd(ra, "job-printer-up-time"); - cupsArrayAdd(ra, "job-printer-uri"); - cupsArrayAdd(ra, "job-state"); - cupsArrayAdd(ra, "job-state-message"); - cupsArrayAdd(ra, "job-state-reasons"); - cupsArrayAdd(ra, "job-uri"); - cupsArrayAdd(ra, "number-of-documents"); - cupsArrayAdd(ra, "number-of-intervening-jobs"); - cupsArrayAdd(ra, "output-device-assigned"); - cupsArrayAdd(ra, "time-at-completed"); - cupsArrayAdd(ra, "time-at-creation"); - cupsArrayAdd(ra, "time-at-processing"); - } - else if (!strcmp(value, "printer-description")) - { - cupsArrayAdd(ra, "charset-configured"); - cupsArrayAdd(ra, "charset-supported"); - cupsArrayAdd(ra, "color-supported"); - cupsArrayAdd(ra, "compression-supported"); - cupsArrayAdd(ra, "document-format-default"); - cupsArrayAdd(ra, "document-format-supported"); - cupsArrayAdd(ra, "generated-natural-language-supported"); - cupsArrayAdd(ra, "ipp-versions-supported"); - cupsArrayAdd(ra, "job-impressions-supported"); - cupsArrayAdd(ra, "job-k-octets-supported"); - cupsArrayAdd(ra, "job-media-sheets-supported"); - cupsArrayAdd(ra, "job-settable-attributes-supported"); - cupsArrayAdd(ra, "multiple-document-jobs-supported"); - cupsArrayAdd(ra, "multiple-operation-time-out"); - cupsArrayAdd(ra, "natural-language-configured"); - cupsArrayAdd(ra, "notify-attributes-supported"); - cupsArrayAdd(ra, "notify-lease-duration-default"); - cupsArrayAdd(ra, "notify-lease-duration-supported"); - cupsArrayAdd(ra, "notify-max-events-supported"); - cupsArrayAdd(ra, "notify-events-default"); - cupsArrayAdd(ra, "notify-events-supported"); - cupsArrayAdd(ra, "notify-pull-method-supported"); - cupsArrayAdd(ra, "notify-schemes-supported"); - cupsArrayAdd(ra, "operations-supported"); - cupsArrayAdd(ra, "pages-per-minute"); - cupsArrayAdd(ra, "pages-per-minute-color"); - cupsArrayAdd(ra, "pdl-override-supported"); - cupsArrayAdd(ra, "printer-alert"); - cupsArrayAdd(ra, "printer-alert-description"); - cupsArrayAdd(ra, "printer-commands"); - cupsArrayAdd(ra, "printer-current-time"); - cupsArrayAdd(ra, "printer-driver-installer"); - cupsArrayAdd(ra, "printer-dns-sd-name"); - cupsArrayAdd(ra, "printer-info"); - cupsArrayAdd(ra, "printer-is-accepting-jobs"); - cupsArrayAdd(ra, "printer-location"); - cupsArrayAdd(ra, "printer-make-and-model"); - cupsArrayAdd(ra, "printer-message-from-operator"); - cupsArrayAdd(ra, "printer-more-info"); - cupsArrayAdd(ra, "printer-more-info-manufacturer"); - cupsArrayAdd(ra, "printer-name"); - cupsArrayAdd(ra, "printer-state"); - cupsArrayAdd(ra, "printer-state-message"); - cupsArrayAdd(ra, "printer-state-reasons"); - cupsArrayAdd(ra, "printer-settable-attributes-supported"); - cupsArrayAdd(ra, "printer-type"); - cupsArrayAdd(ra, "printer-up-time"); - cupsArrayAdd(ra, "printer-uri-supported"); - cupsArrayAdd(ra, "queued-job-count"); - cupsArrayAdd(ra, "reference-uri-schemes-supported"); - cupsArrayAdd(ra, "uri-authentication-supported"); - cupsArrayAdd(ra, "uri-security-supported"); - } - else if (!strcmp(value, "printer-defaults")) - { - char *name; /* Option name */ - - - for (name = (char *)cupsArrayFirst(CommonDefaults); - name; - name = (char *)cupsArrayNext(CommonDefaults)) - cupsArrayAdd(ra, name); + * Write the PPD for the queue... + */ + + if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response)) + { + _cupsRWLockWrite(&printer->lock); + + if ((!printer->info || !*(printer->info)) && (attr = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&printer->info, ippGetString(attr, 0, NULL)); + + if ((!printer->location || !*(printer->location)) && (attr = ippFindAttribute(response, "printer-location", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&printer->location, ippGetString(attr, 0, NULL)); + + if ((!printer->geo_location || !*(printer->geo_location)) && (attr = ippFindAttribute(response, "printer-geo-location", IPP_TAG_URI)) != NULL) + cupsdSetString(&printer->geo_location, ippGetString(attr, 0, NULL)); + + _cupsRWUnlock(&printer->lock); + + if ((from = cupsFileOpen(fromppd, "r")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to read generated PPD: %s", printer->name, strerror(errno)); + return (NULL); + } + + snprintf(toppd, sizeof(toppd), "%s/ppd/%s.ppd", ServerRoot, printer->name); + if ((to = cupsdCreateConfFile(toppd, ConfigFilePerm)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to create PPD for printer: %s", printer->name, strerror(errno)); + cupsFileClose(from); + return (NULL); } - else if (!strcmp(value, "subscription-template")) + + while (cupsFileGets(from, line, sizeof(line))) + cupsFilePrintf(to, "%s\n", line); + + cupsFileClose(from); + if (!cupsdCloseCreatedConfFile(to, toppd)) { - cupsArrayAdd(ra, "notify-attributes"); - cupsArrayAdd(ra, "notify-charset"); - cupsArrayAdd(ra, "notify-events"); - cupsArrayAdd(ra, "notify-lease-duration"); - cupsArrayAdd(ra, "notify-natural-language"); - cupsArrayAdd(ra, "notify-pull-method"); - cupsArrayAdd(ra, "notify-recipient-uri"); - cupsArrayAdd(ra, "notify-time-interval"); - cupsArrayAdd(ra, "notify-user-data"); + printer->config_time = time(NULL); + printer->state = IPP_PSTATE_IDLE; + printer->accepting = 1; + + cupsdSetPrinterAttrs(printer); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name); + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" is now available.", printer->name); } + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed: %s", printer->name, cupsLastErrorString()); + + return (NULL); +} + + +/* + * 'create_local_printer()' - Create a local (temporary) print queue. + */ + +static void +create_local_printer( + cupsd_client_t *con) /* I - Client connection */ +{ + ipp_attribute_t *device_uri, /* device-uri attribute */ + *printer_geo_location, /* printer-geo-location attribute */ + *printer_info, /* printer-info attribute */ + *printer_location, /* printer-location attribute */ + *printer_name; /* printer-name attribute */ + cupsd_printer_t *printer; /* New printer */ + http_status_t status; /* Policy status */ + char name[128], /* Sanitized printer name */ + *nameptr, /* Pointer into name */ + uri[1024]; /* printer-uri-supported value */ + const char *ptr; /* Pointer into attribute value */ + + + /* + * Require local access to create a local printer... + */ + + if (!httpAddrLocalhost(httpGetAddress(con->http))) + { + send_ipp_status(con, IPP_STATUS_ERROR_FORBIDDEN, _("Only local users can create a local printer.")); + return; + } + + /* + * Check any other policy limits... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status, NULL); + return; + } + + /* + * Grab needed attributes... + */ + + if ((printer_name = ippFindAttribute(con->request, "printer-name", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(printer_name) != IPP_TAG_PRINTER || ippGetValueTag(printer_name) != IPP_TAG_NAME) + { + if (!printer_name) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "printer-name"); + else if (ippGetGroupTag(printer_name) != IPP_TAG_PRINTER) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "printer-name"); + else + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "printer-name"); + + return; + } + + for (nameptr = name, ptr = ippGetString(printer_name, 0, NULL); *ptr && nameptr < (name + sizeof(name) - 1); ptr ++) + { + /* + * Sanitize the printer name... + */ + + if (_cups_isalnum(*ptr)) + *nameptr++ = *ptr; + else if (nameptr == name || nameptr[-1] != '_') + *nameptr++ = '_'; + } + + *nameptr = '\0'; + + if ((device_uri = ippFindAttribute(con->request, "device-uri", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(device_uri) != IPP_TAG_PRINTER || ippGetValueTag(device_uri) != IPP_TAG_URI) + { + if (!device_uri) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "device-uri"); + else if (ippGetGroupTag(device_uri) != IPP_TAG_PRINTER) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "device-uri"); else - cupsArrayAdd(ra, value); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "device-uri"); + + return; + } + + printer_geo_location = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI); + printer_info = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT); + printer_location = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT); + + /* + * See if the printer already exists... + */ + + if ((printer = cupsdFindDest(name)) != NULL) + { + send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name); + goto add_printer_attributes; + } + + /* + * Create the printer... + */ + + if ((printer = cupsdAddPrinter(name)) == NULL) + { + send_ipp_status(con, IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer.")); + return; + } + + printer->shared = 0; + printer->temporary = 1; + + cupsdSetDeviceURI(printer, ippGetString(device_uri, 0, NULL)); + + if (printer_geo_location) + cupsdSetString(&printer->geo_location, ippGetString(printer_geo_location, 0, NULL)); + if (printer_info) + cupsdSetString(&printer->info, ippGetString(printer_info, 0, NULL)); + if (printer_location) + cupsdSetString(&printer->location, ippGetString(printer_location, 0, NULL)); + + cupsdSetPrinterAttrs(printer); + + /* + * Run a background thread to create the PPD... + */ + + _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer); + + /* + * Return printer attributes... + */ + + send_ipp_status(con, IPP_STATUS_OK, _("Local printer created.")); + + add_printer_attributes: + + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state); + add_printer_state_reasons(con, printer); + + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri); +} + + +/* + * 'create_requested_array()' - Create an array for the requested-attributes. + */ + +static cups_array_t * /* O - Array of attributes or NULL */ +create_requested_array(ipp_t *request) /* I - IPP request */ +{ + cups_array_t *ra; /* Requested attributes array */ + + + /* + * Create the array for standard attributes... + */ + + ra = ippCreateRequestedArray(request); + + /* + * Add CUPS defaults as needed... + */ + + if (cupsArrayFind(ra, "printer-defaults")) + { + /* + * Include user-set defaults... + */ + + char *name; /* Option name */ + + cupsArrayRemove(ra, "printer-defaults"); + + for (name = (char *)cupsArrayFirst(CommonDefaults); + name; + name = (char *)cupsArrayNext(CommonDefaults)) + if (!cupsArrayFind(ra, name)) + cupsArrayAdd(ra, name); } return (ra); @@ -6564,11 +5563,11 @@ create_requested_array(ipp_t *request) /* I - IPP request */ /* - * 'create_subscription()' - Create a notification subscription. + * 'create_subscriptions()' - Create one or more notification subscriptions. */ static void -create_subscription( +create_subscriptions( cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { @@ -6616,9 +5615,7 @@ create_subscription( * Is the destination valid? */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdCreateSubscription(con=%p(%d), uri=\"%s\")", - con, con->http.fd, uri->values[0].string.text); + cupsdLogMessage(CUPSD_LOG_DEBUG, "create_subscriptions(con=%p(%d), uri=\"%s\")", con, con->number, uri->values[0].string.text); httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, sizeof(scheme), userpass, sizeof(userpass), host, @@ -6753,7 +5750,7 @@ create_subscription( snprintf(notifier, sizeof(notifier), "%s/notifier/%s", ServerBin, scheme); - if (access(notifier, X_OK)) + if (access(notifier, X_OK) || !strcmp(scheme, ".") || !strcmp(scheme, "..")) { send_ipp_status(con, IPP_NOT_POSSIBLE, _("notify-recipient-uri URI \"%s\" uses unknown " @@ -6843,7 +5840,26 @@ create_subscription( } if (recipient) + { cupsdLogMessage(CUPSD_LOG_DEBUG, "recipient=\"%s\"", recipient); + + + if (!strncmp(recipient, "mailto:", 7) && user_data) + { + char temp[64]; /* Temporary string */ + + memcpy(temp, user_data->values[0].unknown.data, (size_t)user_data->values[0].unknown.length); + temp[user_data->values[0].unknown.length] = '\0'; + + if (httpSeparateURI(HTTP_URI_CODING_ALL, temp, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_OK) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad notify-user-data \"%s\"."), temp); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES); + return; + } + } + } + if (pullmethod) cupsdLogMessage(CUPSD_LOG_DEBUG, "pullmethod=\"%s\"", pullmethod); cupsdLogMessage(CUPSD_LOG_DEBUG, "notify-lease-duration=%d", lease); @@ -6869,7 +5885,7 @@ create_subscription( if (MaxLeaseDuration && (lease == 0 || lease > MaxLeaseDuration)) { cupsdLogMessage(CUPSD_LOG_INFO, - "create_subscription: Limiting notify-lease-duration to " + "create_subscriptions: Limiting notify-lease-duration to " "%d seconds.", MaxLeaseDuration); lease = MaxLeaseDuration; @@ -6915,7 +5931,7 @@ create_subscription( { sub->user_data_len = user_data->values[0].unknown.length; memcpy(sub->user_data, user_data->values[0].unknown.data, - sub->user_data_len); + (size_t)sub->user_data_len); } ippAddSeparator(con->response); @@ -6944,10 +5960,11 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ cups_ptype_t dtype; /* Destination type (printer/class) */ cupsd_printer_t *printer; /* Printer/class */ char filename[1024]; /* Script/PPD filename */ + int temporary; /* Temporary queue? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Do we have a valid URI? @@ -6995,11 +6012,10 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ * Remove any old PPD or script files... */ - snprintf(filename, sizeof(filename), "%s/interfaces/%s", ServerRoot, + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, printer->name); unlink(filename); - - snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd.O", ServerRoot, printer->name); unlink(filename); @@ -7009,13 +6025,13 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name); unlink(filename); -#ifdef __APPLE__ /* * Unregister color profiles... */ - apple_unregister_profiles(printer); -#endif /* __APPLE__ */ + cupsdUnregisterColor(printer); + + temporary = printer->temporary; if (dtype & CUPS_PRINTER_CLASS) { @@ -7023,20 +6039,23 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ printer->name, get_username(con)); cupsdDeletePrinter(printer, 0); - cupsdMarkDirty(CUPSD_DIRTY_CLASSES); + if (!temporary) + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); } else { cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".", printer->name, get_username(con)); - if (cupsdDeletePrinter(printer, 0)) + if (cupsdDeletePrinter(printer, 0) && !temporary) cupsdMarkDirty(CUPSD_DIRTY_CLASSES); - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + if (!temporary) + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + if (!temporary) + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); /* * Return with no errors... @@ -7057,7 +6076,7 @@ get_default(cupsd_client_t *con) /* I - Client connection */ cups_array_t *ra; /* Requested attributes array */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->http.fd); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->number); /* * Check policy... @@ -7107,7 +6126,7 @@ get_devices(cupsd_client_t *con) /* I - Client connection */ /* String for included schemes */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->http.fd); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->number); /* * Check policy... @@ -7201,7 +6220,7 @@ get_document(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_document(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -7348,7 +6367,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -7462,19 +6481,23 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ int port; /* Port portion of URI */ int job_comparison; /* Job comparison */ ipp_jstate_t job_state; /* job-state value */ - int first_job_id; /* First job ID */ - int limit; /* Maximum number of jobs to return */ - int count; /* Number of jobs that match */ + int first_job_id = 1, /* First job ID */ + first_index = 1, /* First index */ + limit = 0, /* Maximum number of jobs to return */ + count, /* Number of jobs that match */ + need_load_job = 0; /* Do we need to load the job? */ + const char *job_attr; /* Job attribute requested */ ipp_attribute_t *job_ids; /* job-ids attribute */ cupsd_job_t *job; /* Current job pointer */ cupsd_printer_t *printer; /* Printer */ cups_array_t *list; /* Which job list... */ + int delete_list = 0; /* Delete the list afterwards? */ cups_array_t *ra, /* Requested attributes array */ *exclude; /* Private attributes array */ cupsd_policy_t *policy; /* Current policy */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->number, uri->values[0].string.text); /* @@ -7562,19 +6585,21 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ { job_comparison = -1; job_state = IPP_JOB_STOPPED; - list = Jobs; + list = ActiveJobs; } else if (!strcmp(attr->values[0].string.text, "completed")) { job_comparison = 1; job_state = IPP_JOB_CANCELED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "aborted")) { job_comparison = 0; job_state = IPP_JOB_ABORTED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "all")) { @@ -7586,7 +6611,8 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ { job_comparison = 0; job_state = IPP_JOB_CANCELED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "pending")) { @@ -7626,24 +6652,32 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ * See if they want to limit the number of jobs reported... */ - if ((attr = ippFindAttribute(con->request, "limit", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL) + { + if (job_ids) + { + send_ipp_status(con, IPP_CONFLICT, + _("The %s attribute cannot be provided with job-ids."), + "limit"); + return; + } + + limit = attr->values[0].integer; + } + + if ((attr = ippFindAttribute(con->request, "first-index", IPP_TAG_INTEGER)) != NULL) { if (job_ids) { send_ipp_status(con, IPP_CONFLICT, _("The %s attribute cannot be provided with job-ids."), - "limit"); + "first-index"); return; } - limit = attr->values[0].integer; + first_index = attr->values[0].integer; } - else - limit = 0; - - if ((attr = ippFindAttribute(con->request, "first-job-id", - IPP_TAG_INTEGER)) != NULL) + else if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL) { if (job_ids) { @@ -7655,15 +6689,12 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ first_job_id = attr->values[0].integer; } - else - first_job_id = 1; /* * See if we only want to see jobs for a specific user... */ - if ((attr = ippFindAttribute(con->request, "my-jobs", - IPP_TAG_BOOLEAN)) != NULL && job_ids) + if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && job_ids) { send_ipp_status(con, IPP_CONFLICT, _("The %s attribute cannot be provided with job-ids."), @@ -7675,17 +6706,42 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ else username[0] = '\0'; - if ((ra = create_requested_array(con->request)) == NULL && - !ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD)) + ra = create_requested_array(con->request); + for (job_attr = (char *)cupsArrayFirst(ra); job_attr; job_attr = (char *)cupsArrayNext(ra)) + if (strcmp(job_attr, "job-id") && + strcmp(job_attr, "job-k-octets") && + strcmp(job_attr, "job-media-progress") && + strcmp(job_attr, "job-more-info") && + strcmp(job_attr, "job-name") && + strcmp(job_attr, "job-originating-user-name") && + strcmp(job_attr, "job-preserved") && + strcmp(job_attr, "job-printer-up-time") && + strcmp(job_attr, "job-printer-uri") && + strcmp(job_attr, "job-state") && + strcmp(job_attr, "job-state-reasons") && + strcmp(job_attr, "job-uri") && + strcmp(job_attr, "time-at-completed") && + strcmp(job_attr, "time-at-creation") && + strcmp(job_attr, "number-of-documents")) + { + need_load_job = 1; + break; + } + + if (need_load_job && (limit == 0 || limit > 500) && (list == Jobs || delete_list)) { /* - * IPP conformance - Get-Jobs has a default requested-attributes value of - * "job-id" and "job-uri". + * Limit expensive Get-Jobs for job history to 500 jobs... */ - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-uri"); + ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "limit", 500); + + if (limit) + ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "limit", limit); + + limit = 500; + + cupsdLogClient(con, CUPSD_LOG_INFO, "Limiting Get-Jobs response to %d jobs.", limit); } /* @@ -7713,13 +6769,15 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ { job = cupsdFindJob(job_ids->values[i].integer); - cupsdLoadJob(job); - - if (!job->attrs) + if (need_load_job && !job->attrs) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", - job->id); - continue; + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } } if (i > 0) @@ -7735,9 +6793,12 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ } else { - for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list); - (limit <= 0 || count < limit) && job; - job = (cupsd_job_t *)cupsArrayNext(list)) + if (first_index > 1) + job = (cupsd_job_t *)cupsArrayIndex(list, first_index - 1); + else + job = (cupsd_job_t *)cupsArrayFirst(list); + + for (count = 0; (limit <= 0 || count < limit) && job; job = (cupsd_job_t *)cupsArrayNext(list)) { /* * Filter out jobs that don't match... @@ -7769,16 +6830,18 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ if (job->id < first_job_id) continue; - cupsdLoadJob(job); - - if (!job->attrs) + if (need_load_job && !job->attrs) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", - job->id); - continue; + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } } - if (username[0] && strcasecmp(username, job->username)) + if (username[0] && _cups_strcasecmp(username, job->username)) continue; if (count > 0) @@ -7799,6 +6862,9 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ cupsArrayDelete(ra); + if (delete_list) + cupsArrayDelete(list); + con->response->request.status.status_code = IPP_OK; } @@ -7820,7 +6886,7 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_notifications(con=%p[%d])", - con, con->http.fd); + con, con->number); /* * Get subscription attributes... @@ -7954,18 +7020,19 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con, - con->http.fd, uri, uri->name, uri->values[0].string.text); + con->number, uri, uri->name, uri->values[0].string.text); - if (!strcmp(uri->name, "ppd-name")) + if (!strcmp(ippGetName(uri), "ppd-name")) { /* * Return a PPD file from cups-driverd... */ - char command[1024], /* cups-driverd command */ - options[1024], /* Options to pass to command */ - ppd_name[1024]; /* ppd-name */ - + const char *ppd_name = ippGetString(uri, 0, NULL); + /* ppd-name value */ + char command[1024], /* cups-driverd command */ + options[1024], /* Options to pass to command */ + oppd_name[1024]; /* Escaped ppd-name */ /* * Check policy... @@ -7977,14 +7044,23 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ return; } + /* + * Check ppd-name value... + */ + + if (strstr(ppd_name, "../")) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Invalid ppd-name value.")); + return; + } + /* * Run cups-driverd command with the given options... */ snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin); - url_encode_string(uri->values[0].string.text, ppd_name, sizeof(ppd_name)); - snprintf(options, sizeof(options), "get+%d+%s", - con->request->request.op.request_id, ppd_name); + url_encode_string(ppd_name, oppd_name, sizeof(oppd_name)); + snprintf(options, sizeof(options), "get+%d+%s", ippGetRequestId(con->request), oppd_name); if (cupsdSendCommand(con, command, options, 0)) { @@ -8002,17 +7078,14 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ * went wrong... */ - send_ipp_status(con, IPP_INTERNAL_ERROR, - _("cups-driverd failed to execute.")); + send_ipp_status(con, IPP_INTERNAL_ERROR, _("cups-driverd failed to execute.")); } } - else if (!strcmp(uri->name, "printer-uri") && - cupsdValidateDest(uri->values[0].string.text, &dtype, &dest)) + else if (!strcmp(ippGetName(uri), "printer-uri") && cupsdValidateDest(ippGetString(uri, 0, NULL), &dtype, &dest)) { int i; /* Looping var */ char filename[1024]; /* PPD filename */ - /* * Check policy... */ @@ -8027,24 +7100,20 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ * See if we need the PPD for a class or remote printer... */ - snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, - dest->name); + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest->name); if ((dtype & CUPS_PRINTER_REMOTE) && access(filename, 0)) { - con->response->request.status.status_code = CUPS_SEE_OTHER; - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, - "printer-uri", NULL, dest->uri); + send_ipp_status(con, IPP_STATUS_CUPS_SEE_OTHER, _("See remote printer.")); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, dest->uri); return; } - else if (dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + else if (dtype & CUPS_PRINTER_CLASS) { for (i = 0; i < dest->num_printers; i ++) - if (!(dest->printers[i]->type & - (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))) + if (!(dest->printers[i]->type & CUPS_PRINTER_CLASS)) { - snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, - dest->printers[i]->name); + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, dest->printers[i]->name); if (!access(filename, 0)) break; @@ -8054,9 +7123,8 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ dest = dest->printers[i]; else { - con->response->request.status.status_code = CUPS_SEE_OTHER; - ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, - "printer-uri", NULL, dest->printers[0]->uri); + send_ipp_status(con, IPP_STATUS_CUPS_SEE_OTHER, _("See remote printer.")); + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, dest->printers[0]->uri); return; } } @@ -8067,9 +7135,7 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ if ((con->file = open(filename, O_RDONLY)) < 0) { - send_ipp_status(con, IPP_NOT_FOUND, - _("The PPD file \"%s\" could not be opened: %s"), - uri->values[0].string.text, strerror(errno)); + send_ipp_status(con, IPP_STATUS_ERROR_NOT_FOUND, _("The PPD file \"%s\" could not be opened: %s"), ippGetString(uri, 0, NULL), strerror(errno)); return; } @@ -8077,12 +7143,10 @@ get_ppd(cupsd_client_t *con, /* I - Client connection */ con->pipe_pid = 0; - con->response->request.status.status_code = IPP_OK; + ippSetStatusCode(con->response, IPP_STATUS_OK); } else - send_ipp_status(con, IPP_NOT_FOUND, - _("The PPD file \"%s\" could not be found."), - uri->values[0].string.text); + send_ipp_status(con, IPP_STATUS_ERROR_NOT_FOUND, _("The PPD file \"%s\" could not be found."), ippGetString(uri, 0, NULL)); } @@ -8128,7 +7192,7 @@ get_ppds(cupsd_client_t *con) /* I - Client connection */ /* String for included schemes */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->number); /* * Check policy... @@ -8273,7 +7337,7 @@ get_printer_attrs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -8329,7 +7393,7 @@ get_printer_supported( cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_supported(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -8360,10 +7424,16 @@ get_printer_supported( * Return a list of attributes that can be set via Set-Printer-Attributes. */ + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE, + "printer-geo-location", 0); ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE, "printer-info", 0); ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE, "printer-location", 0); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE, + "printer-organization", 0); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE, + "printer-organizational-unit", 0); con->response->request.status.status_code = IPP_OK; } @@ -8381,8 +7451,9 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* Current attribute */ int limit; /* Max number of printers to return */ int count; /* Number of printers that match */ + int printer_id; /* Printer we are interested in */ cupsd_printer_t *printer; /* Current printer pointer */ - int printer_type, /* printer-type attribute */ + cups_ptype_t printer_type, /* printer-type attribute */ printer_mask; /* printer-type-mask attribute */ char *location; /* Location string */ const char *username; /* Current user */ @@ -8392,7 +7463,7 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con, - con->http.fd, type); + con->number, type); /* * Check policy... @@ -8434,17 +7505,28 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ * Support filtering... */ + if ((attr = ippFindAttribute(con->request, "printer-id", IPP_TAG_INTEGER)) != NULL) + { + if ((printer_id = ippGetInteger(attr, 0)) <= 0) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad \"printer-id\" value %d."), printer_id); + return; + } + } + else + printer_id = 0; + if ((attr = ippFindAttribute(con->request, "printer-type", IPP_TAG_ENUM)) != NULL) - printer_type = attr->values[0].integer; + printer_type = (cups_ptype_t)attr->values[0].integer; else - printer_type = 0; + printer_type = (cups_ptype_t)0; if ((attr = ippFindAttribute(con->request, "printer-type-mask", IPP_TAG_ENUM)) != NULL) - printer_mask = attr->values[0].integer; + printer_mask = (cups_ptype_t)attr->values[0].integer; else - printer_mask = 0; + printer_mask = (cups_ptype_t)0; local = httpAddrLocalhost(&(con->clientaddr)); @@ -8483,20 +7565,14 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ if (!local && !printer->shared) continue; + if (printer_id && printer->printer_id != printer_id) + continue; + if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) && (printer->type & printer_mask) == printer_type && (!location || - (printer->location && !strcasecmp(printer->location, location)))) + (printer->location && !_cups_strcasecmp(printer->location, location)))) { - /* - * If HideImplicitMembers is enabled, see if this printer or class - * is a member of an implicit class... - */ - - if (ImplicitClasses && HideImplicitMembers && - printer->in_implicit_class) - continue; - /* * If a username is specified, see if it is allowed or denied * access... @@ -8547,7 +7623,13 @@ get_subscription_attrs( cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_subscription_attrs(con=%p[%d], sub_id=%d)", - con, con->http.fd, sub_id); + con, con->number, sub_id); + + /* + * Expire subscriptions as needed... + */ + + cupsdExpireSubscriptions(NULL, NULL); /* * Is the subscription ID valid? @@ -8628,7 +7710,7 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_subscriptions(con=%p[%d], uri=%s)", - con, con->http.fd, uri->values[0].string.text); + con, con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -8698,6 +7780,12 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ return; } + /* + * Expire subscriptions as needed... + */ + + cupsdExpireSubscriptions(NULL, NULL); + /* * Copy the subscription attributes to the response using the * requested-attributes attribute that may be provided by the client. @@ -8726,7 +7814,7 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ sub; sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) if ((!printer || sub->dest == printer) && (!job || sub->job == job) && - (!username[0] || !strcasecmp(username, sub->owner))) + (!username[0] || !_cups_strcasecmp(username, sub->owner))) { ippAddSeparator(con->response); @@ -8789,7 +7877,7 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job; /* Job information */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", con, con->http.fd, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", con, con->number, uri->values[0].string.text); /* @@ -8863,16 +7951,35 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ } /* - * Hold the job and return... + * See if the job is in a state that allows holding... */ - if ((attr = ippFindAttribute(con->request, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME); + if (job->state_value > IPP_JOB_STOPPED) + { + /* + * Return a "not-possible" error... + */ - if (attr) + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job #%d is finished and cannot be altered."), + job->id); + return; + } + + /* + * Hold the job and return... + */ + + if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL) { - when = attr->values[0].string.text; + if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr)) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value.")); + ippCopyAttribute(con->response, attr, 0); + return; + } + + when = ippGetString(attr, 0, NULL); cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job, "Job job-hold-until value changed by user."); @@ -8902,7 +8009,7 @@ hold_new_jobs(cupsd_client_t *con, /* I - Connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -8978,7 +8085,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ *dprinter; /* Destination printer */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", con, con->http.fd, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", con, con->number, uri->values[0].string.text); /* @@ -9178,7 +8285,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ * completed... */ - if (strcasecmp(job->dest, src) || + if (_cups_strcasecmp(job->dest, src) || job->state_value > IPP_JOB_STOPPED) continue; @@ -9291,6 +8398,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { ipp_attribute_t *attr; /* Current attribute */ + ipp_attribute_t *doc_name; /* document-name attribute */ ipp_attribute_t *format; /* Document-format attribute */ const char *default_format; /* document-format-default value */ cupsd_job_t *job; /* New job */ @@ -9306,7 +8414,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ int compression; /* Document compression */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->http.fd, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->number, uri->values[0].string.text); /* @@ -9368,6 +8476,10 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Is it a format we support? */ + doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME); + if (doc_name) + ippSetName(con->request, &doc_name, "document-name-supplied"); + if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) { @@ -9375,7 +8487,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Grab format from client... */ - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", super, + if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, @@ -9383,6 +8495,8 @@ print_job(cupsd_client_t *con, /* I - Client connection */ format->values[0].string.text); return; } + + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, ippGetString(format, 0, NULL)); } else if ((default_format = cupsGetOption("document-format", printer->num_options, @@ -9392,7 +8506,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Use default document format... */ - if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2) + if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."), @@ -9406,8 +8520,8 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Auto-type it! */ - strcpy(super, "application"); - strcpy(type, "octet-stream"); + strlcpy(super, "application", sizeof(super)); + strlcpy(type, "octet-stream", sizeof(type)); } if (!strcmp(super, "application") && !strcmp(type, "octet-stream")) @@ -9416,12 +8530,9 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Auto-type the file... */ - ipp_attribute_t *doc_name; /* document-name attribute */ - - cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job ???] Auto-typing file..."); - doc_name = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME); + filetype = mimeFileType(MimeDatabase, con->filename, doc_name ? doc_name->values[0].string.text : NULL, &compression); @@ -9431,6 +8542,9 @@ print_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_INFO, "[Job ???] Request file type is %s/%s.", filetype->super, filetype->type); + + snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, filetype->type); + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, mimetype); } else filetype = mimeType(MimeDatabase, super, type); @@ -9448,11 +8562,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ filetype->type); if (format) - { - _cupsStrFree(format->values[0].string.text); - - format->values[0].string.text = _cupsStrAlloc(mimetype); - } + ippSetString(con->request, &format, 0, mimetype); else ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format", NULL, mimetype); @@ -9477,9 +8587,9 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * Read any embedded job ticket info from PS files... */ - if (!strcasecmp(filetype->super, "application") && - (!strcasecmp(filetype->type, "postscript") || - !strcasecmp(filetype->type, "pdf"))) + if (!_cups_strcasecmp(filetype->super, "application") && + (!_cups_strcasecmp(filetype->type, "postscript") || + !_cups_strcasecmp(filetype->type, "pdf"))) read_job_ticket(con); /* @@ -9500,8 +8610,9 @@ print_job(cupsd_client_t *con, /* I - Client connection */ cupsdUpdateQuota(printer, job->username, 0, kbytes); - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + job->koctets += kbytes; + + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer += kbytes; /* @@ -9511,9 +8622,15 @@ print_job(cupsd_client_t *con, /* I - Client connection */ if (add_file(con, job, filetype, compression)) return; - snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, - job->num_files); - rename(con->filename, filename); + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, job->num_files); + if (rename(con->filename, filename)) + { + cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to rename job document file \"%s\": %s", filename, strerror(errno)); + + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to rename job document file.")); + return; + } + cupsdClearString(&con->filename); /* @@ -9672,12 +8789,17 @@ read_job_ticket(cupsd_client_t *con) /* I - Client connection */ if (attr->group_tag != IPP_TAG_JOB || !attr->name) continue; - if (!strcmp(attr->name, "job-originating-host-name") || - !strcmp(attr->name, "job-originating-user-name") || + if (!strncmp(attr->name, "date-time-at-", 13) || + !strcmp(attr->name, "job-impressions-completed") || !strcmp(attr->name, "job-media-sheets-completed") || - !strcmp(attr->name, "job-k-octets") || + !strncmp(attr->name, "job-k-octets", 12) || !strcmp(attr->name, "job-id") || + !strcmp(attr->name, "job-originating-host-name") || + !strcmp(attr->name, "job-originating-user-name") || + !strcmp(attr->name, "job-pages-completed") || + !strcmp(attr->name, "job-printer-uri") || !strncmp(attr->name, "job-state", 9) || + !strcmp(attr->name, "job-uri") || !strncmp(attr->name, "time-at-", 8)) continue; /* Read-only attrs */ @@ -9706,14 +8828,14 @@ read_job_ticket(cupsd_client_t *con) /* I - Client connection */ if (con->request->last == attr2) con->request->last = prev2; - _ippFreeAttr(attr2); + ippDeleteAttribute(NULL, attr2); } /* * Add new option by copying it... */ - copy_attribute(con->request, attr, 0); + ippCopyAttribute(con->request, attr, 0); } /* @@ -9740,7 +8862,7 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -9775,7 +8897,8 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) == NULL) - strcpy(printer->state_message, "Rejecting Jobs"); + strlcpy(printer->state_message, "Rejecting Jobs", + sizeof(printer->state_message)); else strlcpy(printer->state_message, attr->values[0].string.text, sizeof(printer->state_message)); @@ -9821,7 +8944,7 @@ release_held_new_jobs( cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -9865,6 +8988,8 @@ release_held_new_jobs( "Printer \"%s\" now printing pending/new jobs (\"%s\").", printer->name, get_username(con)); + cupsdCheckJobs(); + /* * Everything was ok, so return OK status... */ @@ -9892,7 +9017,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -9987,13 +9112,12 @@ release_job(cupsd_client_t *con, /* I - Client connection */ if (attr) { - _cupsStrFree(attr->values[0].string.text); - - attr->value_tag = IPP_TAG_KEYWORD; - attr->values[0].string.text = _cupsStrAlloc("no-hold"); + ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD); + ippSetString(job->attrs, &attr, 0, "no-hold"); cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job, "Job job-hold-until value changed by user."); + ippSetString(job->attrs, &job->reasons, 0, "none"); } /* @@ -10029,7 +9153,7 @@ renew_subscription( cupsdLogMessage(CUPSD_LOG_DEBUG2, "renew_subscription(con=%p[%d], sub_id=%d)", - con, con->http.fd, sub_id); + con, con->number, sub_id); /* * Is the subscription ID valid? @@ -10117,7 +9241,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -10272,7 +9396,7 @@ save_auth_info( int i; /* Looping var */ char filename[1024]; /* Job authentication filename */ cups_file_t *fp; /* Job authentication file */ - char line[2048]; /* Line for file */ + char line[65536]; /* Line for file */ cupsd_printer_t *dest; /* Destination printer/class */ @@ -10321,59 +9445,94 @@ save_auth_info( fchown(cupsFileNumber(fp), 0, 0); fchmod(cupsFileNumber(fp), 0400); + cupsFilePuts(fp, "CUPSD-AUTH-V3\n"); + + for (i = 0; + i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0])); + i ++) + cupsdClearString(job->auth_env + i); + if (auth_info && auth_info->num_values == dest->num_auth_info_required) { /* * Write 1 to 3 auth values... */ - cupsdClearString(&job->auth_username); - cupsdClearString(&job->auth_domain); - cupsdClearString(&job->auth_password); - - for (i = 0; i < auth_info->num_values; i ++) + for (i = 0; + i < auth_info->num_values && + i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0])); + i ++) { - httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text, - strlen(auth_info->values[i].string.text)); - cupsFilePrintf(fp, "%s\n", line); + if (strcmp(dest->auth_info_required[i], "negotiate")) + { + httpEncode64_2(line, sizeof(line), auth_info->values[i].string.text, (int)strlen(auth_info->values[i].string.text)); + cupsFilePutConf(fp, dest->auth_info_required[i], line); + } + else + cupsFilePutConf(fp, dest->auth_info_required[i], + auth_info->values[i].string.text); if (!strcmp(dest->auth_info_required[i], "username")) - cupsdSetStringf(&job->auth_username, "AUTH_USERNAME=%s", + cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s", auth_info->values[i].string.text); else if (!strcmp(dest->auth_info_required[i], "domain")) - cupsdSetStringf(&job->auth_domain, "AUTH_DOMAIN=%s", + cupsdSetStringf(job->auth_env + i, "AUTH_DOMAIN=%s", auth_info->values[i].string.text); else if (!strcmp(dest->auth_info_required[i], "password")) - cupsdSetStringf(&job->auth_password, "AUTH_PASSWORD=%s", + cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s", + auth_info->values[i].string.text); + else if (!strcmp(dest->auth_info_required[i], "negotiate")) + cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", auth_info->values[i].string.text); + else + i --; } } + else if (auth_info && auth_info->num_values == 2 && + dest->num_auth_info_required == 1 && + !strcmp(dest->auth_info_required[0], "negotiate")) + { + /* + * Allow fallback to username+password for Kerberized queues... + */ + + httpEncode64_2(line, sizeof(line), auth_info->values[0].string.text, (int)strlen(auth_info->values[0].string.text)); + cupsFilePutConf(fp, "username", line); + + cupsdSetStringf(job->auth_env + 0, "AUTH_USERNAME=%s", + auth_info->values[0].string.text); + + httpEncode64_2(line, sizeof(line), auth_info->values[1].string.text, (int)strlen(auth_info->values[1].string.text)); + cupsFilePutConf(fp, "password", line); + + cupsdSetStringf(job->auth_env + 1, "AUTH_PASSWORD=%s", + auth_info->values[1].string.text); + } else if (con->username[0]) { /* * Write the authenticated username... */ - httpEncode64_2(line, sizeof(line), con->username, strlen(con->username)); - cupsFilePrintf(fp, "%s\n", line); + httpEncode64_2(line, sizeof(line), con->username, (int)strlen(con->username)); + cupsFilePutConf(fp, "username", line); - cupsdSetStringf(&job->auth_username, "AUTH_USERNAME=%s", con->username); - cupsdClearString(&job->auth_domain); + cupsdSetStringf(job->auth_env + 0, "AUTH_USERNAME=%s", con->username); /* * Write the authenticated password... */ - httpEncode64_2(line, sizeof(line), con->password, strlen(con->password)); - cupsFilePrintf(fp, "%s\n", line); + httpEncode64_2(line, sizeof(line), con->password, (int)strlen(con->password)); + cupsFilePutConf(fp, "password", line); - cupsdSetStringf(&job->auth_password, "AUTH_PASSWORD=%s", con->password); + cupsdSetStringf(job->auth_env + 1, "AUTH_PASSWORD=%s", con->password); } #ifdef HAVE_GSSAPI - if (con->have_gss && con->gss_uid > 0) + if (con->gss_uid > 0) { - cupsFilePrintf(fp, "%d\n", (int)con->gss_uid); + cupsFilePrintf(fp, "uid %d\n", (int)con->gss_uid); cupsdSetStringf(&job->auth_uid, "AUTH_UID=%d", (int)con->gss_uid); } #endif /* HAVE_GSSAPI */ @@ -10434,7 +9593,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -10540,6 +9699,14 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Do we have a file to print? */ + if ((attr = ippFindAttribute(con->request, "last-document", + IPP_TAG_BOOLEAN)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Missing last-document attribute in request.")); + return; + } + if (!con->filename) { /* @@ -10547,10 +9714,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * used to close an "open" job by RFC 2911, section 3.3.2. */ - if (job->num_files > 0 && - (attr = ippFindAttribute(con->request, "last-document", - IPP_TAG_BOOLEAN)) != NULL && - attr->values[0].boolean) + if (job->num_files > 0 && attr->values[0].boolean) goto last_document; send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request.")); @@ -10561,6 +9725,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Is it a format we support? */ + cupsdLoadJob(job); + if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) { @@ -10568,13 +9734,15 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Grab format from client... */ - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", + if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."), format->values[0].string.text); return; } + + ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-supplied", NULL, ippGetString(format, 0, NULL)); } else if ((default_format = cupsGetOption("document-format", printer->num_options, @@ -10584,7 +9752,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Use default document format... */ - if (sscanf(default_format, "%15[^/]/%31[^;]", super, type) != 2) + if (sscanf(default_format, "%15[^/]/%255[^;]", super, type) != 2) { send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format-default \"%s\"."), default_format); @@ -10597,8 +9765,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * No document format attribute? Auto-type it! */ - strcpy(super, "application"); - strcpy(type, "octet-stream"); + strlcpy(super, "application", sizeof(super)); + strlcpy(type, "octet-stream", sizeof(type)); } if (!strcmp(super, "application") && !strcmp(type, "octet-stream")) @@ -10623,6 +9791,9 @@ send_document(cupsd_client_t *con, /* I - Client connection */ if (filetype) cupsdLogJob(job, CUPSD_LOG_DEBUG, "Request file type is %s/%s.", filetype->super, filetype->type); + + snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, filetype->type); + ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format-detected", NULL, mimetype); } else filetype = mimeType(MimeDatabase, super, type); @@ -10639,11 +9810,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ if ((jformat = ippFindAttribute(job->attrs, "document-format", IPP_TAG_MIMETYPE)) != NULL) - { - _cupsStrFree(jformat->values[0].string.text); - - jformat->values[0].string.text = _cupsStrAlloc(mimetype); - } + ippSetString(job->attrs, &jformat, 0, mimetype); else ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format", NULL, mimetype); @@ -10680,11 +9847,12 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Add the file to the job... */ - cupsdLoadJob(job); - if (add_file(con, job, filetype, compression)) return; + if ((attr = ippFindAttribute(con->request, "document-name", IPP_TAG_NAME)) != NULL) + ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "document-name-supplied", NULL, ippGetString(attr, 0, NULL)); + if (stat(con->filename, &fileinfo)) kbytes = 0; else @@ -10692,13 +9860,19 @@ send_document(cupsd_client_t *con, /* I - Client connection */ cupsdUpdateQuota(printer, job->username, 0, kbytes); - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + job->koctets += kbytes; + + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer += kbytes; - snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, - job->num_files); - rename(con->filename, filename); + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, job->num_files); + if (rename(con->filename, filename)) + { + cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to rename job document file \"%s\": %s", filename, strerror(errno)); + + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to rename job document file.")); + return; + } cupsdClearString(&con->filename); @@ -10726,6 +9900,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ { job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } else if (job->state_value == IPP_JOB_HELD) { @@ -10737,7 +9913,11 @@ send_document(cupsd_client_t *con, /* I - Client connection */ { job->state->values[0].integer = IPP_JOB_PENDING; job->state_value = IPP_JOB_PENDING; + + ippSetString(job->attrs, &job->reasons, 0, "none"); } + else + ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified"); } job->dirty = 1; @@ -10756,8 +9936,10 @@ send_document(cupsd_client_t *con, /* I - Client connection */ job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; job->hold_until = time(NULL) + MultipleOperationTimeout; - job->dirty = 1; + ippSetString(job->attrs, &job->reasons, 0, "job-incoming"); + + job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); } @@ -10768,9 +9950,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Fill in the response info... */ - snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName, - LocalPort, jobid); - + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, + con->clientname, con->clientport, "/jobs/%d", jobid); ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); @@ -10778,7 +9959,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state_value); - add_job_state_reasons(con, job); + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", + NULL, job->reasons->values[0].string.text); con->response->request.status.status_code = IPP_OK; @@ -10809,11 +9991,13 @@ send_http_error( uri = ippFindAttribute(con->request, "job-uri", IPP_TAG_URI); cupsdLogMessage(status == HTTP_FORBIDDEN ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, - "Returning HTTP %s for %s (%s) from %s", - httpStatus(status), - ippOpString(con->request->request.op.operation_id), + "[Client %d] Returning HTTP %s for %s (%s) from %s", + con->number, httpStatus(status), + con->request ? + ippOpString(con->request->request.op.operation_id) : + "no operation-id", uri ? uri->values[0].string.text : "no URI", - con->http.hostname); + con->http->hostname); if (printer) { @@ -10861,7 +10045,7 @@ send_http_error( if (auth) { if (auth->type == CUPSD_AUTH_DEFAULT) - auth_type = DefaultAuthType; + auth_type = cupsdDefaultAuthType(); else auth_type = auth->type; } @@ -10934,7 +10118,7 @@ set_default(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -10976,7 +10160,7 @@ set_default(cupsd_client_t *con, /* I - Client connection */ "%s is now the default printer.", printer->name); cupsdMarkDirty(CUPSD_DIRTY_PRINTERS | CUPSD_DIRTY_CLASSES | - CUPSD_DIRTY_REMOTE | CUPSD_DIRTY_PRINTCAP); + CUPSD_DIRTY_PRINTCAP); cupsdLogMessage(CUPSD_LOG_INFO, "Default destination set to \"%s\" by \"%s\".", @@ -11016,7 +10200,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Start with "everything is OK" status... @@ -11124,15 +10308,18 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (!strcmp(attr->name, "attributes-charset") || !strcmp(attr->name, "attributes-natural-language") || - !strcmp(attr->name, "document-compression") || - !strcmp(attr->name, "document-format") || + !strncmp(attr->name, "date-time-at-", 13) || + !strncmp(attr->name, "document-compression", 20) || + !strncmp(attr->name, "document-format", 15) || !strcmp(attr->name, "job-detailed-status-messages") || !strcmp(attr->name, "job-document-access-errors") || !strcmp(attr->name, "job-id") || !strcmp(attr->name, "job-impressions-completed") || - !strcmp(attr->name, "job-k-octets") || + !strcmp(attr->name, "job-k-octets-completed") || + !strcmp(attr->name, "job-media-sheets-completed") || !strcmp(attr->name, "job-originating-host-name") || !strcmp(attr->name, "job-originating-user-name") || + !strcmp(attr->name, "job-pages-completed") || !strcmp(attr->name, "job-printer-up-time") || !strcmp(attr->name, "job-printer-uri") || !strcmp(attr->name, "job-sheets") || @@ -11142,9 +10329,6 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ !strcmp(attr->name, "number-of-documents") || !strcmp(attr->name, "number-of-intervening-jobs") || !strcmp(attr->name, "output-device-assigned") || - !strncmp(attr->name, "date-time-at-", 13) || - !strncmp(attr->name, "job-k-octets", 12) || - !strncmp(attr->name, "job-media-sheets", 16) || !strncmp(attr->name, "time-at-", 8)) { /* @@ -11154,13 +10338,44 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ send_ipp_status(con, IPP_ATTRIBUTES_NOT_SETTABLE, _("%s cannot be changed."), attr->name); - if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) - attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; - + attr2 = ippCopyAttribute(con->response, attr, 0); + ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP); continue; } - if (!strcmp(attr->name, "job-priority")) + if (!ippValidateAttribute(attr)) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Bad '%s' value."), attr->name); + ippCopyAttribute(con->response, attr, 0); + return; + } + + if (!strcmp(attr->name, "job-hold-until")) + { + const char *when = ippGetString(attr, 0, NULL); + /* job-hold-until value */ + + if ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value.")); + ippCopyAttribute(con->response, attr, 0); + return; + } + + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", when); + cupsdSetJobHoldUntil(job, when, 0); + + if (!strcmp(when, "no-hold")) + { + cupsdReleaseJob(job); + check_jobs = 1; + } + else + cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".", username); + + event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE; + } + else if (!strcmp(attr->name, "job-priority")) { /* * Change the job priority... @@ -11170,8 +10385,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value.")); - if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) - attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + attr2 = ippCopyAttribute(con->response, attr, 0); + ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP); } else if (job->state_value >= IPP_JOB_PROCESSING) { @@ -11200,8 +10415,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value.")); - if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) - attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + attr2 = ippCopyAttribute(con->response, attr, 0); + ippSetGroupTag(con->response, &attr2, IPP_TAG_UNSUPPORTED_GROUP); } else { @@ -11219,9 +10434,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d", attr->values[0].integer); - cupsdSetJobState(job, attr->values[0].integer, - CUPSD_JOB_DEFAULT, - "Job state changed by \"%s\"", username); + cupsdSetJobState(job, (ipp_jstate_t)attr->values[0].integer, CUPSD_JOB_DEFAULT, "Job state changed by \"%s\"", username); check_jobs = 1; } break; @@ -11275,35 +10488,13 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (job->attrs->last == attr2) job->attrs->last = job->attrs->prev; - _ippFreeAttr(attr2); + ippDeleteAttribute(NULL, attr2); /* * Then copy the attribute... */ - copy_attribute(job->attrs, attr, 0); - - /* - * See if the job-name or job-hold-until is being changed. - */ - - if (!strcmp(attr->name, "job-hold-until")) - { - cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", - attr->values[0].string.text); - cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0); - - if (!strcmp(attr->values[0].string.text, "no-hold")) - { - cupsdReleaseJob(job); - check_jobs = 1; - } - else - cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, - "Job held by \"%s\".", username); - - event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE; - } + ippCopyAttribute(job->attrs, attr, 0); } else if (attr->value_tag == IPP_TAG_DELETEATTR) { @@ -11322,7 +10513,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (attr2 == job->attrs->last) job->attrs->last = job->attrs->prev; - _ippFreeAttr(attr2); + ippDeleteAttribute(NULL, attr2); event |= CUPSD_EVENT_JOB_CONFIG_CHANGED; } @@ -11333,7 +10524,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Add new option by copying it... */ - copy_attribute(job->attrs, attr, 0); + ippCopyAttribute(job->attrs, attr, 0); event |= CUPSD_EVENT_JOB_CONFIG_CHANGED; } @@ -11389,7 +10580,7 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -11427,6 +10618,24 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ changed = 1; } + if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4)) + { + cupsdSetString(&printer->geo_location, attr->values[0].string.text); + changed = 1; + } + + if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL) + { + cupsdSetString(&printer->organization, attr->values[0].string.text); + changed = 1; + } + + if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL) + { + cupsdSetString(&printer->organizational_unit, attr->values[0].string.text); + changed = 1; + } + if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) { @@ -11440,6 +10649,8 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ if (changed) { + printer->config_time = time(NULL); + cupsdSetPrinterAttrs(printer); cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); @@ -11460,14 +10671,14 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ * 'set_printer_defaults()' - Set printer default options from a request. */ -static void +static int /* O - 1 on success, 0 on failure */ set_printer_defaults( cupsd_client_t *con, /* I - Client connection */ cupsd_printer_t *printer) /* I - Printer */ { int i; /* Looping var */ ipp_attribute_t *attr; /* Current attribute */ - int namelen; /* Length of attribute name */ + size_t namelen; /* Length of attribute name */ char name[256], /* New attribute name */ value[256]; /* String version of integer attrs */ @@ -11589,7 +10800,7 @@ set_printer_defaults( send_ipp_status(con, IPP_NOT_POSSIBLE, _("Unknown printer-op-policy \"%s\"."), attr->values[0].string.text); - return; + return (0); } } else if (!strcmp(attr->name, "printer-error-policy")) @@ -11598,7 +10809,7 @@ set_printer_defaults( continue; if (strcmp(attr->values[0].string.text, "retry-current-job") && - ((printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) || + ((printer->type & CUPS_PRINTER_CLASS) || (strcmp(attr->values[0].string.text, "abort-job") && strcmp(attr->values[0].string.text, "retry-job") && strcmp(attr->values[0].string.text, "stop-printer")))) @@ -11606,7 +10817,7 @@ set_printer_defaults( send_ipp_status(con, IPP_NOT_POSSIBLE, _("Unknown printer-error-policy \"%s\"."), attr->values[0].string.text); - return; + return (0); } cupsdLogMessage(CUPSD_LOG_DEBUG, @@ -11642,6 +10853,7 @@ set_printer_defaults( break; case IPP_TAG_NAME : + case IPP_TAG_TEXT : case IPP_TAG_KEYWORD : case IPP_TAG_URI : printer->num_options = cupsAddOption(name, @@ -11688,7 +10900,7 @@ set_printer_defaults( sprintf(value, "%dx%d%s", attr->values[0].resolution.xres, attr->values[0].resolution.yres, attr->values[0].resolution.units == IPP_RES_PER_INCH ? - "dpi" : "dpc"); + "dpi" : "dpcm"); printer->num_options = cupsAddOption(name, value, printer->num_options, &(printer->options)); @@ -11701,6 +10913,8 @@ set_printer_defaults( break; } } + + return (1); } @@ -11719,7 +10933,7 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -11801,7 +11015,7 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -11834,7 +11048,7 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) == NULL) - strcpy(printer->state_message, "Paused"); + strlcpy(printer->state_message, "Paused", sizeof(printer->state_message)); else { strlcpy(printer->state_message, attr->values[0].string.text, @@ -11865,7 +11079,7 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ static void url_encode_attr(ipp_attribute_t *attr, /* I - Attribute */ char *buffer,/* I - String buffer */ - int bufsize)/* I - Size of buffer */ + size_t bufsize)/* I - Size of buffer */ { int i; /* Looping var */ char *bufptr, /* Pointer into buffer */ @@ -11891,8 +11105,7 @@ url_encode_attr(ipp_attribute_t *attr, /* I - Attribute */ *bufptr++ = '\''; - bufptr = url_encode_string(attr->values[i].string.text, - bufptr, bufend - bufptr + 1); + bufptr = url_encode_string(attr->values[i].string.text, bufptr, (size_t)(bufend - bufptr + 1)); if (bufptr >= bufend) break; @@ -11911,7 +11124,7 @@ url_encode_attr(ipp_attribute_t *attr, /* I - Attribute */ static char * /* O - End of string */ url_encode_string(const char *s, /* I - String */ char *buffer, /* I - String buffer */ - int bufsize) /* I - Size of buffer */ + size_t bufsize) /* I - Size of buffer */ { char *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ @@ -12012,7 +11225,7 @@ user_allowed(cupsd_printer_t *p, /* I - Printer or class */ if (cupsdCheckGroup(username, pw, name)) break; } - else if (!strcasecmp(username, name)) + else if (!_cups_strcasecmp(username, name)) break; } @@ -12029,9 +11242,12 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { http_status_t status; /* Policy status */ - ipp_attribute_t *attr, /* Current attribute */ - *auth_info; /* auth-info attribute */ - ipp_attribute_t *format; /* Document-format attribute */ + ipp_attribute_t *attr; /* Current attribute */ +#ifdef HAVE_SSL + ipp_attribute_t *auth_info; /* auth-info attribute */ +#endif /* HAVE_SSL */ + ipp_attribute_t *format, /* Document-format attribute */ + *name; /* Job-name attribute */ cups_ptype_t dtype; /* Destination type (printer/class) */ char super[MIME_MAX_SUPER], /* Supertype of file */ @@ -12041,7 +11257,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * OK, see if the client is sending the document compressed - CUPS @@ -12058,7 +11274,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ ) { send_ipp_status(con, IPP_ATTRIBUTES, - _("Unsupported compression \"%s\"."), + _("Unsupported 'compression' value \"%s\"."), attr->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, "compression", NULL, attr->values[0].string.text); @@ -12073,10 +11289,11 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ if ((format = ippFindAttribute(con->request, "document-format", IPP_TAG_MIMETYPE)) != NULL) { - if (sscanf(format->values[0].string.text, "%15[^/]/%31[^;]", + if (sscanf(format->values[0].string.text, "%15[^/]/%255[^;]", super, type) != 2) { - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"."), + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad 'document-format' value \"%s\"."), format->values[0].string.text); return; } @@ -12087,7 +11304,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_INFO, "Hint: Do you have the raw file printing rules enabled?"); send_ipp_status(con, IPP_DOCUMENT_FORMAT, - _("Unsupported document-format \"%s\"."), + _("Unsupported 'document-format' value \"%s\"."), format->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, "document-format", NULL, format->values[0].string.text); @@ -12095,6 +11312,40 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ } } + /* + * Is the job-hold-until value valid? + */ + + if ((attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_ZERO)) != NULL && ((ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG) || ippGetCount(attr) != 1 || !ippValidateAttribute(attr))) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-hold-until' value.")); + ippCopyAttribute(con->response, attr, 0); + return; + } + + /* + * Is the job-name valid? + */ + + if ((name = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) != NULL) + { + if ((name->value_tag != IPP_TAG_NAME && name->value_tag != IPP_TAG_NAMELANG) || + name->num_values != 1 || !ippValidateAttribute(name)) + { + if (StrictConformance) + { + send_ipp_status(con, IPP_STATUS_ERROR_ATTRIBUTES_OR_VALUES, _("Unsupported 'job-name' value.")); + ippCopyAttribute(con->response, name, 0); + return; + } + else + { + cupsdLogMessage(CUPSD_LOG_WARN, "Unsupported 'job-name' value, deleting from request."); + ippDeleteAttribute(con->request, name); + } + } + } + /* * Is the destination valid? */ @@ -12114,7 +11365,9 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ +#ifdef HAVE_SSL auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT); +#endif /* HAVE_SSL */ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) { @@ -12129,8 +11382,8 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ return; } #ifdef HAVE_SSL - else if (auth_info && !con->http.tls && - !httpAddrLocalhost(con->http.hostaddr)) + else if (auth_info && !con->http->tls && + !httpAddrLocalhost(con->http->hostaddr)) { /* * Require encryption of auth-info over non-local connections... @@ -12184,16 +11437,12 @@ validate_user(cupsd_job_t *job, /* I - Job */ cupsd_client_t *con, /* I - Client connection */ const char *owner, /* I - Owner of job/resource */ char *username, /* O - Authenticated username */ - int userlen) /* I - Length of username */ + size_t userlen) /* I - Length of username */ { cupsd_printer_t *printer; /* Printer for job */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, " - "userlen=%d)", - job->id, con ? con->http.fd : 0, - owner ? owner : "(null)", username, userlen); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, userlen=" CUPS_LLFMT ")", job->id, con ? con->number : 0, owner ? owner : "(null)", username, CUPS_LLCAST userlen); /* * Validate input... @@ -12217,8 +11466,3 @@ validate_user(cupsd_job_t *job, /* I - Job */ return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr, con, owner) == HTTP_OK); } - - -/* - * End of "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $". - */