X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fipp.c;h=c0c2222f003a57ba32b918edb69102ba08bbb983;hb=26c14fa6e1b9639d47aca3032337d9fe728ee2dc;hp=60aa932ecf902ac942e1d54c782bc666a7f79af3;hpb=18ecb4282108afe096df4958d992c80bb5f2b570;p=thirdparty%2Fcups.git diff --git a/scheduler/ipp.c b/scheduler/ipp.c index 60aa932ec..c0c2222f0 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,105 +1,17 @@ /* - * "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $" + * IPP routines for the CUPS scheduler. * - * IPP routines for the Common UNIX Printing System (CUPS) scheduler. + * Copyright 2007-2016 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2009 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 print jobs. - * cancel_job() - Cancel a print job. - * cancel_subscription() - Cancel a subscription. - * check_quotas() - Check quotas for a printer and user. - * check_rss_recipient() - Check that we do not have a duplicate RSS - * feed URI. - * 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_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. - * 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_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. - * save_krb5_creds() - Save Kerberos credentials for the 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. + * 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/". */ /* @@ -110,8 +22,9 @@ #include #ifdef __APPLE__ -# include -# include +/*# include +extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id); +# include */ # ifdef HAVE_MEMBERSHIP_H # include # endif /* HAVE_MEMBERSHIP_H */ @@ -135,21 +48,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, - CMDeviceProfileInfo *profile, 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); @@ -158,27 +62,29 @@ 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); + 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, cupsd_job_t *job, - cups_array_t *ra); + cups_array_t *ra, cups_array_t *exclude); static void copy_printer_attrs(cupsd_client_t *con, cupsd_printer_t *printer, cups_array_t *ra); static void copy_subscription_attrs(cupsd_client_t *con, cupsd_subscription_t *sub, - cups_array_t *ra); + 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); @@ -209,18 +115,12 @@ static void renew_subscription(cupsd_client_t *con, int sub_id); static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri); static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job, ipp_attribute_t *auth_info); -#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H) -static void save_krb5_creds(cupsd_client_t *con, cupsd_job_t *job); -#endif /* HAVE_GSSAPI && HAVE_KRB5_H */ 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__ */ -; + __attribute__((__format__(__printf__, 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); @@ -228,15 +128,12 @@ static void 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); /* @@ -258,7 +155,7 @@ cupsdProcessIPPRequest( cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdProcessIPPRequest(%p[%d]): operation_id = %04x", - con, con->http.fd, con->request->request.op.operation_id); + con, con->number, con->request->request.op.operation_id); /* * First build an empty response message for this request... @@ -286,12 +183,12 @@ cupsdProcessIPPRequest( cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request version number %d.%d", - IPP_VERSION_NOT_SUPPORTED, con->http.hostname, + IPP_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!"), + _("Bad request version number %d.%d."), con->request->request.any.version[0], con->request->request.any.version[1]); } @@ -303,19 +200,19 @@ cupsdProcessIPPRequest( cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Bad request ID %d", - IPP_BAD_REQUEST, con->http.hostname, + IPP_BAD_REQUEST, con->http->hostname, con->request->request.any.request_id); - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad request ID %d!"), + send_ipp_status(con, IPP_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); + IPP_BAD_REQUEST, con->http->hostname); - send_ipp_status(con, IPP_BAD_REQUEST, _("No attributes in request!")); + send_ipp_status(con, IPP_BAD_REQUEST, _("No attributes in request.")); } else { @@ -335,10 +232,10 @@ cupsdProcessIPPRequest( cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Attribute groups are out of order", - IPP_BAD_REQUEST, con->http.hostname); + IPP_BAD_REQUEST, con->http->hostname); send_ipp_status(con, IPP_BAD_REQUEST, - _("Attribute groups are out of order (%x < %x)!"), + _("Attribute groups are out of order (%x < %x)."), attr->group_tag, group); break; } @@ -369,7 +266,20 @@ cupsdProcessIPPRequest( if (attr && attr->name && !strcmp(attr->name, "attributes-natural-language") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE) + { 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; @@ -390,7 +300,7 @@ cupsdProcessIPPRequest( charset->values[0].string.text); else ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, DefaultCharset); + "attributes-charset", NULL, "utf-8"); if (language) ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, @@ -401,21 +311,21 @@ cupsdProcessIPPRequest( "attributes-natural-language", NULL, DefaultLanguage); if (charset && - strcasecmp(charset->values[0].string.text, "us-ascii") && - strcasecmp(charset->values[0].string.text, "utf-8")) + _cups_strcasecmp(charset->values[0].string.text, "us-ascii") && + _cups_strcasecmp(charset->values[0].string.text, "utf-8")) { /* * Bad character set... */ - cupsdLogMessage(CUPSD_LOG_ERROR, "Unsupported character set \"%s\"!", + 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, + IPP_CHARSET, con->http->hostname, charset->values[0].string.text); send_ipp_status(con, IPP_BAD_REQUEST, - _("Unsupported character set \"%s\"!"), + _("Unsupported character set \"%s\"."), charset->values[0].string.text); } else if (!charset || !language || @@ -435,32 +345,32 @@ cupsdProcessIPPRequest( if (!charset) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing attributes-charset attribute!"); + "Missing attributes-charset attribute"); cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Missing attributes-charset attribute", - IPP_BAD_REQUEST, con->http.hostname); + IPP_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); + IPP_BAD_REQUEST, con->http->hostname); } if (!uri) { cupsdLogMessage(CUPSD_LOG_ERROR, "Missing printer-uri, job-uri, or ppd-name " - "attribute!"); + "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); + "attribute", IPP_BAD_REQUEST, con->http->hostname); } cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow..."); @@ -474,7 +384,7 @@ cupsdProcessIPPRequest( cupsdLogMessage(CUPSD_LOG_DEBUG, "End of attributes..."); send_ipp_status(con, IPP_BAD_REQUEST, - _("Missing required attributes!")); + _("Missing required attributes.")); } else { @@ -491,15 +401,14 @@ cupsdProcessIPPRequest( */ if (!strcmp(username->values[0].string.text, "root") && - strcasecmp(con->http.hostname, "localhost") && + _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); } } @@ -523,182 +432,192 @@ cupsdProcessIPPRequest( switch (con->request->request.op.operation_id) { - case IPP_PRINT_JOB : + case IPP_OP_PRINT_JOB : print_job(con, uri); break; - case IPP_VALIDATE_JOB : + case IPP_OP_VALIDATE_JOB : validate_job(con, uri); break; - case IPP_CREATE_JOB : + case IPP_OP_CREATE_JOB : create_job(con, uri); break; - case IPP_SEND_DOCUMENT : + case IPP_OP_SEND_DOCUMENT : send_document(con, uri); break; - case IPP_CANCEL_JOB : + case IPP_OP_CANCEL_JOB : cancel_job(con, uri); break; - case IPP_GET_JOB_ATTRIBUTES : + case IPP_OP_GET_JOB_ATTRIBUTES : get_job_attrs(con, uri); break; - case IPP_GET_JOBS : + case IPP_OP_GET_JOBS : get_jobs(con, uri); break; - case IPP_GET_PRINTER_ATTRIBUTES : + case IPP_OP_GET_PRINTER_ATTRIBUTES : get_printer_attrs(con, uri); break; - case IPP_GET_PRINTER_SUPPORTED_VALUES : + case IPP_OP_GET_PRINTER_SUPPORTED_VALUES : get_printer_supported(con, uri); break; - case IPP_HOLD_JOB : + case IPP_OP_HOLD_JOB : hold_job(con, uri); break; - case IPP_RELEASE_JOB : + case IPP_OP_RELEASE_JOB : release_job(con, uri); break; - case IPP_RESTART_JOB : + case IPP_OP_RESTART_JOB : restart_job(con, uri); break; - case IPP_PAUSE_PRINTER : + case IPP_OP_PAUSE_PRINTER : stop_printer(con, uri); break; - case IPP_RESUME_PRINTER : + case IPP_OP_RESUME_PRINTER : start_printer(con, uri); break; - case IPP_PURGE_JOBS : + case IPP_OP_PURGE_JOBS : + case IPP_OP_CANCEL_JOBS : + case IPP_OP_CANCEL_MY_JOBS : cancel_all_jobs(con, uri); break; - case IPP_SET_JOB_ATTRIBUTES : + case IPP_OP_SET_JOB_ATTRIBUTES : set_job_attrs(con, uri); break; - case IPP_SET_PRINTER_ATTRIBUTES : + case IPP_OP_SET_PRINTER_ATTRIBUTES : set_printer_attrs(con, uri); break; - case IPP_HOLD_NEW_JOBS : + case IPP_OP_HOLD_NEW_JOBS : hold_new_jobs(con, uri); break; - case IPP_RELEASE_HELD_NEW_JOBS : + case IPP_OP_RELEASE_HELD_NEW_JOBS : release_held_new_jobs(con, uri); break; - case CUPS_GET_DEFAULT : + case IPP_OP_CLOSE_JOB : + close_job(con, uri); + break; + + case IPP_OP_CUPS_GET_DEFAULT : get_default(con); break; - case CUPS_GET_PRINTERS : + case IPP_OP_CUPS_GET_PRINTERS : get_printers(con, 0); break; - case CUPS_GET_CLASSES : + case IPP_OP_CUPS_GET_CLASSES : get_printers(con, CUPS_PRINTER_CLASS); break; - case CUPS_ADD_PRINTER : + case IPP_OP_CUPS_ADD_MODIFY_PRINTER : add_printer(con, uri); break; - case CUPS_DELETE_PRINTER : + case IPP_OP_CUPS_DELETE_PRINTER : delete_printer(con, uri); break; - case CUPS_ADD_CLASS : + case IPP_OP_CUPS_ADD_MODIFY_CLASS : add_class(con, uri); break; - case CUPS_DELETE_CLASS : + case IPP_OP_CUPS_DELETE_CLASS : delete_printer(con, uri); break; - case CUPS_ACCEPT_JOBS : - case IPP_ENABLE_PRINTER : + case IPP_OP_CUPS_ACCEPT_JOBS : + case IPP_OP_ENABLE_PRINTER : accept_jobs(con, uri); break; - case CUPS_REJECT_JOBS : - case IPP_DISABLE_PRINTER : + case IPP_OP_CUPS_REJECT_JOBS : + case IPP_OP_DISABLE_PRINTER : reject_jobs(con, uri); break; - case CUPS_SET_DEFAULT : + case IPP_OP_CUPS_SET_DEFAULT : set_default(con, uri); break; - case CUPS_GET_DEVICES : + case IPP_OP_CUPS_GET_DEVICES : get_devices(con); break; - case CUPS_GET_DOCUMENT : + case IPP_OP_CUPS_GET_DOCUMENT : get_document(con, uri); break; - case CUPS_GET_PPD : + case IPP_OP_CUPS_GET_PPD : get_ppd(con, uri); break; - case CUPS_GET_PPDS : + case IPP_OP_CUPS_GET_PPDS : get_ppds(con); break; - case CUPS_MOVE_JOB : + case IPP_OP_CUPS_MOVE_JOB : move_job(con, uri); break; - case CUPS_AUTHENTICATE_JOB : + 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); + case IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS : + case IPP_OP_CREATE_JOB_SUBSCRIPTIONS : + create_subscriptions(con, uri); break; - case IPP_GET_SUBSCRIPTION_ATTRIBUTES : + case IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES : get_subscription_attrs(con, sub_id); break; - case IPP_GET_SUBSCRIPTIONS : + case IPP_OP_GET_SUBSCRIPTIONS : get_subscriptions(con, uri); break; - case IPP_RENEW_SUBSCRIPTION : + case IPP_OP_RENEW_SUBSCRIPTION : renew_subscription(con, sub_id); break; - case IPP_CANCEL_SUBSCRIPTION : + case IPP_OP_CANCEL_SUBSCRIPTION : cancel_subscription(con, sub_id); break; - case IPP_GET_NOTIFICATIONS : + case IPP_OP_GET_NOTIFICATIONS : get_notifications(con); break; + case IPP_OP_CUPS_CREATE_LOCAL_PRINTER : + create_local_printer(con); + break; + default : cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, "%04X %s Operation %04X (%s) not supported", - IPP_OPERATION_NOT_SUPPORTED, con->http.hostname, + 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!"), + _("%s not supported."), ippOpString( con->request->request.op.operation_id)); break; @@ -717,78 +636,63 @@ cupsdProcessIPPRequest( >= 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", + "[Client %d] Returning IPP %s for %s (%s) from %s", + con->number, 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); + 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); + /* + * 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 (cupsdFlushHeader(con) < 0) - return (0); + if (con->http->version == HTTP_1_1) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "[Client %d] Transfer-Encoding: chunked", + con->number); - con->http.data_encoding = HTTP_ENCODE_CHUNKED; - } - else + 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); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "[Client %d] Content-Length: " CUPS_LLFMT, + con->number, 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 @@ -830,11 +734,13 @@ cupsdTimeoutJob(cupsd_job_t *job) /* I - Job to timeout */ * See if we need to add the ending sheet... */ + if (!cupsdLoadJob(job)) + return (-1); + 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) { /* @@ -868,7 +774,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? @@ -881,7 +787,7 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -902,7 +808,8 @@ accept_jobs(cupsd_client_t *con, /* I - Client connection */ printer->accepting = 1; printer->state_message[0] = '\0'; - cupsdAddPrinterHistory(printer); + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, + "Now accepting jobs."); if (dtype & CUPS_PRINTER_CLASS) { @@ -948,12 +855,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? @@ -1002,15 +908,14 @@ 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... */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("A printer named \"%s\" already exists!"), + _("A printer named \"%s\" already exists."), resource + 9); return; } @@ -1028,56 +933,6 @@ 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; - } else if ((status = cupsdCheckPolicy(pclass->op_policy_ptr, con, NULL)) != HTTP_OK) { @@ -1093,36 +948,56 @@ 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); if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", - IPP_TAG_BOOLEAN)) != NULL) + IPP_TAG_BOOLEAN)) != NULL && + attr->values[0].boolean != pclass->accepting) { cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)", pclass->name, attr->values[0].boolean, pclass->accepting); pclass->accepting = attr->values[0].boolean; - cupsdAddPrinterHistory(pclass); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s accepting jobs.", + 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.")); + 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", @@ -1132,7 +1007,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ attr->values[0].integer != IPP_PRINTER_STOPPED) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Attempt to set %s printer-state to bad value %d!"), + _("Attempt to set %s printer-state to bad value %d."), pclass->name, attr->values[0].integer); return; } @@ -1153,7 +1028,9 @@ add_class(cupsd_client_t *con, /* I - Client connection */ { strlcpy(pclass->state_message, attr->values[0].string.text, sizeof(pclass->state_message)); - cupsdAddPrinterHistory(pclass); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, pclass, NULL, "%s", + pclass->state_message); } if ((attr = ippFindAttribute(con->request, "member-uris", IPP_TAG_URI)) != NULL) @@ -1187,13 +1064,13 @@ add_class(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } else if (dtype & CUPS_PRINTER_CLASS) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Nested classes are not allowed!")); + _("Nested classes are not allowed.")); return; } @@ -1211,6 +1088,8 @@ add_class(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_KEYWORD)) != NULL) cupsdSetAuthInfoRequired(pclass, NULL, attr); + pclass->config_time = time(NULL); + /* * Update the printer class attributes and return... */ @@ -1232,20 +1111,18 @@ add_class(cupsd_client_t *con, /* I - Client connection */ if (modify) { - cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, pclass, NULL, - "Class \"%s\" modified by \"%s\".", pclass->name, - get_username(con)); + cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, + pclass, NULL, "Class \"%s\" modified by \"%s\".", + pclass->name, get_username(con)); cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" modified by \"%s\".", pclass->name, get_username(con)); } else { - cupsdAddPrinterHistory(pclass); - - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, pclass, NULL, - "New class \"%s\" added by \"%s\".", pclass->name, - get_username(con)); + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, + pclass, NULL, "New class \"%s\" added by \"%s\".", + pclass->name, get_username(con)); cupsdLogMessage(CUPSD_LOG_INFO, "New class \"%s\" added by \"%s\".", pclass->name, get_username(con)); @@ -1271,7 +1148,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); /* @@ -1286,12 +1163,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, @@ -1299,14 +1182,12 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ if (con) send_ipp_status(con, IPP_INTERNAL_ERROR, - _("Unable to allocate memory for file types!")); + _("Unable to allocate memory for file types.")); return (-1); } - job->compressions = compressions; job->compressions[job->num_files] = compression; - job->filetypes = filetypes; job->filetypes[job->num_files] = filetype; job->num_files ++; @@ -1330,18 +1211,47 @@ 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 */ - char *title; /* Job name/title */ cupsd_job_t *job; /* Current job */ char job_uri[HTTP_MAX_URI]; /* Job URI */ int kbytes; /* Size of print file */ int i; /* Looping var */ int lowerpagerange; /* Page range bound */ + int exact; /* Did we have an exact match? */ + 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"); @@ -1350,11 +1260,11 @@ 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!")); + _("The printer or class is not shared.")); return (NULL); } @@ -1377,8 +1287,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... @@ -1403,9 +1313,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)) { @@ -1417,7 +1364,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ filetype->type); send_ipp_status(con, IPP_DOCUMENT_FORMAT, - _("Unsupported format \'%s\'!"), mimetype); + _("Unsupported format \"%s\"."), mimetype); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, "document-format", NULL, mimetype); @@ -1444,14 +1391,14 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (attr->value_tag != IPP_TAG_KEYWORD && attr->value_tag != IPP_TAG_NAME) { - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value type!")); + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value type.")); return (NULL); } if (attr->num_values > 2) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Too many job-sheets values (%d > 2)!"), + _("Too many job-sheets values (%d > 2)."), attr->num_values); return (NULL); } @@ -1460,7 +1407,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (strcmp(attr->values[i].string.text, "none") && !cupsdFindBanner(attr->values[i].string.text)) { - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-sheets value \"%s\"."), attr->values[i].string.text); return (NULL); } @@ -1503,6 +1450,51 @@ add_job(cupsd_client_t *con, /* I - Client connection */ } } + /* + * Do media selection as needed... + */ + + if (!ippFindAttribute(con->request, "PageRegion", IPP_TAG_ZERO) && + !ippFindAttribute(con->request, "PageSize", IPP_TAG_ZERO) && + _ppdCacheGetPageSize(printer->pc, con->request, NULL, &exact)) + { + if (!exact && + (media_col = ippFindAttribute(con->request, "media-col", + IPP_TAG_BEGIN_COLLECTION)) != NULL) + { + send_ipp_status(con, IPP_OK_SUBST, _("Unsupported margins.")); + + unsup_col = ippNew(); + if ((media_margin = ippFindAttribute(media_col->values[0].collection, + "media-bottom-margin", + IPP_TAG_INTEGER)) != NULL) + ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-bottom-margin", media_margin->values[0].integer); + + if ((media_margin = ippFindAttribute(media_col->values[0].collection, + "media-left-margin", + IPP_TAG_INTEGER)) != NULL) + ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-left-margin", media_margin->values[0].integer); + + if ((media_margin = ippFindAttribute(media_col->values[0].collection, + "media-right-margin", + IPP_TAG_INTEGER)) != NULL) + ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-right-margin", media_margin->values[0].integer); + + if ((media_margin = ippFindAttribute(media_col->values[0].collection, + "media-top-margin", + IPP_TAG_INTEGER)) != NULL) + ippAddInteger(unsup_col, IPP_TAG_ZERO, IPP_TAG_INTEGER, + "media-top-margin", media_margin->values[0].integer); + + ippAddCollection(con->response, IPP_TAG_UNSUPPORTED_GROUP, "media-col", + unsup_col); + ippDelete(unsup_col); + } + } + /* * Make sure we aren't over our limit... */ @@ -1512,8 +1504,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (MaxJobs && cupsArrayCount(Jobs) >= MaxJobs) { - send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Too many active jobs.")); + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Too many active jobs.")); return (NULL); } @@ -1547,30 +1538,43 @@ add_job(cupsd_client_t *con, /* I - Client connection */ priority); } - if ((attr = ippFindAttribute(con->request, "job-name", - IPP_TAG_NAME)) != NULL) - title = attr->values[0].string.text; - else - ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, - title = "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; + return (NULL); + } + 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; + return (NULL); + } if ((job = cupsdAddJob(priority, printer->name)) == NULL) { send_ipp_status(con, IPP_INTERNAL_ERROR, - _("Unable to add job for destination \"%s\"!"), + _("Unable to add job for destination \"%s\"."), printer->name); 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); @@ -1580,7 +1584,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ 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) { @@ -1598,9 +1602,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) @@ -1615,6 +1618,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) { @@ -1624,55 +1630,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 { @@ -1682,17 +1651,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... @@ -1702,15 +1669,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); - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, - title); - 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); @@ -1727,7 +1694,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... @@ -1737,6 +1721,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) { @@ -1748,10 +1734,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... @@ -1766,8 +1753,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; @@ -1793,7 +1780,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\", " @@ -1810,7 +1797,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\", " @@ -1850,18 +1837,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) @@ -1884,7 +1871,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); @@ -1902,15 +1889,14 @@ add_job(cupsd_client_t *con, /* I - Client connection */ } else if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL) - job->sheets = attr; + job->job_sheets = attr; /* * 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); @@ -1918,7 +1904,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; @@ -1949,75 +1937,6 @@ 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... - */ - -static void -add_job_state_reasons( - 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. */ @@ -2089,7 +2008,7 @@ add_job_subscriptions( resource, sizeof(resource)) < HTTP_URI_OK) { send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Bad notify-recipient-uri URI \"%s\"!"), recipient); + _("Bad notify-recipient-uri \"%s\"."), recipient); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_URI_SCHEME); return; @@ -2101,7 +2020,7 @@ add_job_subscriptions( { send_ipp_status(con, IPP_NOT_POSSIBLE, _("notify-recipient-uri URI \"%s\" uses unknown " - "scheme!"), recipient); + "scheme."), recipient); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_URI_SCHEME); return; @@ -2110,7 +2029,7 @@ add_job_subscriptions( if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient)) { send_ipp_status(con, IPP_NOT_POSSIBLE, - _("notify-recipient-uri URI \"%s\" is already used!"), + _("notify-recipient-uri URI \"%s\" is already used."), recipient); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_ATTRIBUTES); @@ -2125,7 +2044,7 @@ add_job_subscriptions( if (strcmp(pullmethod, "ippget")) { send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Bad notify-pull-method \"%s\"!"), pullmethod); + _("Bad notify-pull-method \"%s\"."), pullmethod); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_ATTRIBUTES); return; @@ -2137,7 +2056,7 @@ add_job_subscriptions( strcmp(attr->values[0].string.text, "utf-8")) { send_ipp_status(con, IPP_CHARSET, - _("Character set \"%s\" not supported!"), + _("Character set \"%s\" not supported."), attr->values[0].string.text); return; } @@ -2146,7 +2065,7 @@ add_job_subscriptions( strcmp(attr->values[0].string.text, DefaultLanguage))) { send_ipp_status(con, IPP_CHARSET, - _("Language \"%s\" not supported!"), + _("Language \"%s\" not supported."), attr->values[0].string.text); return; } @@ -2157,7 +2076,7 @@ add_job_subscriptions( { send_ipp_status(con, IPP_REQUEST_VALUE, _("The notify-user-data value is too large " - "(%d > 63 octets)!"), + "(%d > 63 octets)."), attr->values[0].unknown.length); return; } @@ -2201,12 +2120,15 @@ 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); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d", + sub->id, job->id); } if (attr) @@ -2233,7 +2155,7 @@ add_job_subscriptions( * Free and remove this attribute... */ - _ippFreeAttr(attr); + ippDeleteAttribute(NULL, attr); if (prev) prev->next = next; @@ -2256,48 +2178,19 @@ 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[1024]; /* job-uuid string */ - _cups_md5_state_t md5state; /* MD5 state */ - unsigned char md5sum[16]; /* MD5 digest/sum */ - - - /* - * First see if the job already has a job-uuid attribute; if so, return... - */ - - if (ippFindAttribute(job->attrs, "job-uuid", IPP_TAG_URI)) - return; - - /* - * No job-uuid attribute, so build a version 3 UUID with the local job - * ID at the end; see RFC 4122 for details. Start with the MD5 sum of - * the ServerName, server name and port that the client connected to, - * and local job ID... - */ + char uuid[64]; /* job-uuid string */ - snprintf(uuid, sizeof(uuid), "%s:%s:%d:%d", ServerName, con->servername, - con->serverport, job->id); - - _cupsMD5Init(&md5state); - _cupsMD5Append(&md5state, (unsigned char *)uuid, strlen(uuid)); - _cupsMD5Finish(&md5state, md5sum); /* - * Format the UUID URI using the MD5 sum and job ID. + * Add a job-uuid attribute if none exists... */ - snprintf(uuid, sizeof(uuid), - "urn:uuid:%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" - "%02x%02x%02x%02x%02x%02x", - md5sum[0], md5sum[1], md5sum[2], md5sum[3], md5sum[4], md5sum[5], - (md5sum[6] & 15) | 0x30, md5sum[7], (md5sum[8] & 0x3f) | 0x40, - md5sum[9], md5sum[10], md5sum[11], md5sum[12], md5sum[13], - md5sum[14], md5sum[15]); - - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-uuid", NULL, uuid); + 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))); } @@ -2323,14 +2216,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 need_restart_job; /* Need to restart job? */ - int set_device_uri, /* Did we set the device URI? */ + 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? @@ -2378,15 +2271,14 @@ 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... */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("A class named \"%s\" already exists!"), + _("A class named \"%s\" already exists."), resource + 10); return; } @@ -2404,77 +2296,38 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer = cupsdAddPrinter(resource + 10); modify = 0; } - else if (printer->type & CUPS_PRINTER_IMPLICIT) + else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, + NULL)) != HTTP_OK) { - /* - * Check the default policy, then rename the implicit printer to - * "AnyPrinter" or delete it... - */ + send_http_error(con, status, printer); + return; + } + else + modify = 1; - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } + /* + * Look for attributes and copy them over as needed... + */ - if (ImplicitAnyClasses) - { - snprintf(newname, sizeof(newname), "Any%s", resource + 10); - cupsdRenamePrinter(printer, newname); - } - else - cupsdDeletePrinter(printer, 1); + changed_driver = 0; + need_restart_job = 0; - /* - * 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; - } - else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, - NULL)) != HTTP_OK) - { - send_http_error(con, status, printer); - return; - } - else - modify = 1; - - /* - * Look for attributes and copy them over as needed... - */ - - 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); @@ -2491,6 +2344,21 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ http_uri_status_t uri_status; /* URI separation status */ char old_device_uri[1024]; /* Old device URI */ + static const char * const uri_status_strings[] = + { + "URI too large.", + "Bad arguments to function.", + "Bad resource path.", + "Bad port number.", + "Bad hostname/address.", + "Bad username/password.", + "Bad URI scheme.", + "Bad URI.", + "OK", + "Missing URI scheme.", + "Unknown URI scheme", + "Missing resource path." + }; need_restart_job = 1; @@ -2502,12 +2370,14 @@ 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, + uri_status_strings[uri_status - HTTP_URI_STATUS_OVERFLOW]); + if (uri_status < HTTP_URI_OK) { - send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"!"), + 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); return; } @@ -2524,9 +2394,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("File device URIs have been disabled! " + _("File device URIs have been disabled. " "To enable, see the FileDevice directive in " - "\"%s/cupsd.conf\"."), + "\"%s/cups-files.conf\"."), ServerRoot); return; } @@ -2544,8 +2414,8 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * Could not find device in list! */ - send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri scheme \"%s\"!"), - scheme); + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Bad device-uri scheme \"%s\"."), scheme); return; } } @@ -2588,7 +2458,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (!supported || i >= supported->num_values) { - send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"!"), + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"."), attr->values[0].string.text); return; } @@ -2607,27 +2477,51 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ } if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", - IPP_TAG_BOOLEAN)) != NULL) + IPP_TAG_BOOLEAN)) != NULL && + attr->values[0].boolean != printer->accepting) { cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-is-accepting-jobs to %d (was %d.)", printer->name, attr->values[0].boolean, printer->accepting); printer->accepting = attr->values[0].boolean; - cupsdAddPrinterHistory(printer); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, + "%s accepting jobs.", + 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 (printer->shared && !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.")); + 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.")); + return; + } + + 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", @@ -2636,7 +2530,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (attr->values[0].integer != IPP_PRINTER_IDLE && attr->values[0].integer != IPP_PRINTER_STOPPED) { - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d."), attr->values[0].integer); return; } @@ -2658,7 +2552,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ { strlcpy(printer->state_message, attr->values[0].string.text, sizeof(printer->state_message)); - cupsdAddPrinterHistory(printer); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, "%s", + printer->state_message); } if ((attr = ippFindAttribute(con->request, "printer-state-reasons", @@ -2668,7 +2564,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ (int)(sizeof(printer->reasons) / sizeof(printer->reasons[0]))) { send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Too many printer-state-reasons values (%d > %d)!"), + _("Too many printer-state-reasons values (%d > %d)."), attr->num_values, (int)(sizeof(printer->reasons) / sizeof(printer->reasons[0]))); @@ -2700,6 +2596,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (PrintcapFormat == PRINTCAP_PLIST) cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, + "Printer \"%s\" state changed.", printer->name); } set_printer_defaults(con, printer); @@ -2716,12 +2615,13 @@ 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) { need_restart_job = 1; + changed_driver = 1; strlcpy(srcfile, con->filename, sizeof(srcfile)); @@ -2739,137 +2639,89 @@ 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; - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Copied interface script successfully!"); - chmod(dstfile, 0755); + send_ipp_status(con, IPP_STATUS_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED, _("Bad PPD file.")); + 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; - } - - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Copied PPD file successfully!"); - chmod(dstfile, 0644); - -#ifdef __APPLE__ - /* - * (Re)register color profiles... - */ + /* + * The new file is a PPD file, so move the file over to the ppd + * directory... + */ - if (!RunUser) - { - apple_unregister_profiles(printer); - apple_register_profiles(printer); - } -#endif /* __APPLE__ */ - } - else + if (copy_file(srcfile, dstfile, ConfigFilePerm)) { - /* - * This must be an interface script, so remove any old PPD file that - * may be lying around... - */ - - unlink(dstfile); + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file - %s"), strerror(errno)); + 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); - unlink(dstfile); - - snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", 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.")); + return; + } else { /* * 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!")); + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file.")); return; } - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Copied PPD file successfully!"); - chmod(dstfile, 0644); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Copied PPD file successfully"); + } + } -#ifdef __APPLE__ - /* - * (Re)register color profiles... - */ + if (changed_driver) + { + /* + * If we changed the PPD, then remove the printer's cache file and clear the + * printer-state-reasons... + */ - if (!RunUser) - { - apple_unregister_profiles(printer); - apple_register_profiles(printer); - } -#endif /* __APPLE__ */ - } + char cache_name[1024]; /* Cache filename for printer attrs */ + + snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, + printer->name); + unlink(cache_name); + + cupsdSetPrinterReasons(printer, "none"); + + /* + * (Re)register color profiles... + */ + + cupsdRegisterColor(printer); } /* @@ -2889,7 +2741,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; @@ -2914,12 +2766,15 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ } } + printer->config_time = time(NULL); + /* * Update the printer attributes and return... */ cupsdSetPrinterAttrs(printer); - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + if (!printer->temporary) + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); if (need_restart_job && printer->job) { @@ -2935,20 +2790,18 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (modify) { - cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL, - "Printer \"%s\" modified by \"%s\".", printer->name, - get_username(con)); + 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 { - cupsdAddPrinterHistory(printer); - - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, printer, NULL, - "New printer \"%s\" added by \"%s\".", printer->name, - get_username(con)); + 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)); @@ -2970,7 +2823,7 @@ add_printer_state_reasons( { cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer_state_reasons(%p[%d], %p[%s])", - con, con->http.fd, p, p->name); + con, con->number, p, p->name); if (p->num_reasons == 0) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, @@ -2996,7 +2849,7 @@ add_queued_job_count( cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])", - con, con->http.fd, p, p->name); + con, con->number, p, p->name); count = cupsdGetPrinterJobCount(p->name); @@ -3005,671 +2858,124 @@ add_queued_job_count( } -#ifdef __APPLE__ /* - * 'apple_init_profile()' - Initialize a color profile. + * 'apply_printer_defaults()' - Apply printer default options to a job. */ static void -apple_init_profile( - ppd_file_t *ppd, /* I - PPD file */ - cups_array_t *languages, /* I - Languages in the PPD file */ - CMDeviceProfileInfo *profile, /* I - Profile record */ - unsigned id, /* I - Profile ID */ - const char *name, /* I - Profile name */ - const char *text, /* I - Profile UI text */ - const char *iccfile) /* I - ICC filename */ +apply_printer_defaults( + cupsd_printer_t *printer, /* I - Printer */ + cupsd_job_t *job) /* I - Job */ { - char url[1024]; /* URL for profile filename */ - CFMutableDictionaryRef dict; /* Dictionary for name */ - char *language; /* Current language */ - ppd_attr_t *attr; /* Profile attribute */ - CFStringRef cflang, /* Language string */ - cftext; /* Localized text */ + int i, /* Looping var */ + num_options; /* Number of default options */ + cups_option_t *options, /* Default options */ + *option; /* Current option */ /* - * Build the profile name dictionary... + * Collect all of the default options and add the missing ones to the + * job object... */ - dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - cftext = CFStringCreateWithCString(kCFAllocatorDefault, text, - kCFStringEncodingUTF8); - - if (cftext) - { - CFDictionarySetValue(dict, CFSTR("en"), 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)) + for (i = printer->num_options, num_options = 0, options = NULL, + option = printer->options; + i > 0; + i --, option ++) + if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO)) { - 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); - } + num_options = cupsAddOption(option->name, option->value, num_options, + &options); } - cupsArrayRestore(ppd->sorted_attrs); - } - /* - * Fill in the profile data... + * Encode these options as attributes in the job object... */ - if (iccfile) - httpAssembleURI(HTTP_URI_CODING_ALL, url, sizeof(url), "file", NULL, "", 0, - iccfile); - - 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)); + cupsEncodeOptions2(job->attrs, num_options, options, IPP_TAG_JOB); + cupsFreeOptions(num_options, options); } /* - * 'apple_register_profiles()' - Register color profiles for a printer. + * 'authenticate_job()' - Set job authentication info. */ static void -apple_register_profiles( - cupsd_printer_t *p) /* I - Printer */ +authenticate_job(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job URI */ { - 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 */ - CMError error; /* 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 */ - CMDeviceScope scope = /* Scope of the registration */ - { - kCFPreferencesAnyUser, - kCFPreferencesCurrentHost - }; - CMDeviceProfileArrayPtr profiles; /* Profiles */ - CMDeviceProfileInfo *profile; /* Current profile */ - cups_array_t *languages; /* Languages array */ - - - /* - * Make sure ColorSync is available... - */ - - if (CMRegisterColorDevice == NULL) - return; + ipp_attribute_t *attr, /* job-id attribute */ + *auth_info; /* auth-info attribute */ + int jobid; /* Job ID */ + cupsd_job_t *job; /* Current job */ + char scheme[HTTP_MAX_URI], + /* Method portion of URI */ + username[HTTP_MAX_URI], + /* Username portion of URI */ + host[HTTP_MAX_URI], + /* Host portion of URI */ + resource[HTTP_MAX_URI]; + /* Resource portion of URI */ + int port; /* Port portion of URI */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)", + con, con->number, uri->values[0].string.text); /* - * Try opening the PPD file for this printer... + * Start with "everything is OK" status... */ - snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); - if ((ppd = ppdOpenFile(ppdfile)) == NULL) - return; + con->response->request.status.status_code = IPP_OK; /* - * See if we have any profiles... + * See if we have a job URI or a printer URI... */ - if ((attr = ppdFindAttr(ppd, "APTiogaProfile", NULL)) != NULL) - profile_key = "APTiogaProfile"; - else + if (!strcmp(uri->name, "printer-uri")) { - attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); - profile_key = "cupsICCProfile"; - } + /* + * Got a printer URI; see if we also have a job-id attribute... + */ - for (num_profiles = 0; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL)) - if (attr->spec[0] && attr->value && attr->value[0]) + if ((attr = ippFindAttribute(con->request, "job-id", + IPP_TAG_INTEGER)) == NULL) { - 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)) - continue; - - num_profiles ++; + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id.")); + return; } - - /* - * If we have profiles, add them... - */ - - if (num_profiles > 0) + jobid = attr->values[0].integer; + } + else { - if (profile_key[0] == 'A') - { - /* - * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile - * attribute... - */ + /* + * Got a job URI; parse it to get the job ID... + */ - if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL && - attr->value) - default_profile_id = atoi(attr->value); + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, + sizeof(host), &port, resource, sizeof(resource)); - q1_choice = q2_choice = q3_choice = NULL; - } - else + if (strncmp(resource, "/jobs/", 6)) { /* - * For CUPS PPDs, figure out the default profile selector values... + * Not a valid URI! */ - 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); + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), + uri->values[0].string.text); + return; + } - if (q1_attr && q1_attr->value && q1_attr->value[0]) - q1_choice = q1_attr->value; - else - q1_choice = ""; + jobid = atoi(resource + 6); + } - 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; - } - - /* - * 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 %d profiles!", - num_profiles); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - languages = _ppdGetLanguages(ppd); - - for (profile = profiles->profiles, - 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 (access(iccfile, 0)) - 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); - - apple_init_profile(ppd, languages, profile, profile_id, attr->spec, - attr->text[0] ? attr->text : attr->spec, iccfile); - - profile ++; - - /* - * See if this is the default profile... - */ - - if (!default_profile_id) - { - if (q2_choice) - { - if (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) - { - snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, - q2_choice); - if (!strcmp(selector, attr->spec)) - default_profile_id = profile_id; - } - } - - if (!default_profile_id && 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) - { - snprintf(selector, sizeof(selector), "%s..", q1_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; - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for %d profiles!", - num_profiles); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - - for (profile = profiles->profiles, i = cm_option->num_choices, - cm_choice = cm_option->choices; - i > 0; - i --, cm_choice ++, profile ++) - { - 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); - - apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice, - cm_choice->text, NULL); - - 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; - - if ((profiles = calloc(num_profiles, sizeof(CMDeviceProfileArray))) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate memory for %d profiles!", - num_profiles); - ppdClose(ppd); - return; - } - - profiles->profileCount = num_profiles; - - apple_init_profile(ppd, NULL, profiles->profiles, _ppdHashName("Gray.."), - "Gray", "Gray", NULL); - - switch (ppd->colorspace) - { - case PPD_CS_RGB : - case PPD_CS_CMY : - apple_init_profile(ppd, NULL, profiles->profiles + 1, - _ppdHashName("RGB.."), "RGB", "RGB", NULL); - break; - case PPD_CS_RGBK : - case PPD_CS_CMYK : - apple_init_profile(ppd, NULL, profiles->profiles + 1, - _ppdHashName("CMYK.."), "CMYK", "CMYK", NULL); - break; - - case PPD_CS_GRAY : - if (attr) - break; - - case PPD_CS_N : - apple_init_profile(ppd, NULL, profiles->profiles + 1, - _ppdHashName("DeviceN.."), "DeviceN", "DeviceN", - NULL); - break; - } - } - - if (num_profiles > 0) - { - /* - * Make sure we have a default profile ID... - */ - - if (!default_profile_id) - default_profile_id = profiles->profiles[num_profiles - 1].profileID; - - /* - * 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"), printer_name); - - /* - * Register the device with ColorSync... - */ - - error = CMRegisterColorDevice(cmPrinterDeviceClass, device_id, - device_name, &scope); - - /* - * Register the profiles... - */ - - if (error == noErr) - error = CMSetDeviceFactoryProfiles(cmPrinterDeviceClass, device_id, - default_profile_id, profiles); - } - else - error = 1000; - - /* - * Clean up... - */ - - if (error != noErr) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to register ICC color profiles for \"%s\" - %d", - p->name, (int)error); - - for (profile = profiles->profiles; - num_profiles > 0; - profile ++, num_profiles --) - CFRelease(profile->profileName); - - free(profiles); - - if (printer_name) - CFRelease(printer_name); - - if (device_name) - CFRelease(device_name); - } - - ppdClose(ppd); -} - - -/* - * 'apple_unregister_profiles()' - Remove color profiles for the specified - * printer. - */ - -static void -apple_unregister_profiles( - cupsd_printer_t *p) /* I - Printer */ -{ - /* - * Make sure ColorSync is available... - */ - - if (CMUnregisterColorDevice != NULL) - CMUnregisterColorDevice(cmPrinterDeviceClass, _ppdHashName(p->name)); -} -#endif /* __APPLE__ */ - -/* - * 'apply_printer_defaults()' - Apply printer default options to a job. - */ - -static void -apply_printer_defaults( - cupsd_printer_t *printer, /* I - Printer */ - cupsd_job_t *job) /* I - Job */ -{ - int i, /* Looping var */ - num_options; /* Number of default options */ - cups_option_t *options, /* Default options */ - *option; /* Current option */ - - - /* - * Collect all of the default options and add the missing ones to the - * job object... - */ - - for (i = printer->num_options, num_options = 0, options = NULL, - option = printer->options; - i > 0; - i --, option ++) - if (!ippFindAttribute(job->attrs, option->name, IPP_TAG_ZERO)) - { - num_options = cupsAddOption(option->name, option->value, num_options, - &options); - } - - /* - * Encode these options as attributes in the job object... - */ - - cupsEncodeOptions2(job->attrs, num_options, options, IPP_TAG_JOB); - cupsFreeOptions(num_options, options); -} - - -/* - * 'authenticate_job()' - Set job authentication info. - */ - -static void -authenticate_job(cupsd_client_t *con, /* I - Client connection */ - ipp_attribute_t *uri) /* I - Job URI */ -{ - ipp_attribute_t *attr, /* job-id attribute */ - *auth_info; /* auth-info attribute */ - int jobid; /* Job ID */ - cupsd_job_t *job; /* Current job */ - char scheme[HTTP_MAX_URI], - /* Method portion of URI */ - username[HTTP_MAX_URI], - /* Username portion of URI */ - host[HTTP_MAX_URI], - /* Host portion of URI */ - resource[HTTP_MAX_URI]; - /* Resource portion of URI */ - int port; /* Port portion of URI */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)", - con, con->http.fd, uri->values[0].string.text); - - /* - * Start with "everything is OK" status... - */ - - con->response->request.status.status_code = IPP_OK; - - /* - * See if we have a job URI or a printer URI... - */ - - if (!strcmp(uri->name, "printer-uri")) - { - /* - * Got a printer URI; see if we also have a job-id attribute... - */ - - if ((attr = ippFindAttribute(con->request, "job-id", - IPP_TAG_INTEGER)) == NULL) - { - send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); - return; - } - - jobid = attr->values[0].integer; - } - else - { - /* - * Got a job URI; parse it to get the job ID... - */ - - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, - sizeof(scheme), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); - - if (strncmp(resource, "/jobs/", 6)) - { - /* - * Not a valid URI! - */ - - send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri attribute \"%s\"!"), - uri->values[0].string.text); - return; - } - - jobid = atoi(resource + 6); - } - - /* - * See if the job exists... - */ + /* + * See if the job exists... + */ if ((job = cupsdFindJob(jobid)) == NULL) { @@ -3677,8 +2983,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, - _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -3693,7 +2998,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Job #%d is not held for authentication!"), + _("Job #%d is not held for authentication."), jobid); return; } @@ -3708,7 +3013,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... @@ -3721,7 +3025,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ send_http_error(con, HTTP_UNAUTHORIZED, printer); else send_ipp_status(con, IPP_NOT_AUTHORIZED, - _("No authentication information provided!")); + _("No authentication information provided.")); return; } @@ -3752,8 +3056,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"); } /* @@ -3762,18 +3066,23 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ cupsdReleaseJob(job); + cupsdAddEvent(CUPSD_EVENT_JOB_STATE, NULL, job, "Job authenticated by user"); + cupsdLogJob(job, CUPSD_LOG_INFO, "Authenticated by \"%s\".", con->username); + + cupsdCheckJobs(); } /* - * 'cancel_all_jobs()' - Cancel all print jobs. + * 'cancel_all_jobs()' - Cancel all or selected print jobs. */ static void cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Job or Printer URI */ { + int i; /* Looping var */ http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type */ char scheme[HTTP_MAX_URI], /* Scheme portion of URI */ @@ -3782,13 +3091,73 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ ipp_attribute_t *attr; /* Attribute in request */ - const char *username; /* Username */ - cupsd_jobaction_t purge; /* Purge? */ + const char *username = NULL; /* Username */ + cupsd_jobaction_t purge = CUPSD_JOB_DEFAULT; + /* Purge? */ cupsd_printer_t *printer; /* Printer */ + ipp_attribute_t *job_ids; /* job-ids attribute */ + cupsd_job_t *job; /* Job */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con, + con->number, uri->values[0].string.text); + + /* + * Get the jobs to cancel/purge... + */ + + switch (con->request->request.op.operation_id) + { + case IPP_PURGE_JOBS : + /* + * Get the username (if any) for the jobs we want to cancel (only if + * "my-jobs" is specified... + */ + + if ((attr = ippFindAttribute(con->request, "my-jobs", + IPP_TAG_BOOLEAN)) != NULL && + attr->values[0].boolean) + { + if ((attr = ippFindAttribute(con->request, "requesting-user-name", + IPP_TAG_NAME)) != NULL) + username = attr->values[0].string.text; + else + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Missing requesting-user-name attribute.")); + return; + } + } + + /* + * Look for the "purge-jobs" attribute... + */ + + if ((attr = ippFindAttribute(con->request, "purge-jobs", + IPP_TAG_BOOLEAN)) != NULL) + purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT; + else + purge = CUPSD_JOB_PURGE; + break; + + case IPP_CANCEL_MY_JOBS : + if (con->username[0]) + username = con->username; + else if ((attr = ippFindAttribute(con->request, "requesting-user-name", + IPP_TAG_NAME)) != NULL) + username = attr->values[0].string.text; + else + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Missing requesting-user-name attribute.")); + return; + } + default : + break; + } - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER); /* * See if we have a printer URI... @@ -3797,42 +3166,10 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ if (strcmp(uri->name, "printer-uri")) { send_ipp_status(con, IPP_BAD_REQUEST, - _("The printer-uri attribute is required!")); + _("The printer-uri attribute is required.")); return; } - /* - * Get the username (if any) for the jobs we want to cancel (only if - * "my-jobs" is specified... - */ - - if ((attr = ippFindAttribute(con->request, "my-jobs", - IPP_TAG_BOOLEAN)) != NULL && - attr->values[0].boolean) - { - if ((attr = ippFindAttribute(con->request, "requesting-user-name", - IPP_TAG_NAME)) != NULL) - username = attr->values[0].string.text; - else - { - send_ipp_status(con, IPP_BAD_REQUEST, - _("Missing requesting-user-name attribute!")); - return; - } - } - else - username = NULL; - - /* - * Look for the "purge-jobs" attribute... - */ - - if ((attr = ippFindAttribute(con->request, "purge-jobs", - IPP_TAG_BOOLEAN)) != NULL) - purge = attr->values[0].boolean ? CUPSD_JOB_PURGE : CUPSD_JOB_DEFAULT; - else - purge = CUPSD_JOB_PURGE; - /* * And if the destination is valid... */ @@ -3852,7 +3189,7 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ (!strncmp(resource, "/classes/", 9) && resource[9])) { send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -3866,15 +3203,50 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ return; } - /* - * Cancel all jobs on all printers... - */ + if (job_ids) + { + for (i = 0; i < job_ids->num_values; i ++) + { + 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) + { + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), + job_ids->values[i].integer); + return; + } + + for (i = 0; i < job_ids->num_values; i ++) + { + job = cupsdFindJob(job_ids->values[i].integer); + + cupsdSetJobState(job, IPP_JOB_CANCELED, purge, + purge == CUPSD_JOB_PURGE ? "Job purged by user." : + "Job canceled by user."); + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".", + purge == CUPSD_JOB_PURGE ? "purged" : "canceled", + get_username(con)); + } + else + { + /* + * Cancel all jobs on all printers... + */ - cupsdCancelJobs(NULL, username, purge); + cupsdCancelJobs(NULL, username, purge); - cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".", - purge == CUPSD_JOB_PURGE ? "purged" : "canceled", - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".", + purge == CUPSD_JOB_PURGE ? "purged" : "canceled", + get_username(con)); + } } else { @@ -3889,19 +3261,57 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ return; } - /* - * Cancel all of the jobs on the named printer... - */ + if (job_ids) + { + for (i = 0; i < job_ids->num_values; i ++) + { + if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL || + _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) + { + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), + job_ids->values[i].integer); + return; + } - cupsdCancelJobs(printer->name, username, purge); + for (i = 0; i < job_ids->num_values; i ++) + { + job = cupsdFindJob(job_ids->values[i].integer); + + cupsdSetJobState(job, IPP_JOB_CANCELED, purge, + purge == CUPSD_JOB_PURGE ? "Job purged by user." : + "Job canceled by user."); + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Selected jobs were %s by \"%s\".", + purge == CUPSD_JOB_PURGE ? "purged" : "canceled", + get_username(con)); + } + else + { + /* + * Cancel all of the jobs on the named printer... + */ + + cupsdCancelJobs(printer->name, username, purge); - cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".", - printer->name, - purge == CUPSD_JOB_PURGE ? "purged" : "canceled", - get_username(con)); + cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".", + printer->name, + purge == CUPSD_JOB_PURGE ? "purged" : "canceled", + get_username(con)); + } } con->response->request.status.status_code = IPP_OK; + + cupsdCheckJobs(); } @@ -3927,7 +3337,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... @@ -3943,7 +3353,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -3960,7 +3370,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -3972,7 +3382,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) @@ -3987,14 +3397,14 @@ 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) jobid = job->id; else { - send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"), + send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s."), printer->name); return; } @@ -4017,8 +3427,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -4046,7 +3455,7 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -4128,7 +3537,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? @@ -4141,7 +3550,7 @@ cancel_subscription( */ send_ipp_status(con, IPP_NOT_FOUND, - _("notify-subscription-id %d no good!"), sub_id); + _("Subscription #%d does not exist."), sub_id); return; } @@ -4205,12 +3614,13 @@ check_rss_recipient( * 'check_quotas()' - Check quotas for a printer and user. */ -static int /* O - 1 if OK, 0 if not */ +static int /* O - 1 if OK, 0 if forbidden, + -1 if limit reached */ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsd_printer_t *p) /* I - Printer or class */ { - int i; /* Looping var */ - char username[33]; /* Username */ + char username[33], /* Username */ + *name; /* Current user name */ cupsd_quota_t *q; /* Quota data */ #ifdef HAVE_MBR_UID_TO_UUID /* @@ -4233,7 +3643,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... @@ -4241,6 +3651,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... */ @@ -4255,7 +3668,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ { cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for printer \"%s\"...", p->name); - return (0); + return (-1); } } @@ -4269,7 +3682,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ { cupsdLogMessage(CUPSD_LOG_INFO, "Too many jobs for user \"%s\"...", username); - return (0); + return (-1); } } @@ -4277,10 +3690,10 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ * Check against users... */ - if (p->num_users == 0 && p->k_limit == 0 && p->page_limit == 0) + if (cupsArrayCount(p->users) == 0 && p->k_limit == 0 && p->page_limit == 0) return (1); - if (p->num_users) + if (cupsArrayCount(p->users)) { #ifdef HAVE_MBR_UID_TO_UUID /* @@ -4311,21 +3724,22 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ endpwent(); #endif /* HAVE_MBR_UID_TO_UUID */ - for (i = 0; i < p->num_users; i ++) - if (p->users[i][0] == '@') + for (name = (char *)cupsArrayFirst(p->users); + name; + name = (char *)cupsArrayNext(p->users)) + if (name[0] == '@') { /* * Check group membership... */ #ifdef HAVE_MBR_UID_TO_UUID - if (p->users[i][1] == '#') + if (name[1] == '#') { - if (uuid_parse((char *)p->users[i] + 2, grp_uuid)) + if (uuid_parse(name + 2, grp_uuid)) uuid_clear(grp_uuid); } - else if ((mbr_err = mbr_group_name_to_uuid((char *)p->users[i] + 1, - grp_uuid)) != 0) + else if ((mbr_err = mbr_group_name_to_uuid(name + 1, grp_uuid)) != 0) { /* * Invalid ACL entries are ignored for matching; just record a @@ -4334,10 +3748,10 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "check_quotas: UUID lookup failed for ACL entry " - "\"%s\" (err=%d)", p->users[i], mbr_err); + "\"%s\" (err=%d)", name, mbr_err); cupsdLogMessage(CUPSD_LOG_WARN, "Access control entry \"%s\" not a valid group name; " - "entry ignored", p->users[i]); + "entry ignored", name); } if ((mbr_err = mbr_check_membership(usr_uuid, grp_uuid, @@ -4349,7 +3763,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "check_quotas: group \"%s\" membership check " - "failed (err=%d)", p->users[i] + 1, mbr_err); + "failed (err=%d)", name + 1, mbr_err); is_member = 0; } @@ -4361,20 +3775,19 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ break; #else - if (cupsdCheckGroup(username, pw, p->users[i] + 1)) + if (cupsdCheckGroup(username, pw, name + 1)) break; #endif /* HAVE_MBR_UID_TO_UUID */ } #ifdef HAVE_MBR_UID_TO_UUID else { - if (p->users[i][0] == '#') + if (name[0] == '#') { - if (uuid_parse((char *)p->users[i] + 1, usr2_uuid)) + if (uuid_parse(name + 1, usr2_uuid)) uuid_clear(usr2_uuid); } - else if ((mbr_err = mbr_user_name_to_uuid((char *)p->users[i], - usr2_uuid)) != 0) + else if ((mbr_err = mbr_user_name_to_uuid(name, usr2_uuid)) != 0) { /* * Invalid ACL entries are ignored for matching; just record a @@ -4383,21 +3796,21 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG, "check_quotas: UUID lookup failed for ACL entry " - "\"%s\" (err=%d)", p->users[i], mbr_err); + "\"%s\" (err=%d)", name, mbr_err); cupsdLogMessage(CUPSD_LOG_WARN, "Access control entry \"%s\" not a valid user name; " - "entry ignored", p->users[i]); + "entry ignored", name); } if (!uuid_compare(usr_uuid, usr2_uuid)) break; } #else - else if (!strcasecmp(username, p->users[i])) + else if (!_cups_strcasecmp(username, name)) break; #endif /* HAVE_MBR_UID_TO_UUID */ - if ((i < p->num_users) == p->deny_users) + if ((name != NULL) == p->deny_users) { cupsdLogMessage(CUPSD_LOG_INFO, "Denying user \"%s\" access to printer \"%s\"...", @@ -4410,72 +3823,12 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ * Check quotas... */ -#ifdef __APPLE__ - if (AppleQuotas && (q = cupsdFindQuota(p, username)) != NULL) - { - /* - * TODO: Define these special page count values as constants! - */ - - if (q->page_count == -4) /* special case: unlimited user */ - { - cupsdLogMessage(CUPSD_LOG_INFO, - "User \"%s\" request approved for printer %s (%s): " - "unlimited quota.", - username, p->name, p->info); - q->page_count = 0; /* allow user to print */ - return (1); - } - else if (q->page_count == -3) /* quota exceeded */ - { - cupsdLogMessage(CUPSD_LOG_INFO, - "User \"%s\" request denied for printer %s (%s): " - "quota limit exceeded.", - username, p->name, p->info); - q->page_count = 2; /* force quota exceeded failure */ - return (-1); - } - else if (q->page_count == -2) /* quota disabled for user */ - { - cupsdLogMessage(CUPSD_LOG_INFO, - "User \"%s\" request denied for printer %s (%s): " - "printing disabled for user.", - username, p->name, p->info); - q->page_count = 2; /* force quota exceeded failure */ - return (-1); - } - else if (q->page_count == -1) /* quota access error */ - { - cupsdLogMessage(CUPSD_LOG_INFO, - "User \"%s\" request denied for printer %s (%s): " - "unable to determine quota limit.", - username, p->name, p->info); - q->page_count = 2; /* force quota exceeded failure */ - return (-1); - } - else if (q->page_count < 0) /* user not found or other error */ - { - cupsdLogMessage(CUPSD_LOG_INFO, - "User \"%s\" request denied for printer %s (%s): " - "user disabled / missing quota.", - username, p->name, p->info); - q->page_count = 2; /* force quota exceeded failure */ - return (-1); - } - else /* page within user limits */ - { - q->page_count = 0; /* allow user to print */ - return (1); - } - } - else -#endif /* __APPLE__ */ if (p->k_limit || p->page_limit) { if ((q = cupsdUpdateQuota(p, username, 0, 0)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to allocate quota data for user \"%s\"!", + "Unable to allocate quota data for user \"%s\"", username); return (-1); } @@ -4498,189 +3851,121 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ /* - * 'copy_attribute()' - Copy a single attribute. + * 'close_job()' - Close a multi-file job. */ -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? */ +static void +close_job(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ { - int i; /* Looping var */ - ipp_attribute_t *toattr; /* Destination attribute */ + cupsd_job_t *job; /* Job */ + ipp_attribute_t *attr; /* Attribute */ + char job_uri[HTTP_MAX_URI], + /* Job URI */ + username[256]; /* User name */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "copy_attribute(%p, %p[%s,%x,%x])", to, attr, - attr->name ? attr->name : "(null)", attr->group_tag, - attr->value_tag); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con, + con->number, uri->values[0].string.text); + + /* + * See if we have a job URI or a printer URI... + */ - switch (attr->value_tag & ~IPP_TAG_COPY) + if (strcmp(uri->name, "printer-uri")) { - case IPP_TAG_ZERO : - toattr = ippAddSeparator(to); - break; + /* + * job-uri is not supported by Close-Job! + */ - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); + send_ipp_status(con, IPP_BAD_REQUEST, + _("Close-Job doesn't support the job-uri attribute.")); + return; + } - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].integer = attr->values[i].integer; - break; + /* + * Got a printer URI; see if we also have a job-id attribute... + */ - case IPP_TAG_BOOLEAN : - toattr = ippAddBooleans(to, attr->group_tag, attr->name, - attr->num_values, NULL); + if ((attr = ippFindAttribute(con->request, "job-id", + IPP_TAG_INTEGER)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id.")); + return; + } - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].boolean = attr->values[i].boolean; - break; + if ((job = cupsdFindJob(attr->values[0].integer)) == NULL) + { + /* + * Nope - return a "not found" error... + */ - 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; + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), + attr->values[0].integer); + return; + } - case IPP_TAG_DATE : - toattr = ippAddDate(to, attr->group_tag, attr->name, - attr->values[0].date); - break; + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_http_error(con, con->username[0] ? HTTP_FORBIDDEN : HTTP_UNAUTHORIZED, + cupsdFindDest(job->dest)); + return; + } - case IPP_TAG_RESOLUTION : - toattr = ippAddResolutions(to, attr->group_tag, attr->name, - attr->num_values, IPP_RES_PER_INCH, - NULL, NULL); + /* + * Add any ending sheet... + */ - 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; + if (cupsdTimeoutJob(job)) + return; - case IPP_TAG_RANGE : - toattr = ippAddRanges(to, attr->group_tag, attr->name, - attr->num_values, NULL, NULL); + if (job->state_value == IPP_JOB_STOPPED) + { + job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; + } + else if (job->state_value == IPP_JOB_HELD) + { + if ((attr = ippFindAttribute(job->attrs, "job-hold-until", + IPP_TAG_KEYWORD)) == NULL) + attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); - 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; + if (!attr || !strcmp(attr->values[0].string.text, "no-hold")) + { + job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; + } + } - 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); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); - 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; + /* + * Fill in the response info... + */ - case IPP_TAG_BEGIN_COLLECTION : - toattr = ippAddCollections(to, attr->group_tag, attr->name, - attr->num_values, NULL); + 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); - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].collection = ippNew(); - copy_attrs(toattr->values[i].collection, attr->values[i].collection, - NULL, IPP_TAG_ZERO, 0); - } - break; + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); - default : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", + job->state_value); - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].unknown.length = attr->values[i].unknown.length; + con->response->request.status.status_code = IPP_OK; - 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 */ - } + /* + * Start the job if necessary... + */ - return (toattr); + cupsdCheckJobs(); } @@ -4693,7 +3978,8 @@ copy_attrs(ipp_t *to, /* I - Destination request */ ipp_t *from, /* I - Source request */ cups_array_t *ra, /* I - Requested attributes */ ipp_tag_t group, /* I - Group to copy */ - int quickcopy) /* I - Do a quick copy? */ + int quickcopy, /* I - Do a quick copy? */ + cups_array_t *exclude) /* I - Attributes to exclude? */ { ipp_attribute_t *fromattr; /* Source attribute */ @@ -4715,18 +4001,46 @@ 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 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")) + continue; + } + if (!ra || cupsArrayFind(ra, fromattr->name)) { /* * Don't send collection attributes by default to IPP/1.x clients - * since many do not support collections... + * since many do not support collections. Also don't send + * media-col-database unless specifically requested by the client. */ if (fromattr->value_tag == IPP_TAG_BEGIN_COLLECTION && - !ra && to->request.status.version[0] == 1) + !ra && + (to->request.status.version[0] == 1 || + !strcmp(fromattr->name, "media-col-database"))) continue; - copy_attribute(to, fromattr, quickcopy); + ippCopyAttribute(to, fromattr, quickcopy); } } } @@ -4756,7 +4070,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)"); /* @@ -4801,8 +4115,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, @@ -4856,7 +4170,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; @@ -4919,7 +4233,11 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ case IPP_TAG_ENUM : if (!strncmp(s, "time-at-", 8)) { - struct timeval tv = { attr->values[i].integer, 0 }; + struct timeval tv; /* Time value */ + + tv.tv_sec = attr->values[i].integer; + tv.tv_usec = 0; + cupsFilePuts(out, cupsdGetDateTime(&tv, CUPSD_TIME_STANDARD)); } else @@ -4943,7 +4261,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 : @@ -4953,7 +4271,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... @@ -4999,8 +4317,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); @@ -5010,12 +4329,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 */ @@ -5032,7 +4352,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); @@ -5043,7 +4363,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); @@ -5056,7 +4376,7 @@ copy_file(const char *from, /* I - Source file */ cupsFileClose(src); - return (cupsFileClose(dst)); + return (cupsdCloseCreatedConfFile(dst, to)); } @@ -5088,15 +4408,14 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ int i; /* Looping var */ char option[PPD_MAX_NAME], /* Option name */ choice[PPD_MAX_NAME]; /* Choice name */ + ppd_size_t *size; /* Default size */ int num_defaults; /* Number of default options */ cups_option_t *defaults; /* Default options */ char cups_protocol[PPD_MAX_LINE]; /* 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... @@ -5110,13 +4429,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); @@ -5179,7 +4496,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; @@ -5201,7 +4518,17 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ * No data from cups-deviced... */ - cupsdLogMessage(CUPSD_LOG_ERROR, "copy_model: empty PPD file!"); + cupsdLogMessage(CUPSD_LOG_ERROR, "copy_model: empty PPD file"); + unlink(tempfile); + return (-1); + } + + /* + * Open the source file for a copy... + */ + + if ((src = cupsFileOpen(tempfile, "rb")) == NULL) + { unlink(tempfile); return (-1); } @@ -5210,8 +4537,9 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ * 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); } @@ -5260,40 +4588,29 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ cupsFileClose(dst); } - else if (ppdPageSize(ppd, DefaultPaperSize)) + else if ((size = ppdPageSize(ppd, DefaultPaperSize)) != NULL) { /* * Add the default media sizes... */ - num_defaults = cupsAddOption("PageSize", DefaultPaperSize, + num_defaults = cupsAddOption("PageSize", size->name, num_defaults, &defaults); - num_defaults = cupsAddOption("PageRegion", DefaultPaperSize, + num_defaults = cupsAddOption("PageRegion", size->name, num_defaults, &defaults); - num_defaults = cupsAddOption("PaperDimension", DefaultPaperSize, + num_defaults = cupsAddOption("PaperDimension", size->name, num_defaults, &defaults); - num_defaults = cupsAddOption("ImageableArea", DefaultPaperSize, + num_defaults = cupsAddOption("ImageableArea", size->name, num_defaults, &defaults); } 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); @@ -5305,6 +4622,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)) @@ -5346,7 +4665,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ unlink(tempfile); - return (cupsFileClose(dst)); + return (cupsdCloseCreatedConfFile(dst, to)); } @@ -5357,7 +4676,8 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ static void copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job, /* I - Job */ - cups_array_t *ra) /* I - Requested attributes array */ + cups_array_t *ra, /* I - Requested attributes array */ + cups_array_t *exclude) /* I - Private attributes array */ { char job_uri[HTTP_MAX_URI]; /* Job URI */ @@ -5366,39 +4686,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 (!ra || cupsArrayFind(ra, "document-count")) - ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "document-count", job->num_files); + if (!cupsArrayFind(exclude, "all")) + { + if ((!exclude || !cupsArrayFind(exclude, "number-of-documents")) && + (!ra || cupsArrayFind(ra, "number-of-documents"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, + "number-of-documents", job->num_files); - if (!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-media-progress")) && + (!ra || cupsArrayFind(ra, "job-media-progress"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, + "job-media-progress", job->progress); - if (!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 && - (!ra || cupsArrayFind(ra, "job-preserved"))) - ippAddBoolean(con->response, IPP_TAG_JOB, "job-preserved", - job->num_files > 0); + 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 (!ra || cupsArrayFind(ra, "job-printer-up-time")) - ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, - "job-printer-up-time", time(NULL)); + 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-reasons")) - add_job_state_reasons(con, job); + 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_CONST_TAG(IPP_TAG_NAME), "job-name", NULL, job->name); + + if (job->username && (!ra || cupsArrayFind(ra, "job-originating-user-name"))) + ippAddString(con->response, IPP_TAG_JOB, IPP_CONST_TAG(IPP_TAG_NAME), "job-originating-user-name", NULL, job->username); + + 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")) + { + 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 (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); + 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); + } } @@ -5414,9 +4810,10 @@ copy_printer_attrs( { 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 */ - ipp_attribute_t *history; /* History collection */ /* @@ -5426,14 +4823,6 @@ copy_printer_attrs( curtime = time(NULL); -#ifdef __APPLE__ - if ((!ra || cupsArrayFind(ra, "com.apple.print.recoverable-message")) && - printer->recoverable) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, - "com.apple.print.recoverable-message", NULL, - printer->recoverable); -#endif /* __APPLE__ */ - if (!ra || cupsArrayFind(ra, "marker-change-time")) ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "marker-change-time", printer->marker_time); @@ -5462,8 +4851,8 @@ copy_printer_attrs( else { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, - sizeof(printer_uri), "ipp", NULL, con->servername, - con->serverport, + sizeof(printer_uri), "ipp", NULL, con->clientname, + con->clientport, (p2->type & CUPS_PRINTER_CLASS) ? "/classes/%s" : "/printers/%s", p2->name); member_uris->values[i].string.text = _cupsStrAlloc(printer_uri); @@ -5482,11 +4871,18 @@ copy_printer_attrs( "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)); -#ifdef HAVE_DNSSD +#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI) if (!ra || cupsArrayFind(ra, "printer-dns-sd-name")) { if (printer->reg_name) @@ -5496,7 +4892,7 @@ copy_printer_attrs( 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, @@ -5512,7 +4908,7 @@ copy_printer_attrs( "stop-printer" }; - if (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) + if (printer->type & CUPS_PRINTER_CLASS) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, "printer-error-policy-supported", NULL, "retry-current-job"); else @@ -5521,19 +4917,29 @@ copy_printer_attrs( 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->clientname, con->clientport, + "/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); + } + 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-is-temporary")) + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-temporary", (char)printer->temporary); - if ((!ra || cupsArrayFind(ra, "printer-more-info")) && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if (!ra || cupsArrayFind(ra, "printer-more-info")) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), - "http", NULL, con->servername, con->serverport, + "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, @@ -5548,27 +4954,13 @@ copy_printer_attrs( 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); - if (MaxPrinterHistory > 0 && printer->num_history > 0 && - cupsArrayFind(ra, "printer-state-history")) - { - /* - * Printer history is only sent if specifically requested, so that - * older CUPS/IPP clients won't barf on the collection attributes. - */ - - history = ippAddCollections(con->response, IPP_TAG_PRINTER, - "printer-state-history", - printer->num_history, NULL); - - for (i = 0; i < printer->num_history; i ++) - copy_attrs(history->values[i].collection = ippNew(), printer->history[i], - NULL, IPP_TAG_ZERO, 0); - } - if (!ra || cupsArrayFind(ra, "printer-state-message")) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message", NULL, printer->state_message); @@ -5578,8 +4970,7 @@ copy_printer_attrs( 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... @@ -5596,19 +4987,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); - 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, + "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, @@ -5620,10 +5009,10 @@ copy_printer_attrs( if (!ra || cupsArrayFind(ra, "queued-job-count")) add_queued_job_count(con, printer); - copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0); + copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0, NULL); if (printer->ppd_attrs) - copy_attrs(con->response, printer->ppd_attrs, ra, IPP_TAG_ZERO, 0); - copy_attrs(con->response, CommonData, ra, IPP_TAG_ZERO, IPP_TAG_COPY); + 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); } @@ -5635,7 +5024,8 @@ static void copy_subscription_attrs( cupsd_client_t *con, /* I - Client connection */ cupsd_subscription_t *sub, /* I - Subscription */ - cups_array_t *ra) /* I - Requested attributes array */ + cups_array_t *ra, /* I - Requested attributes array */ + cups_array_t *exclude) /* I - Private attributes array */ { ipp_attribute_t *attr; /* Current attribute */ char printer_uri[HTTP_MAX_URI]; @@ -5645,135 +5035,441 @@ copy_subscription_attrs( const char *name; /* Current event name */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "copy_subscription_attrs(con=%p, sub=%p, ra=%p, exclude=%p)", + con, sub, ra, exclude); + /* * Copy the subscription attributes to the response using the * requested-attributes attribute that may be provided by the client. */ - if (!ra || cupsArrayFind(ra, "notify-events")) + if (!exclude || !cupsArrayFind(exclude, "all")) { - if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) + if ((!exclude || !cupsArrayFind(exclude, "notify-events")) && + (!ra || cupsArrayFind(ra, "notify-events"))) { - /* - * Simple event list... - */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_subscription_attrs: notify-events"); - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, - (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), - "notify-events", NULL, name); - } - else - { - /* - * Complex event list... - */ + if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) + { + /* + * Simple event list... + */ + + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, + (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), + "notify-events", NULL, name); + } + else + { + /* + * Complex event list... + */ - for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) - if (sub->mask & mask) - count ++; + for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) + 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_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), + "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); + 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); - count ++; - } + count ++; + } + } } + + if ((!exclude || !cupsArrayFind(exclude, "notify-lease-duration")) && + (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration")))) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-lease-duration", sub->lease); + + if ((!exclude || !cupsArrayFind(exclude, "notify-recipient-uri")) && + (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri")))) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, + "notify-recipient-uri", NULL, sub->recipient); + else if ((!exclude || !cupsArrayFind(exclude, "notify-pull-method")) && + (!ra || cupsArrayFind(ra, "notify-pull-method"))) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, + "notify-pull-method", NULL, "ippget"); + + if ((!exclude || !cupsArrayFind(exclude, "notify-subscriber-user-name")) && + (!ra || cupsArrayFind(ra, "notify-subscriber-user-name"))) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME, + "notify-subscriber-user-name", NULL, sub->owner); + + if ((!exclude || !cupsArrayFind(exclude, "notify-time-interval")) && + (!ra || cupsArrayFind(ra, "notify-time-interval"))) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-time-interval", sub->interval); + + if (sub->user_data_len > 0 && + (!exclude || !cupsArrayFind(exclude, "notify-user-data")) && + (!ra || cupsArrayFind(ra, "notify-user-data"))) + ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data", + sub->user_data, sub->user_data_len); } if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id"))) ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-job-id", sub->job->id); - if (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration"))) - ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, - "notify-lease-duration", sub->lease); - 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); } - if (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri"))) - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, - "notify-recipient-uri", NULL, sub->recipient); - else if (!ra || cupsArrayFind(ra, "notify-pull-method")) - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, - "notify-pull-method", NULL, "ippget"); - - if (!ra || cupsArrayFind(ra, "notify-subscriber-user-name")) - ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME, - "notify-subscriber-user-name", NULL, sub->owner); - if (!ra || cupsArrayFind(ra, "notify-subscription-id")) ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, "notify-subscription-id", sub->id); +} - if (!ra || cupsArrayFind(ra, "notify-time-interval")) - ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, - "notify-time-interval", sub->interval); - if (sub->user_data_len > 0 && (!ra || cupsArrayFind(ra, "notify-user-data"))) - ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data", - sub->user_data, sub->user_data_len); +/* + * 'create_job()' - Print a file to a printer or class. + */ + +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->number, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer)) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class does not exist.")); + 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... + */ + + if ((job = add_job(con, printer, NULL)) == NULL) + return; + + job->pending_timeout = 1; + + /* + * Save and log the job... + */ + + cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".", + job->dest, job->username); +} + + +/* + * 'create_local_bg_thread()' - Background thread for creating a local print queue. + */ + +static void * /* O - Exit status */ +create_local_bg_thread( + cupsd_printer_t *printer) /* I - Printer */ +{ + 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 */ + + + /* + * Try connecting to the printer... + */ + + 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); + } + + /* + * Query the printer for its capabilities... + */ + + 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); + 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: Get-Printer-Attributes returned %s", printer->name, ippErrorString(cupsLastError())); + + // TODO: Grab printer icon file... + httpClose(http); + + /* + * Write the PPD for the queue... + */ + + if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response)) + { + 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)); + + 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); + } + + while (cupsFileGets(from, line, sizeof(line))) + cupsFilePrintf(to, "%s\n", line); + + cupsFileClose(from); + if (!cupsdCloseCreatedConfFile(to, toppd)) + { + 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.", printer->name); + + return (NULL); } -/* - * 'create_job()' - Print a file to a printer or class. - */ +/* + * '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'; -static void -create_job(cupsd_client_t *con, /* I - Client connection */ - ipp_attribute_t *uri) /* I - Printer URI */ -{ - cupsd_printer_t *printer; /* Printer */ - cupsd_job_t *job; /* New job */ + 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 + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "device-uri"); + return; + } - cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + 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); /* - * Is the destination valid? + * See if the printer already exists... */ - if (!cupsdValidateDest(uri->values[0].string.text, NULL, &printer)) + if ((printer = cupsdFindDest(name)) != NULL) { - /* - * Bad URI... - */ - - send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); - return; + send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name); + goto add_printer_attributes; } /* - * Create the job object... + * Create the printer... */ - if ((job = add_job(con, printer, NULL)) == NULL) + if ((printer = cupsdAddPrinter(name)) == NULL) + { + send_ipp_status(con, IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer.")); return; + } - job->pending_timeout = 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); /* - * Save and log the job... + * Run a background thread to create the PPD... */ - cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".", - job->dest, job->username); + _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); } @@ -5784,191 +5480,34 @@ create_job(cupsd_client_t *con, /* I - Client connection */ static cups_array_t * /* O - Array of attributes or NULL */ create_requested_array(ipp_t *request) /* I - IPP request */ { - int i; /* Looping var */ - ipp_attribute_t *requested; /* requested-attributes attribute */ cups_array_t *ra; /* Requested attributes array */ - char *value; /* Current value */ /* - * Get the requested-attributes attribute, and return NULL if we don't - * have one... + * Create the array for standard attributes... */ - if ((requested = ippFindAttribute(request, "requested-attributes", - IPP_TAG_KEYWORD)) == NULL) - return (NULL); + ra = ippCreateRequestedArray(request); /* - * If the attribute contains a single "all" keyword, return NULL... + * Add CUPS defaults as needed... */ - if (requested->num_values == 1 && - !strcmp(requested->values[0].string.text, "all")) - return (NULL); + if (cupsArrayFind(ra, "printer-defaults")) + { + /* + * Include user-set defaults... + */ - /* - * 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)) + 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); - } - else if (!strcmp(value, "subscription-template")) - { - cupsArrayAdd(ra, "notify-attributes"); - cupsArrayAdd(ra, "notify-charset"); - cupsArrayAdd(ra, "notify-events"); - cupsArrayAdd(ra, "notify-lease-duration"); - cupsArrayAdd(ra, "notify-natural-language"); - cupsArrayAdd(ra, "notify-pull-method"); - cupsArrayAdd(ra, "notify-recipient-uri"); - cupsArrayAdd(ra, "notify-time-interval"); - cupsArrayAdd(ra, "notify-user-data"); - } - else - cupsArrayAdd(ra, value); } return (ra); @@ -5976,11 +5515,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 */ { @@ -6028,9 +5567,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, @@ -6058,7 +5595,7 @@ create_subscription( */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -6099,7 +5636,7 @@ create_subscription( if (!attr) { send_ipp_status(con, IPP_BAD_REQUEST, - _("No subscription attributes in request!")); + _("No subscription attributes in request.")); return; } @@ -6157,7 +5694,7 @@ create_subscription( resource, sizeof(resource)) < HTTP_URI_OK) { send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Bad notify-recipient-uri URI \"%s\"!"), recipient); + _("Bad notify-recipient-uri \"%s\"."), recipient); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_URI_SCHEME); return; @@ -6169,7 +5706,7 @@ create_subscription( { send_ipp_status(con, IPP_NOT_POSSIBLE, _("notify-recipient-uri URI \"%s\" uses unknown " - "scheme!"), recipient); + "scheme."), recipient); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_URI_SCHEME); return; @@ -6178,7 +5715,7 @@ create_subscription( if (!strcmp(scheme, "rss") && !check_rss_recipient(recipient)) { send_ipp_status(con, IPP_NOT_POSSIBLE, - _("notify-recipient-uri URI \"%s\" is already used!"), + _("notify-recipient-uri URI \"%s\" is already used."), recipient); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_ATTRIBUTES); @@ -6193,7 +5730,7 @@ create_subscription( if (strcmp(pullmethod, "ippget")) { send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Bad notify-pull-method \"%s\"!"), pullmethod); + _("Bad notify-pull-method \"%s\"."), pullmethod); ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_ENUM, "notify-status-code", IPP_ATTRIBUTES); return; @@ -6205,7 +5742,7 @@ create_subscription( strcmp(attr->values[0].string.text, "utf-8")) { send_ipp_status(con, IPP_CHARSET, - _("Character set \"%s\" not supported!"), + _("Character set \"%s\" not supported."), attr->values[0].string.text); return; } @@ -6214,7 +5751,7 @@ create_subscription( strcmp(attr->values[0].string.text, DefaultLanguage))) { send_ipp_status(con, IPP_CHARSET, - _("Language \"%s\" not supported!"), + _("Language \"%s\" not supported."), attr->values[0].string.text); return; } @@ -6225,7 +5762,7 @@ create_subscription( { send_ipp_status(con, IPP_REQUEST_VALUE, _("The notify-user-data value is too large " - "(%d > 63 octets)!"), + "(%d > 63 octets)."), attr->values[0].unknown.length); return; } @@ -6273,7 +5810,7 @@ create_subscription( else { send_ipp_status(con, IPP_BAD_REQUEST, - _("notify-events not specified!")); + _("notify-events not specified.")); return; } } @@ -6281,7 +5818,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; @@ -6291,7 +5828,8 @@ create_subscription( { if ((job = cupsdFindJob(jobid)) == NULL) { - send_ipp_status(con, IPP_NOT_FOUND, _("Job %d not found!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), + jobid); return; } } @@ -6306,14 +5844,14 @@ create_subscription( } if (job) - cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d", + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for job %d.", sub->id, job->id); else if (printer) cupsdLogMessage(CUPSD_LOG_DEBUG, - "Added subscription %d for printer \"%s\"", + "Added subscription #%d for printer \"%s\".", sub->id, printer->name); else - cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for server", + cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription #%d for server.", sub->id); sub->interval = interval; @@ -6326,7 +5864,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); @@ -6355,10 +5893,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? @@ -6371,7 +5910,7 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -6406,24 +5945,26 @@ 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); - snprintf(filename, sizeof(filename), "%s/%s.ipp", CacheDir, printer->name); + snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, printer->name); + unlink(filename); + + 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) { @@ -6431,18 +5972,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)); - cupsdDeletePrinter(printer, 0); - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + if (cupsdDeletePrinter(printer, 0) && !temporary) + cupsdMarkDirty(CUPSD_DIRTY_CLASSES); + + if (!temporary) + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + if (!temporary) + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); /* * Return with no errors... @@ -6463,7 +6009,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... @@ -6486,7 +6032,7 @@ get_default(cupsd_client_t *con) /* I - Client connection */ con->response->request.status.status_code = IPP_OK; } else - send_ipp_status(con, IPP_NOT_FOUND, _("No default printer")); + send_ipp_status(con, IPP_NOT_FOUND, _("No default printer.")); } @@ -6513,7 +6059,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... @@ -6607,7 +6153,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... @@ -6623,7 +6169,7 @@ get_document(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -6645,8 +6191,7 @@ get_document(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -6664,7 +6209,7 @@ get_document(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -6672,7 +6217,8 @@ get_document(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, + job->username)) != HTTP_OK) { send_http_error(con, status, NULL); return; @@ -6686,15 +6232,16 @@ get_document(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Missing document-number attribute!")); + _("Missing document-number attribute.")); return; } if ((docnum = attr->values[0].integer) < 1 || docnum > job->num_files || attr->num_values > 1) { - send_ipp_status(con, IPP_NOT_FOUND, _("Document %d not found in job %d."), - docnum, jobid); + send_ipp_status(con, IPP_NOT_FOUND, + _("Document #%d does not exist in job #%d."), docnum, + jobid); return; } @@ -6706,7 +6253,8 @@ get_document(cupsd_client_t *con, /* I - Client connection */ "Unable to open document %d in job %d - %s", docnum, jobid, strerror(errno)); send_ipp_status(con, IPP_NOT_FOUND, - _("Unable to open document %d in job %d!"), docnum, jobid); + _("Unable to open document #%d in job #%d."), docnum, + jobid); return; } @@ -6740,16 +6288,19 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* Current attribute */ int jobid; /* Job ID */ cupsd_job_t *job; /* Current job */ - char scheme[HTTP_MAX_URI], /* Method portion of URI */ + cupsd_printer_t *printer; /* Current printer */ + cupsd_policy_t *policy; /* Current security policy */ + char scheme[HTTP_MAX_URI], /* Scheme portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ - cups_array_t *ra; /* Requested attributes array */ + cups_array_t *ra, /* Requested attributes array */ + *exclude; /* Private attributes array */ 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... @@ -6765,7 +6316,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -6787,8 +6338,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -6806,7 +6356,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -6814,12 +6364,22 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + if ((printer = job->printer) == NULL) + printer = cupsdFindDest(job->dest); + + if (printer) + policy = printer->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, job->username)) != HTTP_OK) { send_http_error(con, status, NULL); return; } + exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username); + /* * Copy attributes... */ @@ -6827,7 +6387,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ cupsdLoadJob(job); ra = create_requested_array(con->request); - copy_job_attrs(con, job, ra); + copy_job_attrs(con, job, ra, exclude); cupsArrayDelete(ra); con->response->request.status.status_code = IPP_OK; @@ -6852,17 +6412,26 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ - int completed; /* Completed jobs? */ - int first_job_id; /* First job ID */ - int limit; /* Maximum number of jobs to return */ + int job_comparison; /* Job comparison */ + ipp_jstate_t job_state; /* job-state value */ + int first_job_id = 1, /* First job ID */ + first_index = 1, /* First index */ + current_index = 0; /* Current index */ + int limit = 0; /* Maximum number of jobs to return */ int count; /* Number of jobs that match */ + int 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... */ - cups_array_t *ra; /* Requested attributes array */ + 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); /* @@ -6871,7 +6440,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ if (strcmp(uri->name, "printer-uri")) { - send_ipp_status(con, IPP_BAD_REQUEST, _("No printer-uri in request!")); + send_ipp_status(con, IPP_BAD_REQUEST, _("No printer-uri in request.")); return; } @@ -6908,7 +6477,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } else @@ -6922,135 +6491,315 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ */ if (printer) - { - if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, - NULL)) != HTTP_OK) - { - send_http_error(con, status, printer); - return; - } - } - else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + policy = printer->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK) { send_http_error(con, status, NULL); return; } + job_ids = ippFindAttribute(con->request, "job-ids", IPP_TAG_INTEGER); + /* * See if the "which-jobs" attribute have been specified... */ if ((attr = ippFindAttribute(con->request, "which-jobs", - IPP_TAG_KEYWORD)) != NULL && - !strcmp(attr->values[0].string.text, "completed")) + IPP_TAG_KEYWORD)) != NULL && job_ids) + { + send_ipp_status(con, IPP_CONFLICT, + _("The %s attribute cannot be provided with job-ids."), + "which-jobs"); + return; + } + else if (!attr || !strcmp(attr->values[0].string.text, "not-completed")) + { + job_comparison = -1; + job_state = IPP_JOB_STOPPED; + list = ActiveJobs; + } + else if (!strcmp(attr->values[0].string.text, "completed")) + { + job_comparison = 1; + job_state = IPP_JOB_CANCELED; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; + } + else if (!strcmp(attr->values[0].string.text, "aborted")) + { + job_comparison = 0; + job_state = IPP_JOB_ABORTED; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; + } + else if (!strcmp(attr->values[0].string.text, "all")) + { + job_comparison = 1; + job_state = IPP_JOB_PENDING; + list = Jobs; + } + else if (!strcmp(attr->values[0].string.text, "canceled")) + { + job_comparison = 0; + job_state = IPP_JOB_CANCELED; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; + } + else if (!strcmp(attr->values[0].string.text, "pending")) + { + job_comparison = 0; + job_state = IPP_JOB_PENDING; + list = ActiveJobs; + } + else if (!strcmp(attr->values[0].string.text, "pending-held")) { - completed = 1; - list = Jobs; + job_comparison = 0; + job_state = IPP_JOB_HELD; + list = ActiveJobs; } - else if (attr && !strcmp(attr->values[0].string.text, "all")) + else if (!strcmp(attr->values[0].string.text, "processing")) { - completed = 0; - list = Jobs; + job_comparison = 0; + job_state = IPP_JOB_PROCESSING; + list = PrintingJobs; } - else if (attr && !strcmp(attr->values[0].string.text, "processing")) + else if (!strcmp(attr->values[0].string.text, "processing-stopped")) { - completed = 0; - list = PrintingJobs; + job_comparison = 0; + job_state = IPP_JOB_STOPPED; + list = ActiveJobs; } else { - completed = 0; - list = ActiveJobs; + send_ipp_status(con, IPP_ATTRIBUTES, + _("The which-jobs value \"%s\" is not supported."), + attr->values[0].string.text); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, + "which-jobs", NULL, attr->values[0].string.text); + return; } /* * 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; - else - limit = 0; + } + + 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."), + "first-index"); + return; + } + + first_index = attr->values[0].integer; + } + else if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL) + { + if (job_ids) + { + send_ipp_status(con, IPP_CONFLICT, + _("The %s attribute cannot be provided with job-ids."), + "first-job-id"); + return; + } - if ((attr = ippFindAttribute(con->request, "first-job-id", - IPP_TAG_INTEGER)) != NULL) 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 && - attr->values[0].boolean) + 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."), + "my-jobs"); + return; + } + else if (attr && attr->values[0].boolean) strlcpy(username, get_username(con), sizeof(username)); else username[0] = '\0'; 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; + } - /* - * OK, build a list of jobs for this printer... - */ - - for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list); - (limit <= 0 || count < limit) && job; - job = (cupsd_job_t *)cupsArrayNext(list)) + if (need_load_job && (limit == 0 || limit > 500) && (list == Jobs || delete_list)) { /* - * Filter out jobs that don't match... + * Limit expensive Get-Jobs for job history to 500 jobs... */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", " - "state_value=%d, attrs=%p", job->id, job->dest, - job->username, job->state_value, job->attrs); + ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "limit", 500); - if (!job->dest || !job->username) - cupsdLoadJob(job); + if (limit) + ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "limit", limit); - if (!job->dest || !job->username) - continue; + limit = 500; - if ((dest && strcmp(job->dest, dest)) && - (!job->printer || !dest || strcmp(job->printer->name, dest))) - continue; - if ((job->dtype & dmask) != dtype && - (!job->printer || (job->printer->type & dmask) != dtype)) - continue; - if (completed && job->state_value <= IPP_JOB_STOPPED) - continue; + cupsdLogClient(con, CUPSD_LOG_INFO, "Limiting Get-Jobs response to %d jobs.", limit); + } - if (job->id < first_job_id) - continue; + /* + * OK, build a list of jobs for this printer... + */ - cupsdLoadJob(job); + if (job_ids) + { + int i; /* Looping var */ - if (!job->attrs) + for (i = 0; i < job_ids->num_values; i ++) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d!", - job->id); - continue; + if (!cupsdFindJob(job_ids->values[i].integer)) + break; } - if (username[0] && strcasecmp(username, job->username)) - continue; + if (i < job_ids->num_values) + { + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), + job_ids->values[i].integer); + return; + } - if (count > 0) - ippAddSeparator(con->response); + for (i = 0; i < job_ids->num_values; i ++) + { + job = cupsdFindJob(job_ids->values[i].integer); + + if (need_load_job && !job->attrs) + { + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } + } + + if (i > 0) + ippAddSeparator(con->response); - count ++; + exclude = cupsdGetPrivateAttrs(job->printer ? + job->printer->op_policy_ptr : + policy, con, job->printer, + job->username); - copy_job_attrs(con, job, ra); + copy_job_attrs(con, job, ra, exclude); + } } + else + { + for (count = 0, job = (cupsd_job_t *)cupsArrayFirst(list); + (limit <= 0 || count < limit) && job; + job = (cupsd_job_t *)cupsArrayNext(list)) + { + /* + * Filter out jobs that don't match... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", " + "state_value=%d, attrs=%p", job->id, job->dest, + job->username, job->state_value, job->attrs); + + if (!job->dest || !job->username) + cupsdLoadJob(job); + + if (!job->dest || !job->username) + continue; + + if ((dest && strcmp(job->dest, dest)) && + (!job->printer || !dest || strcmp(job->printer->name, dest))) + continue; + if ((job->dtype & dmask) != dtype && + (!job->printer || (job->printer->type & dmask) != dtype)) + continue; - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count); + if ((job_comparison < 0 && job->state_value > job_state) || + (job_comparison == 0 && job->state_value != job_state) || + (job_comparison > 0 && job->state_value < job_state)) + continue; + + if (job->id < first_job_id) + continue; + + current_index ++; + if (current_index < first_index) + continue; + + if (need_load_job && !job->attrs) + { + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } + } + + if (username[0] && _cups_strcasecmp(username, job->username)) + continue; + + if (count > 0) + ippAddSeparator(con->response); + + count ++; + + exclude = cupsdGetPrivateAttrs(job->printer ? + job->printer->op_policy_ptr : + policy, con, job->printer, + job->username); + + copy_job_attrs(con, job, ra, exclude); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count); + } cupsArrayDelete(ra); + if (delete_list) + cupsArrayDelete(list); + con->response->request.status.status_code = IPP_OK; } @@ -7072,7 +6821,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... @@ -7086,7 +6835,7 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ if (!ids) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Missing notify-subscription-ids attribute!")); + _("Missing notify-subscription-ids attribute.")); return; } @@ -7102,8 +6851,7 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ * Bad subscription ID... */ - send_ipp_status(con, IPP_NOT_FOUND, - _("notify-subscription-id %d no good!"), + send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."), ids->values[i].integer); return; } @@ -7169,7 +6917,7 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ * If we don't have any new events, nothing to do here... */ - if (min_seq > (sub->first_event_id + sub->num_events)) + if (min_seq > (sub->first_event_id + cupsArrayCount(sub->events))) continue; /* @@ -7181,12 +6929,13 @@ get_notifications(cupsd_client_t *con) /* I - Client connection */ else j = min_seq - sub->first_event_id; - for (; j < sub->num_events; j ++) + for (; j < cupsArrayCount(sub->events); j ++) { ippAddSeparator(con->response); - copy_attrs(con->response, sub->events[j]->attrs, NULL, - IPP_TAG_EVENT_NOTIFICATION, 0); + copy_attrs(con->response, + ((cupsd_event_t *)cupsArrayIndex(sub->events, j))->attrs, NULL, + IPP_TAG_EVENT_NOTIFICATION, 0, NULL); } } } @@ -7206,18 +6955,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... @@ -7229,14 +6979,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)) { @@ -7254,17 +7013,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... */ @@ -7279,24 +7035,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; @@ -7306,9 +7058,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; } } @@ -7319,9 +7070,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; } @@ -7329,12 +7078,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)); } @@ -7380,7 +7127,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... @@ -7525,7 +7272,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? @@ -7538,7 +7285,7 @@ get_printer_attrs(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -7581,7 +7328,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? @@ -7594,7 +7341,7 @@ get_printer_supported( */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -7612,10 +7359,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; } @@ -7634,7 +7387,7 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ int limit; /* Max number of printers to return */ int count; /* Number of printers that match */ 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 */ @@ -7644,7 +7397,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... @@ -7688,15 +7441,15 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ 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)); @@ -7738,23 +7491,15 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ 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... */ - if (printer->num_users && username && !user_allowed(printer, username)) + if (cupsArrayCount(printer->users) && username && + !user_allowed(printer, username)) continue; /* @@ -7791,12 +7536,20 @@ get_subscription_attrs( { http_status_t status; /* Policy status */ cupsd_subscription_t *sub; /* Subscription */ - cups_array_t *ra; /* Requested attributes array */ + cupsd_policy_t *policy; /* Current security policy */ + cups_array_t *ra, /* Requested attributes array */ + *exclude; /* Private attributes array */ 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? @@ -7808,8 +7561,8 @@ get_subscription_attrs( * Bad subscription ID... */ - send_ipp_status(con, IPP_NOT_FOUND, - _("notify-subscription-id %d no good!"), sub_id); + send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."), + sub_id); return; } @@ -7817,14 +7570,19 @@ get_subscription_attrs( * Check policy... */ - if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr : - DefaultPolicyPtr, - con, sub->owner)) != HTTP_OK) + if (sub->dest) + policy = sub->dest->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, sub->owner)) != HTTP_OK) { send_http_error(con, status, sub->dest); return; } + exclude = cupsdGetPrivateAttrs(policy, con, sub->dest, sub->owner); + /* * Copy the subscription attributes to the response using the * requested-attributes attribute that may be provided by the client. @@ -7832,7 +7590,7 @@ get_subscription_attrs( ra = create_requested_array(con->request); - copy_subscription_attrs(con, sub, ra); + copy_subscription_attrs(con, sub, ra, exclude); cupsArrayDelete(ra); @@ -7866,11 +7624,13 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ int port; /* Port portion of URI */ cupsd_job_t *job; /* Job pointer */ cupsd_printer_t *printer; /* Printer */ + cupsd_policy_t *policy; /* Policy */ + cups_array_t *exclude; /* Private attributes array */ 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? @@ -7895,8 +7655,8 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ if (!job) { - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%s does not exist!"), - resource + 6); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), + atoi(resource + 6)); return; } } @@ -7907,7 +7667,7 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } else if ((attr = ippFindAttribute(con->request, "notify-job-id", @@ -7917,7 +7677,7 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ if (!job) { - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), attr->values[0].integer); return; } @@ -7929,14 +7689,23 @@ get_subscriptions(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ - if ((status = cupsdCheckPolicy(printer ? printer->op_policy_ptr : - DefaultPolicyPtr, - con, NULL)) != HTTP_OK) + if (printer) + policy = printer->op_policy_ptr; + else + policy = DefaultPolicyPtr; + + if ((status = cupsdCheckPolicy(policy, con, NULL)) != HTTP_OK) { send_http_error(con, status, printer); 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. @@ -7965,10 +7734,15 @@ 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); - copy_subscription_attrs(con, sub, ra); + + exclude = cupsdGetPrivateAttrs(sub->dest ? sub->dest->op_policy_ptr : + policy, con, sub->dest, + sub->owner); + + copy_subscription_attrs(con, sub, ra, exclude); count ++; if (limit && count >= limit) @@ -8023,7 +7797,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); /* @@ -8040,7 +7814,7 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -8063,7 +7837,7 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -8081,7 +7855,7 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -8096,6 +7870,22 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ return; } + /* + * See if the job is in a state that allows holding... + */ + + if (job->state_value > IPP_JOB_STOPPED) + { + /* + * Return a "not-possible" error... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job #%d is finished and cannot be altered."), + job->id); + return; + } + /* * Hold the job and return... */ @@ -8136,7 +7926,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? @@ -8149,7 +7939,7 @@ hold_new_jobs(cupsd_client_t *con, /* I - Connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -8170,7 +7960,6 @@ hold_new_jobs(cupsd_client_t *con, /* I - Connection */ printer->holding_new_jobs = 1; cupsdSetPrinterReasons(printer, "+hold-new-jobs"); - cupsdAddPrinterHistory(printer); if (dtype & CUPS_PRINTER_CLASS) cupsdLogMessage(CUPSD_LOG_INFO, @@ -8213,7 +8002,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); /* @@ -8228,7 +8017,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_BAD_REQUEST, - _("job-printer-uri attribute missing!")); + _("job-printer-uri attribute missing.")); return; } @@ -8239,7 +8028,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -8272,7 +8061,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -8291,7 +8080,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("Job #%d does not exist!"), attr->values[0].integer); + _("Job #%d does not exist."), attr->values[0].integer); return; } else @@ -8317,8 +8106,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -8335,8 +8123,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, - _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } else @@ -8378,7 +8165,7 @@ move_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Job #%d is finished and cannot be altered!"), + _("Job #%d is finished and cannot be altered."), job->id); return; } @@ -8415,7 +8202,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; @@ -8528,6 +8315,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 */ @@ -8543,7 +8331,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); /* @@ -8563,7 +8351,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ ) { send_ipp_status(con, IPP_ATTRIBUTES, - _("Unsupported compression \"%s\"!"), + _("Unsupported compression \"%s\"."), attr->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, "compression", NULL, attr->values[0].string.text); @@ -8582,7 +8370,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ if (!con->filename) { - send_ipp_status(con, IPP_BAD_REQUEST, _("No file!?!")); + send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request.")); return; } @@ -8597,7 +8385,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -8605,6 +8393,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) { @@ -8612,14 +8404,16 @@ 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, - _("Could not scan type \"%s\"!"), + _("Bad document-format \"%s\"."), 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, @@ -8629,10 +8423,10 @@ 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, - _("Could not scan type \"%s\"!"), + _("Bad document-format \"%s\"."), default_format); return; } @@ -8643,8 +8437,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")) @@ -8653,12 +8447,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); @@ -8668,6 +8459,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); @@ -8685,11 +8479,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); @@ -8697,7 +8487,9 @@ print_job(cupsd_client_t *con, /* I - Client connection */ else if (!filetype) { send_ipp_status(con, IPP_DOCUMENT_FORMAT, - _("Unsupported format \'%s/%s\'!"), super, type); + _("Unsupported document-format \"%s\"."), + format ? format->values[0].string.text : + "application/octet-stream"); cupsdLogMessage(CUPSD_LOG_INFO, "Hint: Do you have the raw file printing rules enabled?"); @@ -8712,9 +8504,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); /* @@ -8735,8 +8527,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; /* @@ -8746,9 +8539,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); /* @@ -8907,12 +8706,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 */ @@ -8941,14 +8745,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); } /* @@ -8975,7 +8779,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? @@ -8988,7 +8792,7 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -9010,12 +8814,14 @@ 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)); - cupsdAddPrinterHistory(printer); + cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, printer, NULL, + "No longer accepting jobs."); if (dtype & CUPS_PRINTER_CLASS) { @@ -9055,7 +8861,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? @@ -9068,7 +8874,7 @@ release_held_new_jobs( */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -9089,7 +8895,6 @@ release_held_new_jobs( printer->holding_new_jobs = 0; cupsdSetPrinterReasons(printer, "-hold-new-jobs"); - cupsdAddPrinterHistory(printer); if (dtype & CUPS_PRINTER_CLASS) cupsdLogMessage(CUPSD_LOG_INFO, @@ -9100,6 +8905,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... */ @@ -9127,7 +8934,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... @@ -9143,7 +8950,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -9165,8 +8972,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -9184,7 +8990,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -9198,7 +9004,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not possible" error... */ - send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not held!"), jobid); + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not held."), jobid); return; } @@ -9223,13 +9029,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"); } /* @@ -9265,7 +9070,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? @@ -9277,8 +9082,8 @@ renew_subscription( * Bad subscription ID... */ - send_ipp_status(con, IPP_NOT_FOUND, - _("notify-subscription-id %d no good!"), sub_id); + send_ipp_status(con, IPP_NOT_FOUND, _("Subscription #%d does not exist."), + sub_id); return; } @@ -9289,7 +9094,7 @@ renew_subscription( */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Job subscriptions cannot be renewed!")); + _("Job subscriptions cannot be renewed.")); return; } @@ -9353,7 +9158,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... @@ -9369,7 +9174,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -9391,8 +9196,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -9410,7 +9214,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -9424,7 +9228,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not possible" error... */ - send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not complete!"), + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not complete."), jobid); return; } @@ -9442,7 +9246,7 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Job #%d cannot be restarted - no files!"), jobid); + _("Job #%d cannot be restarted - no files."), jobid); return; } @@ -9509,7 +9313,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 */ @@ -9558,60 +9362,103 @@ 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->gss_uid > 0) + { + cupsFilePrintf(fp, "uid %d\n", (int)con->gss_uid); + cupsdSetStringf(&job->auth_uid, "AUTH_UID=%d", (int)con->gss_uid); + } +#endif /* HAVE_GSSAPI */ + /* * Write a random number of newlines to the end of the file... */ - for (i = (rand() % 1024); i >= 0; i --) + for (i = (CUPS_RAND() % 1024); i >= 0; i --) cupsFilePutChar(fp, '\n'); /* @@ -9619,52 +9466,7 @@ save_auth_info( */ cupsFileClose(fp); - -#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H) -# ifdef HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID - if (con->have_gss && - (con->http.hostaddr->addr.sa_family == AF_LOCAL || con->gss_creds)) -# else - if (con->have_gss && con->gss_creds) -# endif /* HAVE_KRB5_IPC_CLIENT_SET_TARGET_UID */ - save_krb5_creds(con, job); - else if (job->ccname) - cupsdClearString(&(job->ccname)); -#endif /* HAVE_GSSAPI && HAVE_KRB5_H */ -} - - -#if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H) -/* - * 'save_krb5_creds()' - Save Kerberos credentials for the job. - */ - -static void -save_krb5_creds(cupsd_client_t *con, /* I - Client connection */ - cupsd_job_t *job) /* I - Job */ -{ - /* - * Get the credentials... - */ - - job->ccache = cupsdCopyKrb5Creds(con); - - /* - * Add the KRB5CCNAME environment variable to the job so that the - * backend can use the credentials when printing. - */ - - if (job->ccache) - { - cupsdSetStringf(&(job->ccname), "KRB5CCNAME=FILE:%s", - krb5_cc_get_name(KerberosContext, job->ccache)); - - cupsdLogJob(job, CUPSD_LOG_DEBUG2, "save_krb5_creds: %s", job->ccname); - } - else - cupsdClearString(&(job->ccname)); } -#endif /* HAVE_GSSAPI && HAVE_KRB5_H */ /* @@ -9708,7 +9510,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... @@ -9724,7 +9526,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -9746,8 +9548,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -9765,7 +9566,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -9798,7 +9599,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ #endif /* HAVE_LIBZ */ ) { - send_ipp_status(con, IPP_ATTRIBUTES, _("Unsupported compression \"%s\"!"), + send_ipp_status(con, IPP_ATTRIBUTES, _("Unsupported compression \"%s\"."), attr->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, "compression", NULL, attr->values[0].string.text); @@ -9815,9 +9616,25 @@ 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) { - send_ipp_status(con, IPP_BAD_REQUEST, _("No file!?!")); + /* + * Check for an empty request with "last-document" set to true, which is + * used to close an "open" job by RFC 2911, section 3.3.2. + */ + + if (job->num_files > 0 && attr->values[0].boolean) + goto last_document; + + send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request.")); return; } @@ -9825,6 +9642,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) { @@ -9832,13 +9651,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\"!"), + 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, @@ -9848,11 +9669,10 @@ 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, - _("Could not scan type \"%s\"!"), - default_format); + _("Bad document-format-default \"%s\"."), default_format); return; } } @@ -9862,8 +9682,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")) @@ -9885,8 +9705,12 @@ send_document(cupsd_client_t *con, /* I - Client connection */ if (!filetype) filetype = mimeType(MimeDatabase, super, type); - cupsdLogJob(job, CUPSD_LOG_DEBUG, "Request file type is %s/%s.", - filetype->super, filetype->type); + 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); @@ -9903,11 +9727,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); @@ -9915,7 +9735,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ else if (!filetype) { send_ipp_status(con, IPP_DOCUMENT_FORMAT, - _("Unsupported format \'%s/%s\'!"), super, type); + _("Unsupported document-format \"%s/%s\"."), super, type); cupsdLogMessage(CUPSD_LOG_INFO, "Hint: Do you have the raw file printing rules enabled?"); @@ -9932,7 +9752,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ filetype->type); send_ipp_status(con, IPP_DOCUMENT_FORMAT, - _("Unsupported format \'%s\'!"), mimetype); + _("Unsupported document-format \"%s\"."), mimetype); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, "document-format", NULL, mimetype); @@ -9944,11 +9764,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 @@ -9956,13 +9777,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); @@ -9973,6 +9800,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Start the job if this is the last document... */ + last_document: + if ((attr = ippFindAttribute(con->request, "last-document", IPP_TAG_BOOLEAN)) != NULL && attr->values[0].boolean) @@ -9988,6 +9817,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) { @@ -9999,7 +9830,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; @@ -10018,8 +9853,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); } @@ -10030,9 +9867,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); @@ -10040,7 +9876,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; @@ -10071,11 +9908,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) { @@ -10123,7 +9962,7 @@ send_http_error( if (auth) { if (auth->type == CUPSD_AUTH_DEFAULT) - auth_type = DefaultAuthType; + auth_type = cupsdDefaultAuthType(); else auth_type = auth->type; } @@ -10169,7 +10008,7 @@ send_ipp_status(cupsd_client_t *con, /* I - Client connection */ if (ippFindAttribute(con->response, "attributes-charset", IPP_TAG_ZERO) == NULL) ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_CHARSET, - "attributes-charset", NULL, DefaultCharset); + "attributes-charset", NULL, "utf-8"); if (ippFindAttribute(con->response, "attributes-natural-language", IPP_TAG_ZERO) == NULL) @@ -10196,7 +10035,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? @@ -10209,7 +10048,7 @@ set_default(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -10238,7 +10077,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\".", @@ -10278,7 +10117,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... @@ -10300,7 +10139,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ IPP_TAG_INTEGER)) == NULL) { send_ipp_status(con, IPP_BAD_REQUEST, - _("Got a printer-uri attribute but no job-id!")); + _("Got a printer-uri attribute but no job-id.")); return; } @@ -10322,8 +10161,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Not a valid URI! */ - send_ipp_status(con, IPP_BAD_REQUEST, - _("Bad job-uri attribute \"%s\"!"), + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri \"%s\"."), uri->values[0].string.text); return; } @@ -10341,7 +10179,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Nope - return a "not found" error... */ - send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), jobid); return; } @@ -10356,7 +10194,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Job #%d is finished and cannot be altered!"), jobid); + _("Job #%d is finished and cannot be altered."), jobid); return; } @@ -10387,15 +10225,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") || @@ -10405,9 +10246,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)) { /* @@ -10417,9 +10255,8 @@ 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; } @@ -10431,10 +10268,10 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (attr->value_tag != IPP_TAG_INTEGER) { - send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value!")); + 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) { @@ -10461,10 +10298,10 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (attr->value_tag != IPP_TAG_ENUM) { - send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value!")); + 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 { @@ -10482,9 +10319,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; @@ -10538,13 +10373,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); + ippCopyAttribute(job->attrs, attr, 0); /* * See if the job-name or job-hold-until is being changed. @@ -10585,7 +10420,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; } @@ -10596,7 +10431,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; } @@ -10652,7 +10487,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? @@ -10665,7 +10500,7 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -10690,6 +10525,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) { @@ -10703,6 +10556,8 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ if (changed) { + printer->config_time = time(NULL); + cupsdSetPrinterAttrs(printer); cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); @@ -10730,7 +10585,7 @@ set_printer_defaults( { 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 */ @@ -10772,7 +10627,7 @@ set_printer_defaults( } else if (!strcmp(attr->name, "requesting-user-name-allowed")) { - cupsdFreePrinterUsers(printer); + cupsdFreeStrings(&(printer->users)); printer->deny_users = 0; @@ -10781,12 +10636,12 @@ set_printer_defaults( strcmp(attr->values[0].string.text, "all"))) { for (i = 0; i < attr->num_values; i ++) - cupsdAddPrinterUser(printer, attr->values[i].string.text); + cupsdAddString(&(printer->users), attr->values[i].string.text); } } else if (!strcmp(attr->name, "requesting-user-name-denied")) { - cupsdFreePrinterUsers(printer); + cupsdFreeStrings(&(printer->users)); printer->deny_users = 1; @@ -10795,7 +10650,7 @@ set_printer_defaults( strcmp(attr->values[0].string.text, "none"))) { for (i = 0; i < attr->num_values; i ++) - cupsdAddPrinterUser(printer, attr->values[i].string.text); + cupsdAddString(&(printer->users), attr->values[i].string.text); } } else if (!strcmp(attr->name, "job-quota-period")) @@ -10861,7 +10716,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")))) @@ -10905,6 +10760,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, @@ -10951,7 +10807,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)); @@ -10975,13 +10831,14 @@ static void start_printer(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { + int i; /* Temporary variable */ http_status_t status; /* Policy status */ cups_ptype_t dtype; /* Destination type (printer/class) */ cupsd_printer_t *printer; /* Printer data */ 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? @@ -10994,7 +10851,7 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -11025,6 +10882,21 @@ start_printer(cupsd_client_t *con, /* I - Client connection */ cupsdCheckJobs(); + /* + * Check quotas... + */ + + if ((i = check_quotas(con, printer)) < 0) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached.")); + return; + } + else if (i == 0) + { + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Not allowed to print.")); + return; + } + /* * Everything was ok, so return OK status... */ @@ -11048,7 +10920,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? @@ -11061,7 +10933,7 @@ stop_printer(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -11081,7 +10953,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, @@ -11112,7 +10984,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 */ @@ -11138,8 +11010,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; @@ -11158,7 +11029,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 */ @@ -11208,13 +11079,13 @@ static int /* O - 0 if not allowed, 1 if allowed */ user_allowed(cupsd_printer_t *p, /* I - Printer or class */ const char *username) /* I - Username */ { - int i; /* Looping var */ struct passwd *pw; /* User password data */ char baseuser[256], /* Base username */ - *baseptr; /* Pointer to "@" in base username */ + *baseptr, /* Pointer to "@" in base username */ + *name; /* Current user name */ - if (p->num_users == 0) + if (cupsArrayCount(p->users) == 0) return (1); if (!strcmp(username, "root")) @@ -11237,31 +11108,33 @@ user_allowed(cupsd_printer_t *p, /* I - Printer or class */ pw = getpwnam(username); endpwent(); - for (i = 0; i < p->num_users; i ++) + for (name = (char *)cupsArrayFirst(p->users); + name; + name = (char *)cupsArrayNext(p->users)) { - if (p->users[i][0] == '@') + if (name[0] == '@') { /* * Check group membership... */ - if (cupsdCheckGroup(username, pw, p->users[i] + 1)) + if (cupsdCheckGroup(username, pw, name + 1)) break; } - else if (p->users[i][0] == '#') + else if (name[0] == '#') { /* * Check UUID... */ - if (cupsdCheckGroup(username, pw, p->users[i])) + if (cupsdCheckGroup(username, pw, name)) break; } - else if (!strcasecmp(username, p->users[i])) + else if (!_cups_strcasecmp(username, name)) break; } - return ((i < p->num_users) != p->deny_users); + return ((name != NULL) != p->deny_users); } @@ -11275,7 +11148,11 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ ipp_attribute_t *attr; /* Current attribute */ - ipp_attribute_t *format; /* Document-format 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 */ @@ -11285,7 +11162,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 @@ -11293,15 +11170,21 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ */ if ((attr = ippFindAttribute(con->request, "compression", - IPP_TAG_KEYWORD)) != NULL && - !strcmp(attr->values[0].string.text, "none")) + IPP_TAG_KEYWORD)) != NULL) { - send_ipp_status(con, IPP_ATTRIBUTES, - _("Unsupported compression attribute %s!"), - attr->values[0].string.text); - ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, - "compression", NULL, attr->values[0].string.text); - return; + if (strcmp(attr->values[0].string.text, "none") +#ifdef HAVE_LIBZ + && strcmp(attr->values[0].string.text, "gzip") +#endif /* HAVE_LIBZ */ + ) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("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); + return; + } } /* @@ -11311,10 +11194,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; } @@ -11325,7 +11209,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 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); @@ -11333,6 +11217,86 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ } } + /* + * Is the job-name valid? + */ + + if ((name = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) != NULL) + { + int bad_name = 0; /* Is the job-name value bad? */ + + if ((name->value_tag != IPP_TAG_NAME && name->value_tag != IPP_TAG_NAMELANG) || + name->num_values != 1) + { + bad_name = 1; + } + else + { + /* + * Validate that job-name conforms to RFC 5198 (Network Unicode) and + * IPP Everywhere requirements for "name" values... + */ + + const unsigned char *nameptr; /* Pointer into "job-name" attribute */ + + for (nameptr = (unsigned char *)name->values[0].string.text; + *nameptr; + nameptr ++) + { + if (*nameptr < ' ' && *nameptr != '\t') + break; + else if (*nameptr == 0x7f) + break; + else if ((*nameptr & 0xe0) == 0xc0) + { + if ((nameptr[1] & 0xc0) != 0x80) + break; + + nameptr ++; + } + else if ((*nameptr & 0xf0) == 0xe0) + { + if ((nameptr[1] & 0xc0) != 0x80 || + (nameptr[2] & 0xc0) != 0x80) + break; + + nameptr += 2; + } + else if ((*nameptr & 0xf8) == 0xf0) + { + if ((nameptr[1] & 0xc0) != 0x80 || + (nameptr[2] & 0xc0) != 0x80 || + (nameptr[3] & 0xc0) != 0x80) + break; + + nameptr += 3; + } + else if (*nameptr & 0x80) + break; + } + + if (*nameptr) + bad_name = 1; + } + + if (bad_name) + { + if (StrictConformance) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("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? */ @@ -11344,7 +11308,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ */ send_ipp_status(con, IPP_NOT_FOUND, - _("The printer or class was not found.")); + _("The printer or class does not exist.")); return; } @@ -11352,11 +11316,34 @@ 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) { send_http_error(con, status, printer); return; } + else if (printer->num_auth_info_required == 1 && + !strcmp(printer->auth_info_required[0], "negotiate") && + !con->username[0]) + { + send_http_error(con, HTTP_UNAUTHORIZED, printer); + return; + } +#ifdef HAVE_SSL + else if (auth_info && !con->http->tls && + !httpAddrLocalhost(con->http->hostaddr)) + { + /* + * Require encryption of auth-info over non-local connections... + */ + + send_http_error(con, HTTP_UPGRADE_REQUIRED, printer); + return; + } +#endif /* HAVE_SSL */ /* * Everything was ok, so return OK status... @@ -11401,16 +11388,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... @@ -11434,8 +11417,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 $". - */