X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=scheduler%2Fipp.c;h=c0c2222f003a57ba32b918edb69102ba08bbb983;hb=26c14fa6e1b9639d47aca3032337d9fe728ee2dc;hp=f711b8bd0ad27e1679b33f8f641f1770df637e7a;hpb=7cf5915ead7c80b3011a37eaade214568d938f5b;p=thirdparty%2Fcups.git diff --git a/scheduler/ipp.c b/scheduler/ipp.c index f711b8bd0..c0c2222f0 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,110 +1,17 @@ /* - * "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $" + * IPP routines for the CUPS scheduler. * - * IPP routines for the CUPS scheduler. + * Copyright 2007-2016 by Apple Inc. + * Copyright 1997-2007 by Easy Software Products, all rights reserved. * - * Copyright 2007-2010 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products, all rights reserved. + * This file contains Kerberos support code, copyright 2006 by + * Jelmer Vernooij. * - * This file contains Kerberos support code, copyright 2006 by - * Jelmer Vernooij. - * - * These coded instructions, statements, and computer programs are the - * property of Apple Inc. and are protected by Federal copyright - * law. Distribution and use rights are outlined in the file "LICENSE.txt" - * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". - * - * Contents: - * - * cupsdProcessIPPRequest() - Process an incoming IPP request. - * cupsdTimeoutJob() - Timeout a job waiting on job files. - * accept_jobs() - Accept print jobs to a printer. - * add_class() - Add a class to the system. - * add_file() - Add a file to a job. - * add_job() - Add a job to a print queue. - * add_job_state_reasons() - Add the "job-state-reasons" attribute based - * upon the job and printer state... - * add_job_subscriptions() - Add any subscriptions for a job. - * add_job_uuid() - Add job-uuid attribute to a job. - * add_printer() - Add a printer to the system. - * add_printer_state_reasons() - Add the "printer-state-reasons" attribute - * based upon the printer state... - * add_queued_job_count() - Add the "queued-job-count" attribute for the - * specified printer or class. - * apple_init_profile() - Initialize a color profile. - * apple_register_profiles() - Register color profiles for a printer. - * apple_unregister_profiles() - Remove color profiles for the specified - * printer. - * apply_printer_defaults() - Apply printer default options to a job. - * authenticate_job() - Set job authentication info. - * cancel_all_jobs() - Cancel all or selected print jobs. - * cancel_job() - Cancel a print job. - * cancel_subscription() - Cancel a subscription. - * check_rss_recipient() - Check that we do not have a duplicate RSS - * feed URI. - * check_quotas() - Check quotas for a printer and user. - * close_job() - Close a multi-file job. - * copy_attribute() - Copy a single attribute. - * copy_attrs() - Copy attributes from one request to another. - * copy_banner() - Copy a banner file to the requests directory - * for the specified job. - * copy_file() - Copy a PPD file or interface script... - * copy_model() - Copy a PPD model file, substituting default - * values as needed... - * copy_job_attrs() - Copy job attributes. - * copy_printer_attrs() - Copy printer attributes. - * copy_subscription_attrs() - Copy subscription attributes. - * create_job() - Print a file to a printer or class. - * create_requested_array() - Create an array for the requested-attributes. - * create_subscription() - Create a notification subscription. - * delete_printer() - Remove a printer or class from the system. - * get_default() - Get the default destination. - * get_devices() - Get the list of available devices on the - * local system. - * get_document() - Get a copy of a job file. - * get_job_attrs() - Get job attributes. - * get_jobs() - Get a list of jobs for the specified printer. - * get_notifications() - Get events for a subscription. - * get_ppd() - Get a named PPD from the local system. - * get_ppds() - Get the list of PPD files on the local - * system. - * get_printer_attrs() - Get printer attributes. - * get_printer_supported() - Get printer supported values. - * get_printers() - Get a list of printers or classes. - * get_subscription_attrs() - Get subscription attributes. - * get_subscriptions() - Get subscriptions. - * get_username() - Get the username associated with a request. - * hold_job() - Hold a print job. - * hold_new_jobs() - Hold pending/new jobs on a printer or class. - * move_job() - Move a job to a new destination. - * ppd_parse_line() - Parse a PPD default line. - * print_job() - Print a file to a printer or class. - * read_job_ticket() - Read a job ticket embedded in a print file. - * reject_jobs() - Reject print jobs to a printer. - * release_held_new_jobs() - Release pending/new jobs on a printer or - * class. - * release_job() - Release a held print job. - * renew_subscription() - Renew an existing subscription... - * restart_job() - Restart an old print job. - * save_auth_info() - Save authentication information for a job. - * 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/". */ /* @@ -115,8 +22,9 @@ #include #ifdef __APPLE__ -# include -# include +/*# include +extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id); +# include */ # ifdef HAVE_MEMBERSHIP_H # include # endif /* HAVE_MEMBERSHIP_H */ @@ -140,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); @@ -163,28 +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); @@ -215,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); @@ -234,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); /* @@ -264,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... @@ -292,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]); } @@ -309,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 { @@ -341,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; } @@ -375,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; @@ -407,8 +311,8 @@ 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... @@ -418,10 +322,10 @@ cupsdProcessIPPRequest( 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 || @@ -445,7 +349,7 @@ cupsdProcessIPPRequest( 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) @@ -455,7 +359,7 @@ cupsdProcessIPPRequest( 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) @@ -466,7 +370,7 @@ cupsdProcessIPPRequest( 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..."); @@ -480,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 { @@ -497,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); } } @@ -529,188 +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_CANCEL_JOBS : - case IPP_CANCEL_MY_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 IPP_CLOSE_JOB : + case IPP_OP_CLOSE_JOB : close_job(con, uri); break; - case CUPS_GET_DEFAULT : + 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; @@ -729,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 @@ -848,8 +740,7 @@ cupsdTimeoutJob(cupsd_job_t *job) /* I - Job to timeout */ printer = cupsdFindDest(job->dest); attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); - if (printer && - !(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) && + if (printer && !(printer->type & CUPS_PRINTER_REMOTE) && attr && attr->num_values > 1) { /* @@ -883,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? @@ -896,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; } @@ -917,8 +808,6 @@ 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."); @@ -966,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? @@ -1020,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; } @@ -1046,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) { @@ -1111,10 +948,18 @@ add_class(cupsd_client_t *con, /* I - Client connection */ need_restart_job = 0; - if ((attr = ippFindAttribute(con->request, "printer-location", - IPP_TAG_TEXT)) != NULL) + if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL) cupsdSetString(&pclass->location, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4)) + cupsdSetString(&pclass->geo_location, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&pclass->organization, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&pclass->organizational_unit, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) cupsdSetString(&pclass->info, attr->values[0].string.text); @@ -1128,23 +973,31 @@ add_class(cupsd_client_t *con, /* I - Client connection */ 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", @@ -1154,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; } @@ -1175,7 +1028,6 @@ 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); @@ -1212,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; } @@ -1236,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... */ @@ -1266,8 +1120,6 @@ add_class(cupsd_client_t *con, /* I - Client connection */ } else { - cupsdAddPrinterHistory(pclass); - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, pclass, NULL, "New class \"%s\" added by \"%s\".", pclass->name, get_username(con)); @@ -1296,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); /* @@ -1311,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, @@ -1324,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 ++; @@ -1355,6 +1211,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ http_status_t status; /* Policy status */ ipp_attribute_t *attr, /* Current attribute */ *auth_info; /* auth-info attribute */ + const char *mandatory; /* Current mandatory job attribute */ const char *val; /* Default option value */ int priority; /* Job priority */ cupsd_job_t *job; /* Current job */ @@ -1366,10 +1223,35 @@ add_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *media_col, /* media-col attribute */ *media_margin; /* media-*-margin attribute */ ipp_t *unsup_col; /* media-col in unsupported response */ + static const char * const readonly[] =/* List of read-only attributes */ + { + "date-time-at-completed", + "date-time-at-creation", + "date-time-at-processing", + "job-detailed-status-messages", + "job-document-access-errors", + "job-id", + "job-impressions-completed", + "job-k-octets-completed", + "job-media-sheets-completed", + "job-pages-completed", + "job-printer-up-time", + "job-printer-uri", + "job-state", + "job-state-message", + "job-state-reasons", + "job-uri", + "number-of-documents", + "number-of-intervening-jobs", + "output-device-assigned", + "time-at-completed", + "time-at-creation", + "time-at-processing" + }; cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job(%p[%d], %p(%s), %p(%s/%s))", - con, con->http.fd, printer, printer->name, + con, con->number, printer, printer->name, filetype, filetype ? filetype->super : "none", filetype ? filetype->type : "none"); @@ -1378,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); } @@ -1405,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... @@ -1431,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)) { @@ -1445,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); @@ -1472,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); } @@ -1488,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); } @@ -1537,7 +1456,7 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if (!ippFindAttribute(con->request, "PageRegion", IPP_TAG_ZERO) && !ippFindAttribute(con->request, "PageSize", IPP_TAG_ZERO) && - _pwgGetPageSize(printer->pwg, con->request, NULL, &exact)) + _ppdCacheGetPageSize(printer->pc, con->request, NULL, &exact)) { if (!exact && (media_col = ippFindAttribute(con->request, "media-col", @@ -1585,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); } @@ -1620,27 +1538,43 @@ add_job(cupsd_client_t *con, /* I - Client connection */ priority); } - if (!ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) - ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, - "Untitled"); + if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) == NULL) + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); + else if ((attr->value_tag != IPP_TAG_NAME && + attr->value_tag != IPP_TAG_NAMELANG) || + attr->num_values != 1) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("Bad job-name value: Wrong type or count.")); + if ((attr = ippCopyAttribute(con->response, attr, 0)) != NULL) + attr->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + 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); @@ -1650,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) { @@ -1668,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) @@ -1685,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) { @@ -1694,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 { @@ -1752,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... @@ -1772,13 +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); - 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); @@ -1795,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... @@ -1805,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) { @@ -1816,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... @@ -1834,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; @@ -1861,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\", " @@ -1878,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\", " @@ -1918,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) @@ -1952,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); @@ -1970,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); @@ -1986,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; @@ -2017,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. */ @@ -2157,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; @@ -2169,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; @@ -2178,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); @@ -2193,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; @@ -2205,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; } @@ -2214,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; } @@ -2225,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; } @@ -2269,7 +2120,7 @@ add_job_subscriptions( { sub->user_data_len = user_data->values[0].unknown.length; memcpy(sub->user_data, user_data->values[0].unknown.data, - sub->user_data_len); + (size_t)sub->user_data_len); } ippAddSeparator(con->response); @@ -2304,7 +2155,7 @@ add_job_subscriptions( * Free and remove this attribute... */ - _ippFreeAttr(attr); + ippDeleteAttribute(NULL, attr); if (prev) prev->next = next; @@ -2327,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... - */ + char uuid[64]; /* job-uuid string */ - 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... - */ - - 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))); } @@ -2394,15 +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 changed_driver, /* Changed the PPD/interface script? */ + int changed_driver, /* Changed the PPD? */ need_restart_job, /* Need to restart job? */ set_device_uri, /* Did we set the device URI? */ set_port_monitor; /* Did we set the port monitor? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Do we have a valid URI? @@ -2450,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; } @@ -2476,58 +2296,6 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer = cupsdAddPrinter(resource + 10); modify = 0; } - else if (printer->type & CUPS_PRINTER_IMPLICIT) - { - /* - * Check the default policy, then rename the implicit printer to - * "AnyPrinter" or delete it... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - if (ImplicitAnyClasses) - { - snprintf(newname, sizeof(newname), "Any%s", resource + 10); - cupsdRenamePrinter(printer, newname); - } - else - cupsdDeletePrinter(printer, 1); - - /* - * Add the printer as a new local printer... - */ - - printer = cupsdAddPrinter(resource + 10); - modify = 0; - } - else if (printer->type & CUPS_PRINTER_DISCOVERED) - { - /* - * Check the default policy, then rename the remote printer to - * "Printer@server"... - */ - - if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) - { - send_http_error(con, status, NULL); - return; - } - - snprintf(newname, sizeof(newname), "%s@%s", resource + 10, - printer->hostname); - cupsdRenamePrinter(printer, newname); - - /* - * Add the printer as a new local printer... - */ - - printer = cupsdAddPrinter(resource + 10); - modify = 0; - } else if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) { @@ -2544,10 +2312,22 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ changed_driver = 0; need_restart_job = 0; + if ((attr = ippFindAttribute(con->request, "printer-is-temporary", IPP_TAG_BOOLEAN)) != NULL) + printer->temporary = ippGetBoolean(attr, 0); + if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL) cupsdSetString(&printer->location, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI)) != NULL && !strncmp(attr->values[0].string.text, "geo:", 4)) + cupsdSetString(&printer->geo_location, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organization", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&printer->organization, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-organizational-unit", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&printer->organizational_unit, attr->values[0].string.text); + if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) cupsdSetString(&printer->info, attr->values[0].string.text); @@ -2564,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; @@ -2575,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; } @@ -2597,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; } @@ -2617,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; } } @@ -2661,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; } @@ -2688,24 +2485,43 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ 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) - cupsdDeregisterPrinter(printer, 1); - - cupsdLogMessage(CUPSD_LOG_INFO, + 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", @@ -2714,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; } @@ -2736,7 +2552,6 @@ 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); @@ -2749,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]))); @@ -2800,7 +2615,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ cupsdSetString(&printer->device_uri, "file:///dev/null"); /* - * See if we have an interface script or PPD file attached to the request... + * See if we have a PPD file attached to the request... */ if (con->filename) @@ -2824,146 +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; - } + /* + * The new file is a PPD file, so move the file over to the ppd + * directory... + */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "Copied PPD file successfully"); - chmod(dstfile, 0644); - } - else + if (copy_file(srcfile, dstfile, ConfigFilePerm)) { - /* - * This must be an interface script, so remove any old PPD file that - * may be lying around... - */ - - 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"); } } if (changed_driver) { /* - * If we changed the PPD/interface script, then remove the printer's cache - * file and clear the printer-state-reasons... + * If we changed the PPD, then remove the printer's cache file and clear the + * printer-state-reasons... */ char cache_name[1024]; /* Cache filename for printer attrs */ - snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp4", CacheDir, - printer->name); - unlink(cache_name); - - snprintf(cache_name, sizeof(cache_name), "%s/%s.pwg3", CacheDir, + snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, printer->name); unlink(cache_name); cupsdSetPrinterReasons(printer, "none"); -#ifdef __APPLE__ /* * (Re)register color profiles... */ - if (!RunUser) - { - apple_unregister_profiles(printer); - apple_register_profiles(printer); - } -#endif /* __APPLE__ */ + cupsdRegisterColor(printer); } /* @@ -2983,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; @@ -3008,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) { @@ -3038,613 +2799,64 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ } else { - cupsdAddPrinterHistory(printer); - cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, printer, NULL, "New printer \"%s\" added by \"%s\".", - printer->name, get_username(con)); - - cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".", - printer->name, get_username(con)); - } - - con->response->request.status.status_code = IPP_OK; -} - - -/* - * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute - * based upon the printer state... - */ - -static void -add_printer_state_reasons( - cupsd_client_t *con, /* I - Client connection */ - cupsd_printer_t *p) /* I - Printer info */ -{ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "add_printer_state_reasons(%p[%d], %p[%s])", - con, con->http.fd, p, p->name); - - if (p->num_reasons == 0) - ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", NULL, "none"); - else - ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", p->num_reasons, NULL, - (const char * const *)p->reasons); -} - - -/* - * 'add_queued_job_count()' - Add the "queued-job-count" attribute for - * the specified printer or class. - */ - -static void -add_queued_job_count( - cupsd_client_t *con, /* I - Client connection */ - cupsd_printer_t *p) /* I - Printer or class */ -{ - int count; /* Number of jobs on destination */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])", - con, con->http.fd, p, p->name); - - count = cupsdGetPrinterJobCount(p->name); - - ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, - "queued-job-count", count); -} - - -#ifdef __APPLE__ -/* - * 'apple_init_profile()' - Initialize a color profile. - */ - -static void -apple_init_profile( - ppd_file_t *ppd, /* I - PPD file */ - cups_array_t *languages, /* I - Languages in the PPD file */ - 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 */ -{ - 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 */ - - - /* - * Build the profile name dictionary... - */ - - 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)) - { - if (iccfile) - { - if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name, - language)) == NULL) - attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language); - } - else - attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language); - - if (attr && attr->text[0]) - { - cflang = CFStringCreateWithCString(kCFAllocatorDefault, language, - kCFStringEncodingUTF8); - cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text, - kCFStringEncodingUTF8); - - if (cflang && cftext) - CFDictionarySetValue(dict, cflang, cftext); - - if (cflang) - CFRelease(cflang); - - if (cftext) - CFRelease(cftext); - } - } - - cupsArrayRestore(ppd->sorted_attrs); - } - - /* - * Fill in the profile data... - */ - - 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)); -} - - -/* - * 'apple_register_profiles()' - Register color profiles for a printer. - */ - -static void -apple_register_profiles( - cupsd_printer_t *p) /* I - Printer */ -{ - int i; /* Looping var */ - char ppdfile[1024], /* PPD filename */ - iccfile[1024], /* ICC filename */ - selector[PPD_MAX_NAME]; - /* Profile selection string */ - ppd_file_t *ppd; /* PPD file */ - ppd_attr_t *attr, /* Profile attributes */ - *profileid_attr,/* cupsProfileID attribute */ - *q1_attr, /* ColorModel (or other) qualifier */ - *q2_attr, /* MediaType (or other) qualifier */ - *q3_attr; /* Resolution (or other) qualifier */ - char q_keyword[PPD_MAX_NAME]; - /* Qualifier keyword */ - const char *q1_choice, /* ColorModel (or other) choice */ - *q2_choice, /* MediaType (or other) choice */ - *q3_choice; /* Resolution (or other) choice */ - const char *profile_key; /* Profile keyword */ - ppd_option_t *cm_option; /* Color model option */ - ppd_choice_t *cm_choice; /* Color model choice */ - int num_profiles; /* Number of profiles */ - 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; - - /* - * Try opening the PPD file for this printer... - */ - - snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name); - if ((ppd = ppdOpenFile(ppdfile)) == NULL) - return; - - /* - * See if we have any profiles... - */ - - if ((attr = ppdFindAttr(ppd, "APTiogaProfile", NULL)) != NULL) - profile_key = "APTiogaProfile"; - else - { - attr = ppdFindAttr(ppd, "cupsICCProfile", NULL); - profile_key = "cupsICCProfile"; - } - - for (num_profiles = 0; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL)) - if (attr->spec[0] && attr->value && attr->value[0]) - { - if (attr->value[0] != '/') - snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir, - attr->value); - else - strlcpy(iccfile, attr->value, sizeof(iccfile)); - - if (access(iccfile, 0)) - continue; - - num_profiles ++; - } - - - /* - * If we have profiles, add them... - */ - - if (num_profiles > 0) - { - if (profile_key[0] == 'A') - { - /* - * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile - * attribute... - */ - - if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL && - attr->value) - default_profile_id = atoi(attr->value); - - q1_choice = q2_choice = q3_choice = NULL; - } - else - { - /* - * For CUPS PPDs, figure out the default profile selector values... - */ - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q1_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL) - q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL); - - if (q1_attr && q1_attr->value && q1_attr->value[0]) - q1_choice = q1_attr->value; - else - q1_choice = ""; - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q2_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else - q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL); - - if (q2_attr && q2_attr->value && q2_attr->value[0]) - q2_choice = q2_attr->value; - else - q2_choice = NULL; - - if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL && - attr->value && attr->value[0]) - { - snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); - q3_attr = ppdFindAttr(ppd, q_keyword, NULL); - } - else - q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL); - - if (q3_attr && q3_attr->value && q3_attr->value[0]) - q3_choice = q3_attr->value; - else - q3_choice = NULL; - } - - /* - * 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... - */ + printer->name, get_username(con)); - if (error != noErr) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to register ICC color profiles for \"%s\" - %d", - p->name, (int)error); + cupsdLogMessage(CUPSD_LOG_INFO, "New printer \"%s\" added by \"%s\".", + printer->name, get_username(con)); + } - for (profile = profiles->profiles; - num_profiles > 0; - profile ++, num_profiles --) - CFRelease(profile->profileName); + con->response->request.status.status_code = IPP_OK; +} - free(profiles); - if (printer_name) - CFRelease(printer_name); +/* + * 'add_printer_state_reasons()' - Add the "printer-state-reasons" attribute + * based upon the printer state... + */ - if (device_name) - CFRelease(device_name); - } +static void +add_printer_state_reasons( + cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *p) /* I - Printer info */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_state_reasons(%p[%d], %p[%s])", + con, con->number, p, p->name); - ppdClose(ppd); + if (p->num_reasons == 0) + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", NULL, "none"); + else + ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", p->num_reasons, NULL, + (const char * const *)p->reasons); } /* - * 'apple_unregister_profiles()' - Remove color profiles for the specified - * printer. + * 'add_queued_job_count()' - Add the "queued-job-count" attribute for + * the specified printer or class. */ static void -apple_unregister_profiles( - cupsd_printer_t *p) /* I - Printer */ +add_queued_job_count( + cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *p) /* I - Printer or class */ { - /* - * Make sure ColorSync is available... - */ + int count; /* Number of jobs on destination */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])", + con, con->number, p, p->name); + + count = cupsdGetPrinterJobCount(p->name); - if (CMUnregisterColorDevice != NULL) - CMUnregisterColorDevice(cmPrinterDeviceClass, _ppdHashName(p->name)); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "queued-job-count", count); } -#endif /* __APPLE__ */ + /* * 'apply_printer_defaults()' - Apply printer default options to a job. @@ -3709,7 +2921,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)", - con, con->http.fd, uri->values[0].string.text); + con, con->number, uri->values[0].string.text); /* * Start with "everything is OK" status... @@ -3731,7 +2943,7 @@ authenticate_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; } @@ -3753,7 +2965,7 @@ authenticate_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; } @@ -3771,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; } @@ -3787,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; } @@ -3802,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... @@ -3815,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; } @@ -3846,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"); } /* @@ -3856,7 +3066,11 @@ 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(); } @@ -3886,7 +3100,7 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Get the jobs to cancel/purge... @@ -3910,7 +3124,7 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ else { send_ipp_status(con, IPP_BAD_REQUEST, - _("Missing requesting-user-name attribute")); + _("Missing requesting-user-name attribute.")); return; } } @@ -3935,7 +3149,7 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ else { send_ipp_status(con, IPP_BAD_REQUEST, - _("Missing requesting-user-name attribute")); + _("Missing requesting-user-name attribute.")); return; } @@ -3952,7 +3166,7 @@ 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; } @@ -3975,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; } @@ -3993,13 +3207,17 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ { for (i = 0; i < job_ids->num_values; i ++) { - if (!cupsdFindJob(job_ids->values[i].integer)) + if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL) break; + + if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS && + _cups_strcasecmp(job->username, username)) + break; } if (i < job_ids->num_values) { - send_ipp_status(con, IPP_NOT_FOUND, _("job-id %d not found."), + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), job_ids->values[i].integer); return; } @@ -4048,13 +3266,17 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ for (i = 0; i < job_ids->num_values; i ++) { if ((job = cupsdFindJob(job_ids->values[i].integer)) == NULL || - strcasecmp(job->dest, printer->name)) + _cups_strcasecmp(job->dest, printer->name)) break; + + if (con->request->request.op.operation_id == IPP_CANCEL_MY_JOBS && + _cups_strcasecmp(job->username, username)) + break; } if (i < job_ids->num_values) { - send_ipp_status(con, IPP_NOT_FOUND, _("job-id %d not found."), + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), job_ids->values[i].integer); return; } @@ -4088,6 +3310,8 @@ cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ } con->response->request.status.status_code = IPP_OK; + + cupsdCheckJobs(); } @@ -4113,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... @@ -4129,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; } @@ -4146,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; } @@ -4158,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) @@ -4173,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; } @@ -4203,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; } @@ -4232,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; } @@ -4314,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? @@ -4327,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; } @@ -4391,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 /* @@ -4419,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... @@ -4427,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... */ @@ -4441,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); } } @@ -4455,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); } } @@ -4463,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 /* @@ -4497,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 @@ -4520,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, @@ -4535,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; } @@ -4547,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 @@ -4569,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\"...", @@ -4639,7 +3866,7 @@ close_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "close_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * See if we have a job URI or a printer URI... @@ -4664,7 +3891,7 @@ close_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; } @@ -4674,7 +3901,7 @@ close_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"), + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), attr->values[0].integer); return; } @@ -4722,8 +3949,8 @@ close_job(cupsd_client_t *con, /* I - Client connection */ * Fill in the response info... */ - snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName, - LocalPort, job->id); + httpAssembleURIf(HTTP_URI_CODING_ALL, job_uri, sizeof(job_uri), "ipp", NULL, + con->clientname, con->clientport, "/jobs/%d", job->id); ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-uri", NULL, job_uri); @@ -4732,8 +3959,6 @@ close_job(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", job->state_value); - add_job_state_reasons(con, job); - con->response->request.status.status_code = IPP_OK; /* @@ -4744,192 +3969,6 @@ close_job(cupsd_client_t *con, /* I - Client connection */ } -/* - * 'copy_attribute()' - Copy a single attribute. - */ - -static ipp_attribute_t * /* O - New attribute */ -copy_attribute( - ipp_t *to, /* O - Destination request/response */ - ipp_attribute_t *attr, /* I - Attribute to copy */ - int quickcopy) /* I - Do a quick copy? */ -{ - int i; /* Looping var */ - ipp_attribute_t *toattr; /* Destination attribute */ - - - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "copy_attribute(%p, %p[%s,%x,%x])", to, attr, - attr->name ? attr->name : "(null)", attr->group_tag, - attr->value_tag); - - switch (attr->value_tag & ~IPP_TAG_COPY) - { - case IPP_TAG_ZERO : - toattr = ippAddSeparator(to); - break; - - case IPP_TAG_INTEGER : - case IPP_TAG_ENUM : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].integer = attr->values[i].integer; - break; - - case IPP_TAG_BOOLEAN : - toattr = ippAddBooleans(to, attr->group_tag, attr->name, - attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].boolean = attr->values[i].boolean; - break; - - case IPP_TAG_STRING : - case IPP_TAG_TEXT : - case IPP_TAG_NAME : - case IPP_TAG_KEYWORD : - case IPP_TAG_URI : - case IPP_TAG_URISCHEME : - case IPP_TAG_CHARSET : - case IPP_TAG_LANGUAGE : - case IPP_TAG_MIMETYPE : - toattr = ippAddStrings(to, attr->group_tag, - (ipp_tag_t)(attr->value_tag | quickcopy), - attr->name, attr->num_values, NULL, NULL); - - if (quickcopy) - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = attr->values[i].string.text; - } - else if (attr->value_tag & IPP_TAG_COPY) - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = - _cupsStrAlloc(attr->values[i].string.text); - } - else - { - for (i = 0; i < attr->num_values; i ++) - toattr->values[i].string.text = - _cupsStrRetain(attr->values[i].string.text); - } - break; - - case IPP_TAG_DATE : - toattr = ippAddDate(to, attr->group_tag, attr->name, - attr->values[0].date); - break; - - case IPP_TAG_RESOLUTION : - toattr = ippAddResolutions(to, attr->group_tag, attr->name, - attr->num_values, IPP_RES_PER_INCH, - NULL, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].resolution.xres = attr->values[i].resolution.xres; - toattr->values[i].resolution.yres = attr->values[i].resolution.yres; - toattr->values[i].resolution.units = attr->values[i].resolution.units; - } - break; - - case IPP_TAG_RANGE : - toattr = ippAddRanges(to, attr->group_tag, attr->name, - attr->num_values, NULL, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].range.lower = attr->values[i].range.lower; - toattr->values[i].range.upper = attr->values[i].range.upper; - } - break; - - case IPP_TAG_TEXTLANG : - case IPP_TAG_NAMELANG : - toattr = ippAddStrings(to, attr->group_tag, - (ipp_tag_t)(attr->value_tag | quickcopy), - attr->name, attr->num_values, NULL, NULL); - - if (quickcopy) - { - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].string.charset = attr->values[i].string.charset; - toattr->values[i].string.text = attr->values[i].string.text; - } - } - else if (attr->value_tag & IPP_TAG_COPY) - { - for (i = 0; i < attr->num_values; i ++) - { - if (!i) - toattr->values[i].string.charset = - _cupsStrAlloc(attr->values[i].string.charset); - else - toattr->values[i].string.charset = - toattr->values[0].string.charset; - - toattr->values[i].string.text = - _cupsStrAlloc(attr->values[i].string.text); - } - } - else - { - for (i = 0; i < attr->num_values; i ++) - { - if (!i) - toattr->values[i].string.charset = - _cupsStrRetain(attr->values[i].string.charset); - else - toattr->values[i].string.charset = - toattr->values[0].string.charset; - - toattr->values[i].string.text = - _cupsStrRetain(attr->values[i].string.text); - } - } - break; - - case IPP_TAG_BEGIN_COLLECTION : - toattr = ippAddCollections(to, attr->group_tag, attr->name, - attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].collection = attr->values[i].collection; - attr->values[i].collection->use ++; - } - break; - - default : - toattr = ippAddIntegers(to, attr->group_tag, attr->value_tag, - attr->name, attr->num_values, NULL); - - for (i = 0; i < attr->num_values; i ++) - { - toattr->values[i].unknown.length = attr->values[i].unknown.length; - - if (toattr->values[i].unknown.length > 0) - { - if ((toattr->values[i].unknown.data = - malloc(toattr->values[i].unknown.length)) == NULL) - toattr->values[i].unknown.length = 0; - else - memcpy(toattr->values[i].unknown.data, - attr->values[i].unknown.data, - toattr->values[i].unknown.length); - } - } - break; /* anti-compiler-warning-code */ - } - - return (toattr); -} - - /* * 'copy_attrs()' - Copy attributes from one request to another. */ @@ -4939,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 */ @@ -4961,6 +4001,31 @@ 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)) { /* @@ -4975,7 +4040,7 @@ copy_attrs(ipp_t *to, /* I - Destination request */ !strcmp(fromattr->name, "media-col-database"))) continue; - copy_attribute(to, fromattr, quickcopy); + ippCopyAttribute(to, fromattr, quickcopy); } } } @@ -5005,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)"); /* @@ -5050,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, @@ -5105,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; @@ -5168,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 @@ -5192,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 : @@ -5202,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... @@ -5248,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); @@ -5259,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 */ @@ -5281,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); @@ -5292,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); @@ -5305,7 +4376,7 @@ copy_file(const char *from, /* I - Source file */ cupsFileClose(src); - return (cupsFileClose(dst)); + return (cupsdCloseCreatedConfFile(dst, to)); } @@ -5344,9 +4415,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ /* cupsProtocol attribute */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "copy_model(con=%p, from=\"%s\", to=\"%s\")", - con, from, to); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_model(con=%p, from=\"%s\", to=\"%s\")", con, from, to); /* * Run cups-driverd to get the PPD file... @@ -5360,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); @@ -5429,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; @@ -5456,12 +4523,23 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ return (-1); } + /* + * Open the source file for a copy... + */ + + if ((src = cupsFileOpen(tempfile, "rb")) == NULL) + { + unlink(tempfile); + return (-1); + } + /* * Read the source file and see what page sizes are supported... */ - if ((ppd = ppdOpenFile(tempfile)) == NULL) + if ((ppd = _ppdOpen(src, _PPD_LOCALIZATION_NONE)) == NULL) { + cupsFileClose(src); unlink(tempfile); return (-1); } @@ -5528,22 +4606,11 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ ppdClose(ppd); - /* - * Open the source file for a copy... - */ - - if ((src = cupsFileOpen(tempfile, "rb")) == NULL) - { - cupsFreeOptions(num_defaults, defaults); - unlink(tempfile); - return (-1); - } - /* * Open the destination file for a copy... */ - if ((dst = cupsFileOpen(to, "wb")) == NULL) + if ((dst = cupsdCreateConfFile(to, ConfigFilePerm)) == NULL) { cupsFreeOptions(num_defaults, defaults); cupsFileClose(src); @@ -5555,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)) @@ -5596,7 +4665,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ unlink(tempfile); - return (cupsFileClose(dst)); + return (cupsdCloseCreatedConfFile(dst, to)); } @@ -5607,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 */ @@ -5616,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); + } - copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0); + 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); + + 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); + } } @@ -5668,7 +4814,6 @@ copy_printer_attrs( /* Printer icons */ time_t curtime; /* Current time */ int i; /* Looping var */ - ipp_attribute_t *history; /* History collection */ /* @@ -5706,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); @@ -5726,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) @@ -5740,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, @@ -5756,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 @@ -5768,7 +4920,7 @@ copy_printer_attrs( if (!ra || cupsArrayFind(ra, "printer-icons")) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_icons, sizeof(printer_icons), - "http", NULL, con->servername, con->serverport, + "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); @@ -5776,18 +4928,18 @@ copy_printer_attrs( } if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs")) - ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", - printer->accepting); + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting); if (!ra || cupsArrayFind(ra, "printer-is-shared")) - ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", - printer->shared); + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", (char)printer->shared); - if ((!ra || cupsArrayFind(ra, "printer-more-info")) && - !(printer->type & CUPS_PRINTER_DISCOVERED)) + if (!ra || cupsArrayFind(ra, "printer-is-temporary")) + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-temporary", (char)printer->temporary); + + if (!ra || cupsArrayFind(ra, "printer-more-info")) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), - "http", NULL, con->servername, con->serverport, + "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, @@ -5802,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); @@ -5832,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... @@ -5850,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, @@ -5874,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); } @@ -5889,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]; @@ -5899,87 +5035,104 @@ 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... + */ - for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) - if (sub->mask & mask) - count ++; + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, + (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), + "notify-events", NULL, name); + } + else + { + /* + * Complex event list... + */ - 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) + count ++; - for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) - if (sub->mask & mask) - { - attr->values[count].string.text = - (char *)cupsdEventName((cupsd_eventmask_t)mask); + attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION, + (ipp_tag_t)(IPP_TAG_KEYWORD | IPP_TAG_COPY), + "notify-events", count, NULL, NULL); - count ++; - } + 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 ++; + } + } } + + 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); } @@ -5991,12 +5144,20 @@ static void create_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { + int i; /* Looping var */ cupsd_printer_t *printer; /* Printer */ cupsd_job_t *job; /* New job */ + static const char * const forbidden_attrs[] = + { /* List of forbidden attributes */ + "compression", + "document-format", + "document-name", + "document-natural-language" + }; cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con, - con->http.fd, uri->values[0].string.text); + con->number, uri->values[0].string.text); /* * Is the destination valid? @@ -6009,10 +5170,33 @@ create_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; } + /* + * 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... */ @@ -6032,197 +5216,298 @@ create_job(cupsd_client_t *con, /* I - Client connection */ /* - * 'create_requested_array()' - Create an array for the requested-attributes. + * 'create_local_bg_thread()' - Background thread for creating a local print queue. */ -static cups_array_t * /* O - Array of attributes or NULL */ -create_requested_array(ipp_t *request) /* I - IPP request */ +static void * /* O - Exit status */ +create_local_bg_thread( + cupsd_printer_t *printer) /* I - Printer */ { - int i; /* Looping var */ - ipp_attribute_t *requested; /* requested-attributes attribute */ - cups_array_t *ra; /* Requested attributes array */ - char *value; /* Current value */ + cups_file_t *from, /* Source file */ + *to; /* Destination file */ + char fromppd[1024], /* Source PPD */ + toppd[1024], /* Destination PPD */ + scheme[32], /* URI scheme */ + userpass[256], /* User:pass */ + host[256], /* Hostname */ + resource[1024], /* Resource path */ + line[1024]; /* Line from PPD */ + int port; /* Port number */ + http_encryption_t encryption; /* Type of encryption to use */ + http_t *http; /* Connection to printer */ + ipp_t *request, /* Request to printer */ + *response; /* Response from printer */ + ipp_attribute_t *attr; /* Attribute in response */ /* - * Get the requested-attributes attribute, and return NULL if we don't - * have one... + * Try connecting to the printer... */ - if ((requested = ippFindAttribute(request, "requested-attributes", - IPP_TAG_KEYWORD)) == NULL) + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Generating PPD file from \"%s\"...", printer->name, printer->device_uri); + + if (httpSeparateURI(HTTP_URI_CODING_ALL, printer->device_uri, scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)) < HTTP_URI_STATUS_OK) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Bad device URI \"%s\".", printer->name, printer->device_uri); + return (NULL); + } + + if (!strcmp(scheme, "ipps") || port == 443) + encryption = HTTP_ENCRYPTION_ALWAYS; + else + encryption = HTTP_ENCRYPTION_IF_REQUESTED; + + if ((http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 30000, NULL)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: Unable to connect to %s:%d: %s", printer->name, host, port, cupsLastErrorString()); return (NULL); + } /* - * If the attribute contains a single "all" keyword, return NULL... + * Query the printer for its capabilities... */ - if (requested->num_values == 1 && - !strcmp(requested->values[0].string.text, "all")) - return (NULL); + cupsdLogMessage(CUPSD_LOG_DEBUG, "%s: Connected to %s:%d, sending Get-Printer-Attributes request...", printer->name, host, port); + + request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); + 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); /* - * Create an array using "strcmp" as the comparison function... - */ - - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - - for (i = 0; i < requested->num_values; i ++) - { - value = requested->values[i].string.text; - - if (!strcmp(value, "job-template")) - { - cupsArrayAdd(ra, "copies"); - cupsArrayAdd(ra, "copies-default"); - cupsArrayAdd(ra, "copies-supported"); - cupsArrayAdd(ra, "finishings"); - cupsArrayAdd(ra, "finishings-default"); - cupsArrayAdd(ra, "finishings-supported"); - cupsArrayAdd(ra, "job-hold-until"); - cupsArrayAdd(ra, "job-hold-until-default"); - cupsArrayAdd(ra, "job-hold-until-supported"); - cupsArrayAdd(ra, "job-priority"); - cupsArrayAdd(ra, "job-priority-default"); - cupsArrayAdd(ra, "job-priority-supported"); - cupsArrayAdd(ra, "job-sheets"); - cupsArrayAdd(ra, "job-sheets-default"); - cupsArrayAdd(ra, "job-sheets-supported"); - cupsArrayAdd(ra, "media"); - cupsArrayAdd(ra, "media-default"); - cupsArrayAdd(ra, "media-supported"); - cupsArrayAdd(ra, "multiple-document-handling"); - cupsArrayAdd(ra, "multiple-document-handling-default"); - cupsArrayAdd(ra, "multiple-document-handling-supported"); - cupsArrayAdd(ra, "number-up"); - cupsArrayAdd(ra, "number-up-default"); - cupsArrayAdd(ra, "number-up-supported"); - cupsArrayAdd(ra, "orientation-requested"); - cupsArrayAdd(ra, "orientation-requested-default"); - cupsArrayAdd(ra, "orientation-requested-supported"); - cupsArrayAdd(ra, "page-ranges"); - cupsArrayAdd(ra, "page-ranges-supported"); - cupsArrayAdd(ra, "printer-resolution"); - cupsArrayAdd(ra, "printer-resolution-default"); - cupsArrayAdd(ra, "printer-resolution-supported"); - cupsArrayAdd(ra, "print-quality"); - cupsArrayAdd(ra, "print-quality-default"); - cupsArrayAdd(ra, "print-quality-supported"); - cupsArrayAdd(ra, "sides"); - cupsArrayAdd(ra, "sides-default"); - cupsArrayAdd(ra, "sides-supported"); - } - else if (!strcmp(value, "job-description")) - { - cupsArrayAdd(ra, "date-time-at-completed"); - cupsArrayAdd(ra, "date-time-at-creation"); - cupsArrayAdd(ra, "date-time-at-processing"); - cupsArrayAdd(ra, "job-detailed-status-message"); - cupsArrayAdd(ra, "job-document-access-errors"); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-impressions"); - cupsArrayAdd(ra, "job-impressions-completed"); - cupsArrayAdd(ra, "job-k-octets"); - cupsArrayAdd(ra, "job-k-octets-processed"); - cupsArrayAdd(ra, "job-media-progress"); - cupsArrayAdd(ra, "job-media-sheets"); - cupsArrayAdd(ra, "job-media-sheets-completed"); - cupsArrayAdd(ra, "job-message-from-operator"); - cupsArrayAdd(ra, "job-more-info"); - cupsArrayAdd(ra, "job-name"); - cupsArrayAdd(ra, "job-originating-user-name"); - cupsArrayAdd(ra, "job-printer-up-time"); - cupsArrayAdd(ra, "job-printer-uri"); - cupsArrayAdd(ra, "job-state"); - cupsArrayAdd(ra, "job-state-message"); - cupsArrayAdd(ra, "job-state-reasons"); - cupsArrayAdd(ra, "job-uri"); - cupsArrayAdd(ra, "number-of-documents"); - cupsArrayAdd(ra, "number-of-intervening-jobs"); - cupsArrayAdd(ra, "output-device-assigned"); - cupsArrayAdd(ra, "time-at-completed"); - cupsArrayAdd(ra, "time-at-creation"); - cupsArrayAdd(ra, "time-at-processing"); - } - else if (!strcmp(value, "printer-description")) - { - cupsArrayAdd(ra, "charset-configured"); - cupsArrayAdd(ra, "charset-supported"); - cupsArrayAdd(ra, "color-supported"); - cupsArrayAdd(ra, "compression-supported"); - cupsArrayAdd(ra, "document-format-default"); - cupsArrayAdd(ra, "document-format-supported"); - cupsArrayAdd(ra, "generated-natural-language-supported"); - cupsArrayAdd(ra, "ipp-versions-supported"); - cupsArrayAdd(ra, "job-impressions-supported"); - cupsArrayAdd(ra, "job-k-octets-supported"); - cupsArrayAdd(ra, "job-media-sheets-supported"); - cupsArrayAdd(ra, "job-settable-attributes-supported"); - cupsArrayAdd(ra, "multiple-document-jobs-supported"); - cupsArrayAdd(ra, "multiple-operation-time-out"); - cupsArrayAdd(ra, "natural-language-configured"); - cupsArrayAdd(ra, "notify-attributes-supported"); - cupsArrayAdd(ra, "notify-lease-duration-default"); - cupsArrayAdd(ra, "notify-lease-duration-supported"); - cupsArrayAdd(ra, "notify-max-events-supported"); - cupsArrayAdd(ra, "notify-events-default"); - cupsArrayAdd(ra, "notify-events-supported"); - cupsArrayAdd(ra, "notify-pull-method-supported"); - cupsArrayAdd(ra, "notify-schemes-supported"); - cupsArrayAdd(ra, "operations-supported"); - cupsArrayAdd(ra, "pages-per-minute"); - cupsArrayAdd(ra, "pages-per-minute-color"); - cupsArrayAdd(ra, "pdl-override-supported"); - cupsArrayAdd(ra, "printer-alert"); - cupsArrayAdd(ra, "printer-alert-description"); - cupsArrayAdd(ra, "printer-commands"); - cupsArrayAdd(ra, "printer-current-time"); - cupsArrayAdd(ra, "printer-driver-installer"); - cupsArrayAdd(ra, "printer-dns-sd-name"); - cupsArrayAdd(ra, "printer-info"); - cupsArrayAdd(ra, "printer-is-accepting-jobs"); - cupsArrayAdd(ra, "printer-location"); - cupsArrayAdd(ra, "printer-make-and-model"); - cupsArrayAdd(ra, "printer-message-from-operator"); - cupsArrayAdd(ra, "printer-more-info"); - cupsArrayAdd(ra, "printer-more-info-manufacturer"); - cupsArrayAdd(ra, "printer-name"); - cupsArrayAdd(ra, "printer-state"); - cupsArrayAdd(ra, "printer-state-message"); - cupsArrayAdd(ra, "printer-state-reasons"); - cupsArrayAdd(ra, "printer-settable-attributes-supported"); - cupsArrayAdd(ra, "printer-type"); - cupsArrayAdd(ra, "printer-up-time"); - cupsArrayAdd(ra, "printer-uri-supported"); - cupsArrayAdd(ra, "queued-job-count"); - cupsArrayAdd(ra, "reference-uri-schemes-supported"); - cupsArrayAdd(ra, "uri-authentication-supported"); - cupsArrayAdd(ra, "uri-security-supported"); - } - else if (!strcmp(value, "printer-defaults")) - { - char *name; /* Option name */ - - - for (name = (char *)cupsArrayFirst(CommonDefaults); - name; - name = (char *)cupsArrayNext(CommonDefaults)) - cupsArrayAdd(ra, name); + * Write the PPD for the queue... + */ + + if (_ppdCreateFromIPP(fromppd, sizeof(fromppd), response)) + { + 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); } - else if (!strcmp(value, "subscription-template")) + + while (cupsFileGets(from, line, sizeof(line))) + cupsFilePrintf(to, "%s\n", line); + + cupsFileClose(from); + if (!cupsdCloseCreatedConfFile(to, toppd)) { - cupsArrayAdd(ra, "notify-attributes"); - cupsArrayAdd(ra, "notify-charset"); - cupsArrayAdd(ra, "notify-events"); - cupsArrayAdd(ra, "notify-lease-duration"); - cupsArrayAdd(ra, "notify-natural-language"); - cupsArrayAdd(ra, "notify-pull-method"); - cupsArrayAdd(ra, "notify-recipient-uri"); - cupsArrayAdd(ra, "notify-time-interval"); - cupsArrayAdd(ra, "notify-user-data"); + printer->config_time = time(NULL); + printer->state = IPP_PSTATE_IDLE; + printer->accepting = 1; + + cupsdSetPrinterAttrs(printer); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, "Printer \"%s\" is now available.", printer->name); + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" is now available.", printer->name); } + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: PPD creation failed.", printer->name); + + return (NULL); +} + + +/* + * 'create_local_printer()' - Create a local (temporary) print queue. + */ + +static void +create_local_printer( + cupsd_client_t *con) /* I - Client connection */ +{ + ipp_attribute_t *device_uri, /* device-uri attribute */ + *printer_geo_location, /* printer-geo-location attribute */ + *printer_info, /* printer-info attribute */ + *printer_location, /* printer-location attribute */ + *printer_name; /* printer-name attribute */ + cupsd_printer_t *printer; /* New printer */ + http_status_t status; /* Policy status */ + char name[128], /* Sanitized printer name */ + *nameptr, /* Pointer into name */ + uri[1024]; /* printer-uri-supported value */ + const char *ptr; /* Pointer into attribute value */ + + + /* + * Require local access to create a local printer... + */ + + if (!httpAddrLocalhost(httpGetAddress(con->http))) + { + send_ipp_status(con, IPP_STATUS_ERROR_FORBIDDEN, _("Only local users can create a local printer.")); + return; + } + + /* + * Check any other policy limits... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status, NULL); + return; + } + + /* + * Grab needed attributes... + */ + + if ((printer_name = ippFindAttribute(con->request, "printer-name", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(printer_name) != IPP_TAG_PRINTER || ippGetValueTag(printer_name) != IPP_TAG_NAME) + { + if (!printer_name) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "printer-name"); + else if (ippGetGroupTag(printer_name) != IPP_TAG_PRINTER) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "printer-name"); + else + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "printer-name"); + + return; + } + + for (nameptr = name, ptr = ippGetString(printer_name, 0, NULL); *ptr && nameptr < (name + sizeof(name) - 1); ptr ++) + { + /* + * Sanitize the printer name... + */ + + if (_cups_isalnum(*ptr)) + *nameptr++ = *ptr; + else if (nameptr == name || nameptr[-1] != '_') + *nameptr++ = '_'; + } + + *nameptr = '\0'; + + if ((device_uri = ippFindAttribute(con->request, "device-uri", IPP_TAG_ZERO)) == NULL || ippGetGroupTag(device_uri) != IPP_TAG_PRINTER || ippGetValueTag(device_uri) != IPP_TAG_URI) + { + if (!device_uri) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Missing required attribute \"%s\"."), "device-uri"); + else if (ippGetGroupTag(device_uri) != IPP_TAG_PRINTER) + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is in the wrong group."), "device-uri"); else - cupsArrayAdd(ra, value); + send_ipp_status(con, IPP_STATUS_ERROR_BAD_REQUEST, _("Attribute \"%s\" is the wrong value type."), "device-uri"); + + return; + } + + printer_geo_location = ippFindAttribute(con->request, "printer-geo-location", IPP_TAG_URI); + printer_info = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT); + printer_location = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT); + + /* + * See if the printer already exists... + */ + + if ((printer = cupsdFindDest(name)) != NULL) + { + send_ipp_status(con, IPP_STATUS_ERROR_NOT_POSSIBLE, _("Printer \"%s\" already exists."), name); + goto add_printer_attributes; + } + + /* + * Create the printer... + */ + + if ((printer = cupsdAddPrinter(name)) == NULL) + { + send_ipp_status(con, IPP_STATUS_ERROR_INTERNAL, _("Unable to create printer.")); + return; + } + + cupsdSetDeviceURI(printer, ippGetString(device_uri, 0, NULL)); + + if (printer_geo_location) + cupsdSetString(&printer->geo_location, ippGetString(printer_geo_location, 0, NULL)); + if (printer_info) + cupsdSetString(&printer->info, ippGetString(printer_info, 0, NULL)); + if (printer_location) + cupsdSetString(&printer->location, ippGetString(printer_location, 0, NULL)); + + cupsdSetPrinterAttrs(printer); + + /* + * Run a background thread to create the PPD... + */ + + _cupsThreadCreate((_cups_thread_func_t)create_local_bg_thread, printer); + + /* + * Return printer attributes... + */ + + send_ipp_status(con, IPP_STATUS_OK, _("Local printer created.")); + + add_printer_attributes: + + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", (char)printer->accepting); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", printer->state); + add_printer_state_reasons(con, printer); + + httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), httpIsEncrypted(con->http) ? "ipps" : "ipp", NULL, con->clientname, con->clientport, "/printers/%s", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uri-supported", NULL, uri); +} + + +/* + * 'create_requested_array()' - Create an array for the requested-attributes. + */ + +static cups_array_t * /* O - Array of attributes or NULL */ +create_requested_array(ipp_t *request) /* I - IPP request */ +{ + cups_array_t *ra; /* Requested attributes array */ + + + /* + * Create the array for standard attributes... + */ + + ra = ippCreateRequestedArray(request); + + /* + * Add CUPS defaults as needed... + */ + + if (cupsArrayFind(ra, "printer-defaults")) + { + /* + * Include user-set defaults... + */ + + char *name; /* Option name */ + + cupsArrayRemove(ra, "printer-defaults"); + + for (name = (char *)cupsArrayFirst(CommonDefaults); + name; + name = (char *)cupsArrayNext(CommonDefaults)) + if (!cupsArrayFind(ra, name)) + cupsArrayAdd(ra, name); } return (ra); @@ -6230,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 */ { @@ -6282,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, @@ -6312,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; } @@ -6353,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; } @@ -6411,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; @@ -6423,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; @@ -6432,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); @@ -6447,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; @@ -6459,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; } @@ -6468,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; } @@ -6479,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; } @@ -6527,7 +5810,7 @@ create_subscription( else { send_ipp_status(con, IPP_BAD_REQUEST, - _("notify-events not specified")); + _("notify-events not specified.")); return; } } @@ -6535,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; @@ -6545,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; } } @@ -6560,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; @@ -6580,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); @@ -6609,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? @@ -6625,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; } @@ -6660,30 +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, - printer->name); - unlink(filename); - snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, printer->name); unlink(filename); - - snprintf(filename, sizeof(filename), "%s/%s.ipp4", CacheDir, printer->name); + snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd.O", ServerRoot, + printer->name); unlink(filename); snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, printer->name); unlink(filename); - snprintf(filename, sizeof(filename), "%s/%s.pwg3", CacheDir, printer->name); + 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) { @@ -6691,20 +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)); - if (cupsdDeletePrinter(printer, 0)) + if (cupsdDeletePrinter(printer, 0) && !temporary) cupsdMarkDirty(CUPSD_DIRTY_CLASSES); - cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + if (!temporary) + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); } - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + if (!temporary) + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); /* * Return with no errors... @@ -6725,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... @@ -6748,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.")); } @@ -6775,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... @@ -6869,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... @@ -6885,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; } @@ -6907,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; } @@ -6926,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; } @@ -6934,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; @@ -6948,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; } @@ -6968,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; } @@ -7003,16 +6289,18 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ int jobid; /* Job ID */ cupsd_job_t *job; /* Current job */ cupsd_printer_t *printer; /* Current printer */ - char scheme[HTTP_MAX_URI], /* Method portion of URI */ + 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... @@ -7028,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; } @@ -7050,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; } @@ -7069,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; } @@ -7081,20 +6368,18 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ printer = cupsdFindDest(job->dest); 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, job->username)) != HTTP_OK) { send_http_error(con, status, NULL); return; } + exclude = cupsdGetPrivateAttrs(policy, con, printer, job->username); + /* * Copy attributes... */ @@ -7102,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; @@ -7129,17 +6414,24 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ int port; /* Port portion of URI */ int job_comparison; /* Job comparison */ ipp_jstate_t job_state; /* job-state value */ - int first_job_id; /* First job ID */ - int limit; /* Maximum number of jobs to return */ + int 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); /* @@ -7148,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; } @@ -7185,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 @@ -7199,15 +6491,11 @@ 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; @@ -7231,19 +6519,21 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ { job_comparison = -1; job_state = IPP_JOB_STOPPED; - list = Jobs; + list = ActiveJobs; } else if (!strcmp(attr->values[0].string.text, "completed")) { job_comparison = 1; job_state = IPP_JOB_CANCELED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "aborted")) { job_comparison = 0; job_state = IPP_JOB_ABORTED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "all")) { @@ -7255,7 +6545,8 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ { job_comparison = 0; job_state = IPP_JOB_CANCELED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "pending")) { @@ -7295,8 +6586,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ * See if they want to limit the number of jobs reported... */ - if ((attr = ippFindAttribute(con->request, "limit", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL) { if (job_ids) { @@ -7308,11 +6598,20 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ limit = attr->values[0].integer; } - else - limit = 0; - if ((attr = ippFindAttribute(con->request, "first-job-id", - IPP_TAG_INTEGER)) != NULL) + 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) { @@ -7324,15 +6623,12 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ first_job_id = attr->values[0].integer; } - else - first_job_id = 1; /* * See if we only want to see jobs for a specific user... */ - if ((attr = ippFindAttribute(con->request, "my-jobs", - IPP_TAG_BOOLEAN)) != NULL && job_ids) + if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && job_ids) { send_ipp_status(con, IPP_CONFLICT, _("The %s attribute cannot be provided with job-ids."), @@ -7344,17 +6640,42 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ else username[0] = '\0'; - if ((ra = create_requested_array(con->request)) == NULL && - !ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD)) + ra = create_requested_array(con->request); + for (job_attr = (char *)cupsArrayFirst(ra); job_attr; job_attr = (char *)cupsArrayNext(ra)) + if (strcmp(job_attr, "job-id") && + strcmp(job_attr, "job-k-octets") && + strcmp(job_attr, "job-media-progress") && + strcmp(job_attr, "job-more-info") && + strcmp(job_attr, "job-name") && + strcmp(job_attr, "job-originating-user-name") && + strcmp(job_attr, "job-preserved") && + strcmp(job_attr, "job-printer-up-time") && + strcmp(job_attr, "job-printer-uri") && + strcmp(job_attr, "job-state") && + strcmp(job_attr, "job-state-reasons") && + strcmp(job_attr, "job-uri") && + strcmp(job_attr, "time-at-completed") && + strcmp(job_attr, "time-at-creation") && + strcmp(job_attr, "number-of-documents")) + { + need_load_job = 1; + break; + } + + if (need_load_job && (limit == 0 || limit > 500) && (list == Jobs || delete_list)) { /* - * IPP conformance - Get-Jobs has a default requested-attributes value of - * "job-id" and "job-uri". + * Limit expensive Get-Jobs for job history to 500 jobs... */ - ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); - cupsArrayAdd(ra, "job-id"); - cupsArrayAdd(ra, "job-uri"); + ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "limit", 500); + + if (limit) + ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "limit", limit); + + limit = 500; + + cupsdLogClient(con, CUPSD_LOG_INFO, "Limiting Get-Jobs response to %d jobs.", limit); } /* @@ -7373,7 +6694,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ if (i < job_ids->num_values) { - send_ipp_status(con, IPP_NOT_FOUND, _("job-id %d not found."), + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist."), job_ids->values[i].integer); return; } @@ -7382,19 +6703,26 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ { job = cupsdFindJob(job_ids->values[i].integer); - cupsdLoadJob(job); - - if (!job->attrs) + if (need_load_job && !job->attrs) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", - job->id); - continue; + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } } if (i > 0) ippAddSeparator(con->response); - copy_job_attrs(con, job, ra); + exclude = cupsdGetPrivateAttrs(job->printer ? + job->printer->op_policy_ptr : + policy, con, job->printer, + job->username); + + copy_job_attrs(con, job, ra, exclude); } } else @@ -7433,16 +6761,22 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ if (job->id < first_job_id) continue; - cupsdLoadJob(job); + current_index ++; + if (current_index < first_index) + continue; - if (!job->attrs) + if (need_load_job && !job->attrs) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", - job->id); - continue; + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } } - if (username[0] && strcasecmp(username, job->username)) + if (username[0] && _cups_strcasecmp(username, job->username)) continue; if (count > 0) @@ -7450,7 +6784,12 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ count ++; - copy_job_attrs(con, job, ra); + 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); @@ -7458,6 +6797,9 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ cupsArrayDelete(ra); + if (delete_list) + cupsArrayDelete(list); + con->response->request.status.status_code = IPP_OK; } @@ -7479,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... @@ -7493,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; } @@ -7509,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; } @@ -7576,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; /* @@ -7588,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); } } } @@ -7613,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... @@ -7636,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)) { @@ -7661,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... */ @@ -7686,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; @@ -7713,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; } } @@ -7726,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; } @@ -7736,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)); } @@ -7787,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... @@ -7932,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? @@ -7945,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; } @@ -7988,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? @@ -8001,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; } @@ -8019,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; } @@ -8041,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 */ @@ -8051,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... @@ -8095,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)); @@ -8145,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; /* @@ -8198,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? @@ -8215,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; } @@ -8224,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. @@ -8239,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); @@ -8273,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? @@ -8302,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; } } @@ -8314,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", @@ -8324,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; } @@ -8336,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. @@ -8372,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) @@ -8430,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); /* @@ -8447,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; } @@ -8470,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; } @@ -8488,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; } @@ -8503,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... */ @@ -8543,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? @@ -8556,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; } @@ -8577,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, @@ -8620,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); /* @@ -8635,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; } @@ -8646,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; } @@ -8679,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; } @@ -8698,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 @@ -8724,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; } @@ -8742,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 @@ -8785,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; } @@ -8822,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; @@ -8935,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 */ @@ -8950,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); /* @@ -8970,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); @@ -8989,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; } @@ -9004,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; } @@ -9012,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) { @@ -9019,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, - _("Bad document-format \"%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, @@ -9036,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, - _("Bad document-format \"%s\""), + _("Bad document-format \"%s\"."), default_format); return; } @@ -9050,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")) @@ -9060,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); @@ -9075,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); @@ -9092,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); @@ -9104,7 +8487,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ else if (!filetype) { send_ipp_status(con, IPP_DOCUMENT_FORMAT, - _("Unsupported document-format \"%s\""), + _("Unsupported document-format \"%s\"."), format ? format->values[0].string.text : "application/octet-stream"); cupsdLogMessage(CUPSD_LOG_INFO, @@ -9121,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); /* @@ -9144,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; /* @@ -9155,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); /* @@ -9316,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 */ @@ -9350,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); } /* @@ -9384,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? @@ -9397,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; } @@ -9419,13 +8814,12 @@ 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."); @@ -9467,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? @@ -9480,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; } @@ -9501,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, @@ -9512,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... */ @@ -9539,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... @@ -9555,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; } @@ -9577,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; } @@ -9596,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; } @@ -9610,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; } @@ -9635,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"); } /* @@ -9677,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? @@ -9689,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; } @@ -9701,7 +9094,7 @@ renew_subscription( */ send_ipp_status(con, IPP_NOT_POSSIBLE, - _("Job subscriptions cannot be renewed")); + _("Job subscriptions cannot be renewed.")); return; } @@ -9765,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... @@ -9781,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; } @@ -9803,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; } @@ -9822,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; } @@ -9836,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; } @@ -9854,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; } @@ -9921,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 */ @@ -9970,54 +9362,97 @@ 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_env + 1, "AUTH_PASSWORD=%s", con->password); + } - cupsdSetStringf(&job->auth_password, "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... @@ -10031,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 */ /* @@ -10120,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... @@ -10136,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; } @@ -10158,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; } @@ -10177,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; } @@ -10210,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); @@ -10227,6 +9616,14 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Do we have a file to print? */ + if ((attr = ippFindAttribute(con->request, "last-document", + IPP_TAG_BOOLEAN)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Missing last-document attribute in request.")); + return; + } + if (!con->filename) { /* @@ -10234,13 +9631,10 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * used to close an "open" job by RFC 2911, section 3.3.2. */ - if (job->num_files > 0 && - (attr = ippFindAttribute(con->request, "last-document", - IPP_TAG_BOOLEAN)) != NULL && - attr->values[0].boolean) + if (job->num_files > 0 && attr->values[0].boolean) goto last_document; - send_ipp_status(con, IPP_BAD_REQUEST, _("No file!?")); + send_ipp_status(con, IPP_BAD_REQUEST, _("No file in print request.")); return; } @@ -10248,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) { @@ -10255,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, @@ -10271,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; } } @@ -10285,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")) @@ -10308,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); @@ -10326,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); @@ -10338,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?"); @@ -10355,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); @@ -10367,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 @@ -10379,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); @@ -10413,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) { @@ -10424,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; @@ -10443,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); } @@ -10455,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); @@ -10465,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; @@ -10496,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) { @@ -10548,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; } @@ -10621,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? @@ -10634,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; } @@ -10663,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\".", @@ -10703,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... @@ -10725,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; } @@ -10747,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; } @@ -10766,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; } @@ -10781,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; } @@ -10812,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") || @@ -10830,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)) { /* @@ -10842,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; } @@ -10856,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) { @@ -10886,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 { @@ -10907,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; @@ -10963,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. @@ -11010,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; } @@ -11021,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; } @@ -11077,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? @@ -11090,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; } @@ -11115,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) { @@ -11128,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); @@ -11155,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 */ @@ -11197,7 +10627,7 @@ set_printer_defaults( } else if (!strcmp(attr->name, "requesting-user-name-allowed")) { - cupsdFreePrinterUsers(printer); + cupsdFreeStrings(&(printer->users)); printer->deny_users = 0; @@ -11206,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; @@ -11220,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")) @@ -11286,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")))) @@ -11330,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, @@ -11376,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)); @@ -11400,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? @@ -11419,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; } @@ -11450,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... */ @@ -11473,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? @@ -11486,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; } @@ -11506,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, @@ -11537,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 */ @@ -11563,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; @@ -11583,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 */ @@ -11633,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")) @@ -11662,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); } @@ -11699,9 +11147,12 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Printer URI */ { http_status_t status; /* Policy status */ - ipp_attribute_t *attr, /* Current attribute */ - *auth_info; /* auth-info attribute */ - ipp_attribute_t *format; /* Document-format attribute */ + ipp_attribute_t *attr; /* Current attribute */ +#ifdef HAVE_SSL + ipp_attribute_t *auth_info; /* auth-info attribute */ +#endif /* HAVE_SSL */ + ipp_attribute_t *format, /* Document-format attribute */ + *name; /* Job-name attribute */ cups_ptype_t dtype; /* Destination type (printer/class) */ char super[MIME_MAX_SUPER], /* Supertype of file */ @@ -11711,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 @@ -11728,7 +11179,7 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ ) { send_ipp_status(con, IPP_ATTRIBUTES, - _("Unsupported compression \"%s\""), + _("Unsupported 'compression' value \"%s\"."), attr->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, "compression", NULL, attr->values[0].string.text); @@ -11743,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; } @@ -11757,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 document-format \"%s\""), + _("Unsupported 'document-format' value \"%s\"."), format->values[0].string.text); ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, "document-format", NULL, format->values[0].string.text); @@ -11765,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? */ @@ -11776,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; } @@ -11784,7 +11316,9 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ * Check policy... */ +#ifdef HAVE_SSL auth_info = ippFindAttribute(con->request, "auth-info", IPP_TAG_TEXT); +#endif /* HAVE_SSL */ if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) { @@ -11799,8 +11333,8 @@ validate_job(cupsd_client_t *con, /* I - Client connection */ return; } #ifdef HAVE_SSL - else if (auth_info && !con->http.tls && - !httpAddrLocalhost(con->http.hostaddr)) + else if (auth_info && !con->http->tls && + !httpAddrLocalhost(con->http->hostaddr)) { /* * Require encryption of auth-info over non-local connections... @@ -11854,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... @@ -11887,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 $". - */