X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=scheduler%2Fipp.c;h=637d760b4fdf7120c6b68a88a485cbad2cfe0d7c;hp=cd8b6c26ea557c73aaf5a7a433d3811ab6736665;hb=f11a948a02771f78f50b530880a0269d4b4f58eb;hpb=5d6412a9f1d6faef517cc8038f9d3784afef9945 diff --git a/scheduler/ipp.c b/scheduler/ipp.c index cd8b6c26e..637d760b4 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -1,9 +1,9 @@ /* - * "$Id: ipp.c 7682 2008-06-21 00:06:02Z mike $" + * "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $" * * IPP routines for the Common UNIX Printing System (CUPS) scheduler. * - * Copyright 2007-2008 by Apple Inc. + * Copyright 2007-2009 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * This file contains Kerberos support code, copyright 2006 by @@ -25,7 +25,7 @@ * 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 subcriptions for a job. + * 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 @@ -77,7 +77,7 @@ * 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_ps_job_ticket() - Reads a job ticket embedded in a PS file. + * read_job_ticket() - Read a job ticket embedded in a print file. * reject_jobs() - Reject print jobs to a printer. * release_job() - Release a held print job. * renew_subscription() - Renew an existing subscription... @@ -89,6 +89,7 @@ * 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. @@ -193,16 +194,20 @@ static void get_ppd(cupsd_client_t *con, ipp_attribute_t *uri); static void get_ppds(cupsd_client_t *con); static void get_printers(cupsd_client_t *con, int type); static void get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri); +static void get_printer_supported(cupsd_client_t *con, ipp_attribute_t *uri); static void get_subscription_attrs(cupsd_client_t *con, int sub_id); static void get_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri); static const char *get_username(cupsd_client_t *con); static void hold_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void hold_new_jobs(cupsd_client_t *con, ipp_attribute_t *uri); static void move_job(cupsd_client_t *con, ipp_attribute_t *uri); static int ppd_parse_line(const char *line, char *option, int olen, char *choice, int clen); static void print_job(cupsd_client_t *con, ipp_attribute_t *uri); -static void read_ps_job_ticket(cupsd_client_t *con); +static void read_job_ticket(cupsd_client_t *con); static void reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri); +static void release_held_new_jobs(cupsd_client_t *con, + ipp_attribute_t *uri); static void release_job(cupsd_client_t *con, ipp_attribute_t *uri); static void renew_subscription(cupsd_client_t *con, int sub_id); static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri); @@ -222,6 +227,7 @@ __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); 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); @@ -249,7 +255,7 @@ cupsdProcessIPPRequest( ipp_attribute_t *attr; /* Current attribute */ ipp_attribute_t *charset; /* Character set attribute */ ipp_attribute_t *language; /* Language attribute */ - ipp_attribute_t *uri; /* Printer URI attribute */ + ipp_attribute_t *uri = NULL; /* Printer or job URI attribute */ ipp_attribute_t *username; /* requesting-user-name attr */ int sub_id; /* Subscription ID */ @@ -275,10 +281,11 @@ cupsdProcessIPPRequest( * Then validate the request header and required attributes... */ - if (con->request->request.any.version[0] != 1) + if (con->request->request.any.version[0] != 1 && + con->request->request.any.version[0] != 2) { /* - * Return an error, since we only support IPP 1.x. + * Return an error, since we only support IPP 1.x and 2.x. */ cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, @@ -292,6 +299,20 @@ cupsdProcessIPPRequest( con->request->request.any.version[0], con->request->request.any.version[1]); } + else if (con->request->request.any.request_id < 1) + { + /* + * Return an error, since request IDs must be between 1 and 2^31-1 + */ + + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s Bad request ID %d", + IPP_BAD_REQUEST, con->http.hostname, + con->request->request.any.request_id); + + 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, @@ -339,7 +360,8 @@ cupsdProcessIPPRequest( */ attr = con->request->attrs; - if (attr && !strcmp(attr->name, "attributes-charset") && + if (attr && attr->name && + !strcmp(attr->name, "attributes-charset") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_CHARSET) charset = attr; else @@ -348,7 +370,8 @@ cupsdProcessIPPRequest( if (attr) attr = attr->next; - if (attr && !strcmp(attr->name, "attributes-natural-language") && + if (attr && attr->name && + !strcmp(attr->name, "attributes-natural-language") && (attr->value_tag & IPP_TAG_MASK) == IPP_TAG_LANGUAGE) language = attr; else @@ -536,6 +559,10 @@ cupsdProcessIPPRequest( get_printer_attrs(con, uri); break; + case IPP_GET_PRINTER_SUPPORTED_VALUES : + get_printer_supported(con, uri); + break; + case IPP_HOLD_JOB : hold_job(con, uri); break; @@ -564,6 +591,18 @@ cupsdProcessIPPRequest( set_job_attrs(con, uri); break; + case IPP_SET_PRINTER_ATTRIBUTES : + set_printer_attrs(con, uri); + break; + + case IPP_HOLD_NEW_JOBS : + hold_new_jobs(con, uri); + break; + + case IPP_RELEASE_HELD_NEW_JOBS : + release_held_new_jobs(con, uri); + break; + case CUPS_GET_DEFAULT : get_default(con); break; @@ -678,10 +717,20 @@ cupsdProcessIPPRequest( * Sending data from the scheduler... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdProcessIPPRequest: %d status_code=%x (%s)", - con->http.fd, con->response->request.status.status_code, - ippErrorString(con->response->request.status.status_code)); + cupsdLogMessage(con->response->request.status.status_code + >= IPP_BAD_REQUEST && + con->response->request.status.status_code + != IPP_NOT_FOUND ? CUPSD_LOG_ERROR : CUPSD_LOG_DEBUG, + "Returning IPP %s for %s (%s) from %s", + ippErrorString(con->response->request.status.status_code), + ippOpString(con->request->request.op.operation_id), + uri ? uri->values[0].string.text : "no URI", + con->http.hostname); + + if (LogLevel == CUPSD_LOG_DEBUG2) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdProcessIPPRequest: ippLength(response)=%ld", + (long)ippLength(con->response)); if (cupsdSendHeader(con, HTTP_OK, "application/ipp", CUPSD_AUTH_NONE)) { @@ -893,7 +942,7 @@ add_class(cupsd_client_t *con, /* I - Client connection */ { http_status_t status; /* Policy status */ int i; /* Looping var */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ @@ -914,8 +963,8 @@ add_class(cupsd_client_t *con, /* I - Client connection */ * Do we have a valid URI? */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); @@ -1169,23 +1218,14 @@ add_class(cupsd_client_t *con, /* I - Client connection */ if (need_restart_job && pclass->job) { - cupsd_job_t *job; - /* - * Stop the current job and then restart it below... + * Reset the current job to a "pending" status... */ - job = (cupsd_job_t *)pclass->job; - - cupsdStopJob(job, 1); - - job->state->values[0].integer = IPP_JOB_PENDING; - job->state_value = IPP_JOB_PENDING; + cupsdSetJobState(pclass->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE, + "Job restarted because the class was modified."); } - if (need_restart_job) - cupsdCheckJobs(); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); if (modify) @@ -1252,7 +1292,8 @@ add_file(cupsd_client_t *con, /* I - Connection to client */ if (!compressions || !filetypes) { - cupsdCancelJob(job, 1, IPP_JOB_ABORTED); + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE, + "Job aborted because the scheduler ran out of memory."); if (con) send_ipp_status(con, IPP_INTERNAL_ERROR, @@ -1326,9 +1367,9 @@ add_job(cupsd_client_t *con, /* I - Client connection */ send_http_error(con, status, printer); return (NULL); } - else if (printer->num_auth_info_required > 0 && - strcmp(printer->auth_info_required[0], "none") && - !con->username[0] && !auth_info) + else if (printer->num_auth_info_required == 1 && + !strcmp(printer->auth_info_required[0], "negotiate") && + !con->username[0]) { send_http_error(con, HTTP_UNAUTHORIZED, printer); return (NULL); @@ -1691,14 +1732,14 @@ add_job(cupsd_client_t *con, /* I - Client connection */ * Hold job until specified time... */ - cupsdSetJobHoldUntil(job, attr->values[0].string.text); + cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0); job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; } else if (job->attrs->request.op.operation_id == IPP_CREATE_JOB) { - job->hold_until = time(NULL) + 60; + job->hold_until = time(NULL) + MultipleOperationTimeout; job->state->values[0].integer = IPP_JOB_HELD; job->state_value = IPP_JOB_HELD; } @@ -1724,8 +1765,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 = _cupsStrAlloc(printer->job_sheets[0]); - attr->values[1].string.text = _cupsStrAlloc(printer->job_sheets[1]); + attr->values[0].string.text = _cupsStrRetain(printer->job_sheets[0]); + attr->values[1].string.text = _cupsStrRetain(printer->job_sheets[1]); } job->job_sheets = attr; @@ -1849,7 +1890,9 @@ add_job(cupsd_client_t *con, /* I - Client connection */ if ((kbytes = copy_banner(con, job, attr->values[0].string.text)) < 0) { - cupsdDeleteJob(job); + cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE, + "Aborting job because the start banner could not be " + "copied."); return (NULL); } @@ -1975,7 +2018,7 @@ add_job_state_reasons( /* - * 'add_job_subscriptions()' - Add any subcriptions for a job. + * 'add_job_subscriptions()' - Add any subscriptions for a job. */ static void @@ -2146,24 +2189,25 @@ add_job_subscriptions( if (mask == CUPSD_EVENT_NONE) mask = CUPSD_EVENT_JOB_COMPLETED; - sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job, recipient, - 0); + if ((sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job, + recipient, 0)) != NULL) + { + sub->interval = interval; - sub->interval = interval; + cupsdSetString(&sub->owner, job->username); - cupsdSetString(&sub->owner, job->username); + if (user_data) + { + sub->user_data_len = user_data->values[0].unknown.length; + memcpy(sub->user_data, user_data->values[0].unknown.data, + sub->user_data_len); + } - if (user_data) - { - sub->user_data_len = user_data->values[0].unknown.length; - memcpy(sub->user_data, user_data->values[0].unknown.data, - sub->user_data_len); + ippAddSeparator(con->response); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-subscription-id", sub->id); } - ippAddSeparator(con->response); - ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, - "notify-subscription-id", sub->id); - if (attr) attr = attr->next; } @@ -2443,7 +2487,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * Do we have a valid device URI? */ - http_uri_status_t uri_status; /* URI separation status */ + http_uri_status_t uri_status; /* URI separation status */ + char old_device_uri[1024]; + /* Old device URI */ need_restart_job = 1; @@ -2497,21 +2543,25 @@ 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 \"%s\"!"), - attr->values[0].string.text); + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri scheme \"%s\"!"), + scheme); return; } } + if (printer->sanitized_device_uri) + strlcpy(old_device_uri, printer->sanitized_device_uri, + sizeof(old_device_uri)); + else + old_device_uri[0] = '\0'; + + cupsdSetDeviceURI(printer, attr->values[0].string.text); + cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s device-uri to \"%s\" (was \"%s\".)", - printer->name, - cupsdSanitizeURI(attr->values[0].string.text, line, - sizeof(line)), - cupsdSanitizeURI(printer->device_uri, resource, - sizeof(resource))); + printer->name, printer->sanitized_device_uri, + old_device_uri); - cupsdSetString(&printer->device_uri, attr->values[0].string.text); set_device_uri = 1; } @@ -2525,7 +2575,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ need_restart_job = 1; - supported = ippFindAttribute(printer->attrs, "port-monitor-supported", + supported = ippFindAttribute(printer->ppd_attrs, "port-monitor-supported", IPP_TAG_NAME); if (supported) { @@ -2601,6 +2651,7 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ cupsdSetPrinterState(printer, (ipp_pstate_t)(attr->values[0].integer), 0); } } + if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) != NULL) { @@ -2609,6 +2660,47 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ cupsdAddPrinterHistory(printer); } + if ((attr = ippFindAttribute(con->request, "printer-state-reasons", + IPP_TAG_KEYWORD)) != NULL) + { + if (attr->num_values > + (int)(sizeof(printer->reasons) / sizeof(printer->reasons[0]))) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Too many printer-state-reasons values (%d > %d)!"), + attr->num_values, + (int)(sizeof(printer->reasons) / + sizeof(printer->reasons[0]))); + return; + } + + for (i = 0; i < printer->num_reasons; i ++) + _cupsStrFree(printer->reasons[i]); + + printer->num_reasons = 0; + for (i = 0; i < attr->num_values; i ++) + { + if (!strcmp(attr->values[i].string.text, "none")) + continue; + + printer->reasons[printer->num_reasons] = + _cupsStrRetain(attr->values[i].string.text); + printer->num_reasons ++; + + if (!strcmp(attr->values[i].string.text, "paused") && + printer->state != IPP_PRINTER_STOPPED) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Setting %s printer-state to %d (was %d.)", + printer->name, IPP_PRINTER_STOPPED, printer->state); + cupsdStopPrinter(printer, 0); + } + } + + if (PrintcapFormat == PRINTCAP_PLIST) + cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); + } + set_printer_defaults(con, printer); if ((attr = ippFindAttribute(con->request, "auth-info-required", @@ -2705,8 +2797,11 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * (Re)register color profiles... */ - apple_unregister_profiles(printer); - apple_register_profiles(printer); + if (!RunUser) + { + apple_unregister_profiles(printer); + apple_register_profiles(printer); + } #endif /* __APPLE__ */ } else @@ -2767,8 +2862,11 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ * (Re)register color profiles... */ - apple_unregister_profiles(printer); - apple_register_profiles(printer); + if (!RunUser) + { + apple_unregister_profiles(printer); + apple_register_profiles(printer); + } #endif /* __APPLE__ */ } } @@ -2824,23 +2922,14 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ if (need_restart_job && printer->job) { - cupsd_job_t *job; - /* - * Stop the current job and then restart it below... + * Restart the current job... */ - job = (cupsd_job_t *)printer->job; - - cupsdStopJob(job, 1); - - job->state->values[0].integer = IPP_JOB_PENDING; - job->state_value = IPP_JOB_PENDING; + cupsdSetJobState(printer->job, IPP_JOB_PENDING, CUPSD_JOB_FORCE, + "Job restarted because the printer was modified."); } - if (need_restart_job) - cupsdCheckJobs(); - cupsdMarkDirty(CUPSD_DIRTY_PRINTCAP); if (modify) @@ -2884,8 +2973,7 @@ add_printer_state_reasons( if (p->num_reasons == 0) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, - "printer-state-reasons", NULL, - p->state == IPP_PRINTER_STOPPED ? "paused" : "none"); + "printer-state-reasons", NULL, "none"); else ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "printer-state-reasons", p->num_reasons, NULL, @@ -3330,8 +3418,10 @@ apple_register_profiles( * Use the default colorspace... */ - num_profiles = 1 + ppd->colorspace != PPD_CS_GRAY; - + 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, @@ -3359,14 +3449,15 @@ apple_register_profiles( _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; - - default : - break; } } @@ -3390,8 +3481,8 @@ apple_register_profiles( device_name = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - printer_name = CFStringCreateWithCString(kCFAllocatorDefault, p->name, - kCFStringEncodingUTF8); + printer_name = CFStringCreateWithCString(kCFAllocatorDefault, + p->name, kCFStringEncodingUTF8); if (device_name && printer_name) { @@ -3511,7 +3602,7 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ *auth_info; /* auth-info attribute */ int jobid; /* Job ID */ cupsd_job_t *job; /* Current job */ - char method[HTTP_MAX_URI], + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ @@ -3557,8 +3648,8 @@ authenticate_job(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -3870,21 +3961,28 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ } /* - * See if the printer is currently printing a job... + * See if there are any pending jobs... */ - if (printer->job) - jobid = ((cupsd_job_t *)printer->job)->id; + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->state_value <= IPP_JOB_PROCESSING && + !strcasecmp(job->dest, printer->name)) + break; + + if (job) + jobid = job->id; else { /* - * No, see if there are any pending jobs... + * No, try stopped jobs... */ - for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) - if (job->state_value <= IPP_JOB_PROCESSING && + if (job->state_value == IPP_JOB_STOPPED && !strcasecmp(job->dest, printer->name)) break; @@ -3892,21 +3990,9 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ jobid = job->id; else { - for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); - job; - job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) - if (job->state_value == IPP_JOB_STOPPED && - !strcasecmp(job->dest, printer->name)) - break; - - if (job) - jobid = job->id; - else - { - send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"), - printer->name); - return; - } + send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"), + printer->name); + return; } } } @@ -4005,7 +4091,9 @@ cancel_job(cupsd_client_t *con, /* I - Client connection */ * Cancel the job and return... */ - cupsdCancelJob(job, purge, IPP_JOB_CANCELED); + cupsdSetJobState(job, IPP_JOB_CANCELED, purge, + purge ? "Job purged by \"%s\"" : "Job canceled by \"%s\"", + username); cupsdCheckJobs(); if (purge) @@ -4295,16 +4383,7 @@ check_quotas(cupsd_client_t *con, /* I - Client connection */ "entry ignored", p->users[i]); } - if ((mbr_err = mbr_check_membership(usr_uuid, usr2_uuid, - &is_member)) != 0) - { - cupsdLogMessage(CUPSD_LOG_DEBUG, - "check_quotas: User \"%s\" identity check failed " - "(err=%d)", p->users[i], mbr_err); - is_member = 0; - } - - if (is_member) + if (!uuid_compare(usr_uuid, usr2_uuid)) break; } #else @@ -4472,12 +4551,18 @@ copy_attribute( for (i = 0; i < attr->num_values; i ++) toattr->values[i].string.text = attr->values[i].string.text; } - else + 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 : @@ -4523,7 +4608,7 @@ copy_attribute( toattr->values[i].string.text = attr->values[i].string.text; } } - else + else if (attr->value_tag & IPP_TAG_COPY) { for (i = 0; i < attr->num_values; i ++) { @@ -4538,6 +4623,21 @@ copy_attribute( _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 : @@ -4610,7 +4710,18 @@ copy_attrs(ipp_t *to, /* I - Destination request */ continue; if (!ra || cupsArrayFind(ra, fromattr->name)) + { + /* + * Don't send collection attributes by default to IPP/1.x clients + * since many do not support collections... + */ + + if (fromattr->value_tag == IPP_TAG_BEGIN_COLLECTION && + !ra && to->request.status.version[0] == 1) + continue; + copy_attribute(to, fromattr, quickcopy); + } } } @@ -4801,7 +4912,10 @@ copy_banner(cupsd_client_t *con, /* I - Client connection */ case IPP_TAG_INTEGER : case IPP_TAG_ENUM : if (!strncmp(s, "time-at-", 8)) - cupsFilePuts(out, cupsdGetDateTime(attr->values[i].integer)); + { + struct timeval tv = { attr->values[i].integer, 0 }; + cupsFilePuts(out, cupsdGetDateTime(&tv, CUPSD_TIME_STANDARD)); + } else cupsFilePrintf(out, "%d", attr->values[i].integer); break; @@ -4972,12 +5086,6 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ cups_option_t *defaults; /* Default options */ char cups_protocol[PPD_MAX_LINE]; /* cupsProtocol attribute */ - int have_letter, /* Have Letter size */ - have_a4; /* Have A4 size */ -#ifdef HAVE_LIBPAPER - char *paper_result; /* Paper size name from libpaper */ - char system_paper[64]; /* Paper size name buffer */ -#endif /* HAVE_LIBPAPER */ cupsdLogMessage(CUPSD_LOG_DEBUG2, @@ -5007,7 +5115,7 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ "copy_model: Running \"cups-driverd cat %s\"...", from); if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1], - -1, -1, 0, DefaultProfile, &temppid)) + -1, -1, 0, DefaultProfile, NULL, &temppid)) { close(tempfd); unlink(tempfile); @@ -5102,9 +5210,6 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ return (-1); } - have_letter = ppdPageSize(ppd, "Letter") != NULL; - have_a4 = ppdPageSize(ppd, "A4") != NULL; - /* * Open the destination (if possible) and set the default options... */ @@ -5149,81 +5254,20 @@ copy_model(cupsd_client_t *con, /* I - Client connection */ cupsFileClose(dst); } -#ifdef HAVE_LIBPAPER - else if ((paper_result = systempapername()) != NULL) - { - /* - * Set the default media sizes from the systemwide default... - */ - - strlcpy(system_paper, paper_result, sizeof(system_paper)); - system_paper[0] = toupper(system_paper[0] & 255); - - if ((!strcmp(system_paper, "Letter") && have_letter) || - (!strcmp(system_paper, "A4") && have_a4)) - { - num_defaults = cupsAddOption("PageSize", system_paper, - num_defaults, &defaults); - num_defaults = cupsAddOption("PageRegion", system_paper, - num_defaults, &defaults); - num_defaults = cupsAddOption("PaperDimension", system_paper, - num_defaults, &defaults); - num_defaults = cupsAddOption("ImageableArea", system_paper, - num_defaults, &defaults); - } - } -#endif /* HAVE_LIBPAPER */ - else + else if (ppdPageSize(ppd, DefaultPaperSize)) { /* * Add the default media sizes... - * - * Note: These values are generally not valid for large-format devices - * like plotters, however it is probably safe to say that those - * users will configure the media size after initially adding - * the device anyways... */ - if (!DefaultLanguage || - !strcasecmp(DefaultLanguage, "C") || - !strcasecmp(DefaultLanguage, "POSIX") || - !strcasecmp(DefaultLanguage, "en") || - !strncasecmp(DefaultLanguage, "en.", 3) || - !strncasecmp(DefaultLanguage, "en_US", 5) || - !strncasecmp(DefaultLanguage, "en_CA", 5) || - !strncasecmp(DefaultLanguage, "fr_CA", 5)) - { - /* - * These are the only locales that will default to "letter" size... - */ - - if (have_letter) - { - num_defaults = cupsAddOption("PageSize", "Letter", num_defaults, - &defaults); - num_defaults = cupsAddOption("PageRegion", "Letter", num_defaults, - &defaults); - num_defaults = cupsAddOption("PaperDimension", "Letter", num_defaults, - &defaults); - num_defaults = cupsAddOption("ImageableArea", "Letter", num_defaults, - &defaults); - } - } - else if (have_a4) - { - /* - * The rest default to "a4" size... - */ - - num_defaults = cupsAddOption("PageSize", "A4", num_defaults, - &defaults); - num_defaults = cupsAddOption("PageRegion", "A4", num_defaults, - &defaults); - num_defaults = cupsAddOption("PaperDimension", "A4", num_defaults, - &defaults); - num_defaults = cupsAddOption("ImageableArea", "A4", num_defaults, - &defaults); - } + num_defaults = cupsAddOption("PageSize", DefaultPaperSize, + num_defaults, &defaults); + num_defaults = cupsAddOption("PageRegion", DefaultPaperSize, + num_defaults, &defaults); + num_defaults = cupsAddOption("PaperDimension", DefaultPaperSize, + num_defaults, &defaults); + num_defaults = cupsAddOption("ImageableArea", DefaultPaperSize, + num_defaults, &defaults); } ppdClose(ppd); @@ -5324,6 +5368,10 @@ copy_job_attrs(cupsd_client_t *con, /* I - Client connection */ ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "document-count", 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 (!ra || cupsArrayFind(ra, "job-more-info")) ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_URI, "job-more-info", NULL, job_uri); @@ -5404,7 +5452,7 @@ copy_printer_attrs( if ((p2_uri = ippFindAttribute(p2->attrs, "printer-uri-supported", IPP_TAG_URI)) != NULL) member_uris->values[i].string.text = - _cupsStrAlloc(p2_uri->values[0].string.text); + _cupsStrRetain(p2_uri->values[0].string.text); else { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, @@ -5448,6 +5496,25 @@ copy_printer_attrs( ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-error-policy", NULL, printer->error_policy); + if (!ra || cupsArrayFind(ra, "printer-error-policy-supported")) + { + static const char * const errors[] =/* printer-error-policy-supported values */ + { + "abort-job", + "retry-current-job", + "retry-job", + "stop-printer" + }; + + if (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)) + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, + "printer-error-policy-supported", NULL, "retry-current-job"); + else + ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY, + "printer-error-policy-supported", + sizeof(errors) / sizeof(errors[0]), NULL, errors); + } + if (!ra || cupsArrayFind(ra, "printer-is-accepting-jobs")) ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", printer->accepting); @@ -5456,6 +5523,17 @@ copy_printer_attrs( ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", printer->shared); + if ((!ra || cupsArrayFind(ra, "printer-more-info")) && + !(printer->type & CUPS_PRINTER_DISCOVERED)) + { + httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), + "http", NULL, con->servername, con->serverport, + (printer->type & CUPS_PRINTER_CLASS) ? + "/classes/%s" : "/printers/%s", printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-more-info", NULL, printer_uri); + } + if (!ra || cupsArrayFind(ra, "printer-op-policy")) ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-op-policy", NULL, printer->op_policy); @@ -5521,8 +5599,7 @@ copy_printer_attrs( "printer-up-time", curtime); if ((!ra || cupsArrayFind(ra, "printer-uri-supported")) && - !ippFindAttribute(printer->attrs, "printer-uri-supported", - IPP_TAG_URI)) + !(printer->type & CUPS_PRINTER_DISCOVERED)) { httpAssembleURIf(HTTP_URI_CODING_ALL, printer_uri, sizeof(printer_uri), "ipp", NULL, con->servername, con->serverport, @@ -5538,6 +5615,8 @@ copy_printer_attrs( add_queued_job_count(con, printer); copy_attrs(con->response, printer->attrs, ra, IPP_TAG_ZERO, 0); + 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); } @@ -5785,6 +5864,7 @@ create_requested_array(ipp_t *request) /* I - IPP request */ 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"); @@ -5817,6 +5897,7 @@ create_requested_array(ipp_t *request) /* I - IPP request */ 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"); @@ -5849,6 +5930,7 @@ create_requested_array(ipp_t *request) /* I - IPP request */ 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"); @@ -6210,7 +6292,12 @@ create_subscription( else job = NULL; - sub = cupsdAddSubscription(mask, printer, job, recipient, 0); + if ((sub = cupsdAddSubscription(mask, printer, job, recipient, 0)) == NULL) + { + send_ipp_status(con, IPP_TOO_MANY_SUBSCRIPTIONS, + _("There are too many subscriptions.")); + return; + } if (job) cupsdLogMessage(CUPSD_LOG_DEBUG, "Added subscription %d for job %d", @@ -6321,6 +6408,9 @@ delete_printer(cupsd_client_t *con, /* I - Client connection */ printer->name); unlink(filename); + snprintf(filename, sizeof(filename), "%s/%s.ipp", CacheDir, printer->name); + unlink(filename); + #ifdef __APPLE__ /* * Unregister color profiles... @@ -6405,13 +6495,16 @@ get_devices(cupsd_client_t *con) /* I - Client connection */ ipp_attribute_t *limit, /* limit attribute */ *timeout, /* timeout attribute */ *requested, /* requested-attributes attribute */ - *exclude; /* exclude-schemes attribute */ + *exclude, /* exclude-schemes attribute */ + *include; /* include-schemes attribute */ char command[1024], /* cups-deviced command */ - options[1024], /* Options to pass to command */ + options[2048], /* Options to pass to command */ requested_str[256], /* String for requested attributes */ - exclude_str[512]; - /* String for excluded attributes */ + exclude_str[512], + /* String for excluded schemes */ + include_str[512]; + /* String for included schemes */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->http.fd); @@ -6435,6 +6528,7 @@ get_devices(cupsd_client_t *con) /* I - Client connection */ requested = ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD); exclude = ippFindAttribute(con->request, "exclude-schemes", IPP_TAG_NAME); + include = ippFindAttribute(con->request, "include-schemes", IPP_TAG_NAME); if (requested) url_encode_attr(requested, requested_str, sizeof(requested_str)); @@ -6446,15 +6540,21 @@ get_devices(cupsd_client_t *con) /* I - Client connection */ else exclude_str[0] = '\0'; + if (include) + url_encode_attr(include, include_str, sizeof(include_str)); + else + include_str[0] = '\0'; + snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin); snprintf(options, sizeof(options), - "%d+%d+%d+%d+%s%s%s", + "%d+%d+%d+%d+%s%s%s%s%s", con->request->request.op.request_id, limit ? limit->values[0].integer : 0, timeout ? timeout->values[0].integer : 10, (int)User, requested_str, - exclude_str[0] ? "%20" : "", exclude_str); + exclude_str[0] ? "%20" : "", exclude_str, + include_str[0] ? "%20" : "", include_str); if (cupsdSendCommand(con, command, options, 1)) { @@ -6491,7 +6591,7 @@ get_document(cupsd_client_t *con, /* I - Client connection */ int jobid; /* Job ID */ int docnum; /* Document number */ cupsd_job_t *job; /* Current job */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ @@ -6529,8 +6629,8 @@ get_document(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -6634,7 +6734,7 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *attr; /* Current attribute */ int jobid; /* Job ID */ cupsd_job_t *job; /* Current job */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ @@ -6671,8 +6771,8 @@ get_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -6763,12 +6863,17 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ * Is the destination valid? */ + if (strcmp(uri->name, "printer-uri")) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("No printer-uri in request!")); + return; + } + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); - if (!strcmp(resource, "/") || - (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6)) + if (!strcmp(resource, "/") || !strcmp(resource, "/jobs")) { dest = NULL; dtype = (cups_ptype_t)0; @@ -6841,7 +6946,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ completed = 0; list = Jobs; } - else if (attr && !strcmp(attr->values[0].string.text, "printing")) + else if (attr && !strcmp(attr->values[0].string.text, "processing")) { completed = 0; list = PrintingJobs; @@ -6893,7 +6998,10 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ * Filter out jobs that don't match... */ - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: job->id = %d", job->id); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "get_jobs: job->id=%d, dest=\"%s\", username=\"%s\", " + "state_value=%d, attrs=%p", job->id, job->dest, + job->username, job->state_value, job->attrs); if (!job->dest || !job->username) cupsdLoadJob(job); @@ -6916,7 +7024,11 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ 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)) continue; @@ -6926,11 +7038,11 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ count ++; - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count = %d", count); - copy_job_attrs(con, job, ra); } + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: count=%d", count); + cupsArrayDelete(ra); con->response->request.status.status_code = IPP_OK; @@ -7237,9 +7349,11 @@ get_ppds(cupsd_client_t *con) /* I - Client connection */ *product, /* ppd-product attribute */ *psversion, /* ppd-psverion attribute */ *type, /* ppd-type attribute */ - *requested; /* requested-attributes attribute */ + *requested, /* requested-attributes attribute */ + *exclude, /* exclude-schemes attribute */ + *include; /* include-schemes attribute */ char command[1024], /* cups-driverd command */ - options[1024], /* Options to pass to command */ + options[4096], /* Options to pass to command */ device_str[256],/* Escaped ppd-device-id string */ language_str[256], /* Escaped ppd-natural-language */ @@ -7252,8 +7366,12 @@ get_ppds(cupsd_client_t *con) /* I - Client connection */ psversion_str[256], /* Escaped ppd-psversion string */ type_str[256], /* Escaped ppd-type string */ - requested_str[256]; + requested_str[256], /* String for requested attributes */ + exclude_str[512], + /* String for excluded schemes */ + include_str[512]; + /* String for included schemes */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd); @@ -7286,6 +7404,10 @@ get_ppds(cupsd_client_t *con) /* I - Client connection */ type = ippFindAttribute(con->request, "ppd-type", IPP_TAG_KEYWORD); requested = ippFindAttribute(con->request, "requested-attributes", IPP_TAG_KEYWORD); + exclude = ippFindAttribute(con->request, "exclude-schemes", + IPP_TAG_NAME); + include = ippFindAttribute(con->request, "include-schemes", + IPP_TAG_NAME); if (requested) url_encode_attr(requested, requested_str, sizeof(requested_str)); @@ -7333,9 +7455,19 @@ get_ppds(cupsd_client_t *con) /* I - Client connection */ else type_str[0] = '\0'; + if (exclude) + url_encode_attr(exclude, exclude_str, sizeof(exclude_str)); + else + exclude_str[0] = '\0'; + + if (include) + url_encode_attr(include, include_str, sizeof(include_str)); + else + include_str[0] = '\0'; + snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin); snprintf(options, sizeof(options), - "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", con->request->request.op.request_id, limit ? limit->values[0].integer : 0, requested_str, @@ -7346,7 +7478,9 @@ get_ppds(cupsd_client_t *con) /* I - Client connection */ model_number ? "%20" : "", model_number_str, product ? "%20" : "", product_str, psversion ? "%20" : "", psversion_str, - type ? "%20" : "", type_str); + type ? "%20" : "", type_str, + exclude_str[0] ? "%20" : "", exclude_str, + include_str[0] ? "%20" : "", include_str); if (cupsdSendCommand(con, command, options, 0)) { @@ -7426,6 +7560,61 @@ get_printer_attrs(cupsd_client_t *con, /* I - Client connection */ } +/* + * 'get_printer_supported()' - Get printer supported values. + */ + +static void +get_printer_supported( + cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + cups_ptype_t dtype; /* Destination type (printer/class) */ + cupsd_printer_t *printer; /* Printer/class */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_supported(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status, printer); + return; + } + + /* + * Return a list of attributes that can be set via Set-Printer-Attributes. + */ + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE, + "printer-info", 0); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ADMINDEFINE, + "printer-location", 0); + + con->response->request.status.status_code = IPP_OK; +} + + /* * 'get_printers()' - Get a list of printers or classes. */ @@ -7445,6 +7634,7 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ const char *username; /* Current user */ char *first_printer_name; /* first-printer-name attribute */ cups_array_t *ra; /* Requested attributes array */ + int local; /* Local connection? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con, @@ -7502,6 +7692,8 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ else printer_mask = 0; + local = httpAddrLocalhost(&(con->clientaddr)); + if ((attr = ippFindAttribute(con->request, "printer-location", IPP_TAG_TEXT)) != NULL) location = attr->values[0].string.text; @@ -7534,10 +7726,13 @@ get_printers(cupsd_client_t *con, /* I - Client connection */ count < limit && printer; printer = (cupsd_printer_t *)cupsArrayNext(Printers)) { + if (!local && !printer->shared) + continue; + if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) && (printer->type & printer_mask) == printer_type && - (!location || !printer->location || - !strcasecmp(printer->location, location))) + (!location || + (printer->location && !strcasecmp(printer->location, location)))) { /* * If HideImplicitMembers is enabled, see if this printer or class @@ -7812,10 +8007,10 @@ static void hold_job(cupsd_client_t *con, /* I - Client connection */ ipp_attribute_t *uri) /* I - Job or Printer URI */ { - ipp_attribute_t *attr, /* Current job-hold-until */ - *newattr; /* New job-hold-until */ + ipp_attribute_t *attr; /* Current job-hold-until */ + const char *when; /* New value */ int jobid; /* Job ID */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ @@ -7852,8 +8047,8 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -7899,50 +8094,90 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ * Hold the job and return... */ - cupsdHoldJob(job); + if ((attr = ippFindAttribute(con->request, "job-hold-until", + IPP_TAG_KEYWORD)) == NULL) + attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME); - cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job, - "Job held by user."); + if (attr) + { + when = attr->values[0].string.text; - if ((newattr = ippFindAttribute(con->request, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - newattr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME); + cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job, + "Job job-hold-until value changed by user."); + } + else + when = "indefinite"; - if ((attr = ippFindAttribute(job->attrs, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); + cupsdSetJobHoldUntil(job, when, 1); + cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".", + username); - if (attr) - { - /* - * Free the old hold value and copy the new one over... - */ + con->response->request.status.status_code = IPP_OK; +} - _cupsStrFree(attr->values[0].string.text); - if (newattr) - { - attr->value_tag = newattr->value_tag; - attr->values[0].string.text = - _cupsStrAlloc(newattr->values[0].string.text); - } - else - { - attr->value_tag = IPP_TAG_KEYWORD; - attr->values[0].string.text = _cupsStrAlloc("indefinite"); - } +/* + * 'hold_new_jobs()' - Hold pending/new jobs on a printer or class. + */ + +static void +hold_new_jobs(cupsd_client_t *con, /* I - Connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + cups_ptype_t dtype; /* Destination type (printer/class) */ + cupsd_printer_t *printer; /* Printer data */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_new_jobs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) + { /* - * Hold job until specified time... + * Bad URI... */ - cupsdSetJobHoldUntil(job, attr->values[0].string.text); + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } - cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job, - "Job job-hold-until value changed by user."); + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status, printer); + return; } - cupsdLogJob(job, CUPSD_LOG_INFO, "Held by \"%s\".", username); + /* + * Hold pending/new jobs sent to the printer... + */ + + printer->holding_new_jobs = 1; + + cupsdSetPrinterReasons(printer, "+hold-new-jobs"); + cupsdAddPrinterHistory(printer); + + if (dtype & CUPS_PRINTER_CLASS) + cupsdLogMessage(CUPSD_LOG_INFO, + "Class \"%s\" now holding pending/new jobs (\"%s\").", + printer->name, get_username(con)); + else + cupsdLogMessage(CUPSD_LOG_INFO, + "Printer \"%s\" now holding pending/new jobs (\"%s\").", + printer->name, get_username(con)); + + /* + * Everything was ok, so return OK status... + */ con->response->request.status.status_code = IPP_OK; } @@ -8467,8 +8702,9 @@ print_job(cupsd_client_t *con, /* I - Client connection */ */ if (!strcasecmp(filetype->super, "application") && - !strcasecmp(filetype->type, "postscript")) - read_ps_job_ticket(con); + (!strcasecmp(filetype->type, "postscript") || + !strcasecmp(filetype->type, "pdf"))) + read_job_ticket(con); /* * Create the job object... @@ -8519,6 +8755,8 @@ print_job(cupsd_client_t *con, /* I - Client connection */ "File of type %s/%s queued by \"%s\".", filetype->super, filetype->type, job->username); cupsdLogJob(job, CUPSD_LOG_DEBUG, "hold_until=%d", (int)job->hold_until); + cupsdLogJob(job, CUPSD_LOG_INFO, "Queued on \"%s\" by \"%s\".", + job->dest, job->username); /* * Start the job if possible... @@ -8529,16 +8767,16 @@ print_job(cupsd_client_t *con, /* I - Client connection */ /* - * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file. + * 'read_job_ticket()' - Read a job ticket embedded in a print file. * - * This function only gets called when printing a single PostScript + * This function only gets called when printing a single PDF or PostScript * file using the Print-Job operation. It doesn't work for Create-Job + * Send-File, since the job attributes need to be set at job creation - * time for banners to work. The embedded PS job ticket stuff is here - * only to allow the Windows printer driver for CUPS to pass in JCL + * time for banners to work. The embedded job ticket stuff is here + * primarily to allow the Windows printer driver for CUPS to pass in JCL * options and IPP attributes which otherwise would be lost. * - * The format of a PS job ticket is simple: + * The format of a job ticket is simple: * * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN * @@ -8548,8 +8786,8 @@ print_job(cupsd_client_t *con, /* I - Client connection */ * %cupsJobTicket: attrN=valueN * * Job ticket lines must appear immediately after the first line that - * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop - * looking for job ticket info when it finds a line that does not begin + * specifies PostScript (%!PS-Adobe-3.0) or PDF (%PDF) format, and CUPS + * stops looking for job ticket info when it finds a line that does not begin * with "%cupsJobTicket:". * * The maximum length of a job ticket line, including the prefix, is @@ -8562,7 +8800,7 @@ print_job(cupsd_client_t *con, /* I - Client connection */ */ static void -read_ps_job_ticket(cupsd_client_t *con) /* I - Client connection */ +read_job_ticket(cupsd_client_t *con) /* I - Client connection */ { cups_file_t *fp; /* File to read from */ char line[256]; /* Line data */ @@ -8581,8 +8819,7 @@ read_ps_job_ticket(cupsd_client_t *con) /* I - Client connection */ if ((fp = cupsFileOpen(con->filename, "rb")) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "read_ps_job_ticket: Unable to open PostScript print file " - "- %s", + "Unable to open print file for job ticket - %s", strerror(errno)); return; } @@ -8594,14 +8831,13 @@ read_ps_job_ticket(cupsd_client_t *con) /* I - Client connection */ if (cupsFileGets(fp, line, sizeof(line)) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "read_ps_job_ticket: Unable to read from PostScript print " - "file - %s", + "Unable to read from print file for job ticket - %s", strerror(errno)); cupsFileClose(fp); return; } - if (strncmp(line, "%!PS-Adobe-", 11)) + if (strncmp(line, "%!PS-Adobe-", 11) && strncmp(line, "%PDF-", 5)) { /* * Not a DSC-compliant file, so no job ticket info will be available... @@ -8793,6 +9029,74 @@ reject_jobs(cupsd_client_t *con, /* I - Client connection */ } +/* + * 'release_held_new_jobs()' - Release pending/new jobs on a printer or class. + */ + +static void +release_held_new_jobs( + cupsd_client_t *con, /* I - Connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + cups_ptype_t dtype; /* Destination type (printer/class) */ + cupsd_printer_t *printer; /* Printer data */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_held_new_jobs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status, printer); + return; + } + + /* + * Hold pending/new jobs sent to the printer... + */ + + printer->holding_new_jobs = 0; + + cupsdSetPrinterReasons(printer, "-hold-new-jobs"); + cupsdAddPrinterHistory(printer); + + if (dtype & CUPS_PRINTER_CLASS) + cupsdLogMessage(CUPSD_LOG_INFO, + "Class \"%s\" now printing pending/new jobs (\"%s\").", + printer->name, get_username(con)); + else + cupsdLogMessage(CUPSD_LOG_INFO, + "Printer \"%s\" now printing pending/new jobs (\"%s\").", + printer->name, get_username(con)); + + /* + * Everything was ok, so return OK status... + */ + + con->response->request.status.status_code = IPP_OK; +} + + /* * 'release_job()' - Release a held print job. */ @@ -8803,7 +9107,7 @@ release_job(cupsd_client_t *con, /* I - Client connection */ { ipp_attribute_t *attr; /* Current attribute */ int jobid; /* Job ID */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ @@ -8840,8 +9144,8 @@ release_job(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -8928,6 +9232,8 @@ release_job(cupsd_client_t *con, /* I - Client connection */ cupsdLogJob(job, CUPSD_LOG_INFO, "Released by \"%s\".", username); con->response->request.status.status_code = IPP_OK; + + cupsdCheckJobs(); } @@ -9026,12 +9332,12 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ { ipp_attribute_t *attr; /* Current attribute */ int jobid; /* Job ID */ - char method[HTTP_MAX_URI], /* Method portion of URI */ + cupsd_job_t *job; /* Job information */ + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ host[HTTP_MAX_URI], /* Host portion of URI */ resource[HTTP_MAX_URI]; /* Resource portion of URI */ int port; /* Port portion of URI */ - cupsd_job_t *job; /* Job information */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", con, @@ -9063,8 +9369,8 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -9139,10 +9445,37 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ } /* - * Restart the job and return... + * See if the job-hold-until attribute is specified... */ - cupsdRestartJob(job); + if ((attr = ippFindAttribute(con->request, "job-hold-until", + IPP_TAG_KEYWORD)) == NULL) + attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME); + + if (attr && strcmp(attr->values[0].string.text, "no-hold")) + { + /* + * Return the job to a held state... + */ + + cupsdLogJob(job, CUPSD_LOG_DEBUG, + "Restarted by \"%s\" with job-hold-until=%s.", + username, attr->values[0].string.text); + cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0); + + cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE, + NULL, job, "Job restarted by user with job-hold-until=%s", + attr->values[0].string.text); + } + else + { + /* + * Restart the job... + */ + + cupsdRestartJob(job); + cupsdCheckJobs(); + } cupsdLogJob(job, CUPSD_LOG_INFO, "Restarted by \"%s\".", username); @@ -9275,7 +9608,7 @@ save_auth_info( cupsFileClose(fp); #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5_H) - if (con->gss_have_creds) + if (con->gss_creds) save_krb5_creds(con, job); else if (job->ccname) cupsdClearString(&(job->ccname)); @@ -9292,104 +9625,26 @@ static void save_krb5_creds(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job) /* I - Job */ { -# if !defined(HAVE_KRB5_CC_NEW_UNIQUE) && !defined(HAVE_HEIMDAL) - cupsdLogMessage(CUPSD_LOG_INFO, - "Sorry, your version of Kerberos does not support delegated " - "credentials!"); - return; - -# else - krb5_error_code error; /* Kerberos error code */ - OM_uint32 major_status, /* Major status code */ - minor_status; /* Minor status code */ - krb5_principal principal; /* Kerberos principal */ - - -# ifdef __APPLE__ /* - * If the weak-linked GSSAPI/Kerberos library is not present, don't try - * to use it... + * Get the credentials... */ - if (krb5_init_context == NULL) - return; -# endif /* __APPLE__ */ - - /* - * We MUST create a file-based cache because memory-based caches are - * only valid for the current process/address space. - * - * Due to various bugs/features in different versions of Kerberos, we - * need either the krb5_cc_new_unique() function or Heimdal's version - * of krb5_cc_gen_new() to create a new FILE: credential cache that - * can be passed to the backend. These functions create a temporary - * file (typically in /tmp) containing the cached credentials, which - * are removed when we have successfully printed a job. - */ - -# ifdef HAVE_KRB5_CC_NEW_UNIQUE - if ((error = krb5_cc_new_unique(KerberosContext, "FILE", NULL, - &(job->ccache))) != 0) -# else /* HAVE_HEIMDAL */ - if ((error = krb5_cc_gen_new(KerberosContext, &krb5_fcc_ops, - &(job->ccache))) != 0) -# endif /* HAVE_KRB5_CC_NEW_UNIQUE */ - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to create new credentials cache (%d/%s)", - error, strerror(errno)); - job->ccache = NULL; - return; - } - - if ((error = krb5_parse_name(KerberosContext, con->username, &principal)) != 0) - { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to parse kerberos username (%d/%s)", - error, strerror(errno)); - krb5_cc_destroy(KerberosContext, job->ccache); - job->ccache = NULL; - return; - } - - if ((error = krb5_cc_initialize(KerberosContext, job->ccache, principal))) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to initialize credentials cache (%d/%s)", error, - strerror(errno)); - krb5_cc_destroy(KerberosContext, job->ccache); - krb5_free_principal(KerberosContext, principal); - job->ccache = NULL; - return; - } - - krb5_free_principal(KerberosContext, principal); - - /* - * Copy the user's credentials to the new cache file... - */ - - major_status = gss_krb5_copy_ccache(&minor_status, con->gss_delegated_cred, - job->ccache); - - if (GSS_ERROR(major_status)) - { - cupsdLogGSSMessage(CUPSD_LOG_ERROR, major_status, minor_status, - "Unable to import client credentials cache"); - krb5_cc_destroy(KerberosContext, job->ccache); - job->ccache = NULL; - return; - } + job->ccache = cupsdCopyKrb5Creds(con); /* * Add the KRB5CCNAME environment variable to the job so that the * backend can use the credentials when printing. */ - cupsdSetStringf(&(job->ccname), "KRB5CCNAME=FILE:%s", - krb5_cc_get_name(KerberosContext, job->ccache)); + 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); -# endif /* HAVE_KRB5_CC_NEW_UNIQUE || HAVE_HEIMDAL */ + cupsdLogJob(job, CUPSD_LOG_DEBUG2, "save_krb5_creds: %s", job->ccname); + } + else + cupsdClearString(&(job->ccname)); } #endif /* HAVE_GSSAPI && HAVE_KRB5_H */ @@ -9410,7 +9665,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ cupsd_job_t *job; /* Current job */ char job_uri[HTTP_MAX_URI], /* Job URI */ - method[HTTP_MAX_URI], + scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ @@ -9463,8 +9718,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -9617,11 +9872,7 @@ send_document(cupsd_client_t *con, /* I - Client connection */ else filetype = mimeType(MimeDatabase, super, type); - jformat = ippFindAttribute(job->attrs, "document-format", IPP_TAG_MIMETYPE); - - if (filetype && - (!jformat || - (!strcmp(super, "application") && !strcmp(type, "octet-stream")))) + if (filetype) { /* * Replace the document-format attribute value with the auto-typed or @@ -9631,7 +9882,8 @@ send_document(cupsd_client_t *con, /* I - Client connection */ snprintf(mimetype, sizeof(mimetype), "%s/%s", filetype->super, filetype->type); - if (jformat) + if ((jformat = ippFindAttribute(job->attrs, "document-format", + IPP_TAG_MIMETYPE)) != NULL) { _cupsStrFree(jformat->values[0].string.text); @@ -9746,7 +9998,7 @@ 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) + 60; + job->hold_until = time(NULL) + MultipleOperationTimeout; job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); @@ -9792,39 +10044,71 @@ send_http_error( http_status_t status, /* I - HTTP status code */ cupsd_printer_t *printer) /* I - Printer, if any */ { - cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", - ippOpString(con->request->request.op.operation_id), - httpStatus(status)); - - if (status == HTTP_UNAUTHORIZED && - printer && printer->num_auth_info_required > 0 && - !strcmp(printer->auth_info_required[0], "negotiate")) - cupsdSendError(con, status, CUPSD_AUTH_NEGOTIATE); - else if (printer) - { - char resource[HTTP_MAX_URI]; /* Resource portion of URI */ - cupsd_location_t *auth; /* Pointer to authentication element */ + ipp_attribute_t *uri; /* Request URI, if any */ + + + if ((uri = ippFindAttribute(con->request, "printer-uri", + IPP_TAG_URI)) == NULL) + 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), + uri ? uri->values[0].string.text : "no URI", + con->http.hostname); + + if (printer) + { int auth_type; /* Type of authentication required */ - if (printer->type & CUPS_PRINTER_CLASS) - snprintf(resource, sizeof(resource), "/classes/%s", printer->name); - else - snprintf(resource, sizeof(resource), "/printers/%s", printer->name); - - if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL || - auth->type == CUPSD_AUTH_NONE) - auth = cupsdFindPolicyOp(printer->op_policy_ptr, - con->request ? - con->request->request.op.operation_id : - IPP_PRINT_JOB); - - if (!auth) - auth_type = CUPSD_AUTH_NONE; - else if (auth->type == CUPSD_AUTH_DEFAULT) - auth_type = DefaultAuthType; + auth_type = CUPSD_AUTH_NONE; + + if (status == HTTP_UNAUTHORIZED && + printer->num_auth_info_required > 0 && + !strcmp(printer->auth_info_required[0], "negotiate") && + con->request && + (con->request->request.op.operation_id == IPP_PRINT_JOB || + con->request->request.op.operation_id == IPP_CREATE_JOB || + con->request->request.op.operation_id == CUPS_AUTHENTICATE_JOB)) + { + /* + * Creating and authenticating jobs requires Kerberos... + */ + + auth_type = CUPSD_AUTH_NEGOTIATE; + } else - auth_type = auth->type; + { + /* + * Use policy/location-defined authentication requirements... + */ + + char resource[HTTP_MAX_URI]; /* Resource portion of URI */ + cupsd_location_t *auth; /* Pointer to authentication element */ + + + if (printer->type & CUPS_PRINTER_CLASS) + snprintf(resource, sizeof(resource), "/classes/%s", printer->name); + else + snprintf(resource, sizeof(resource), "/printers/%s", printer->name); + + if ((auth = cupsdFindBest(resource, HTTP_POST)) == NULL || + auth->type == CUPSD_AUTH_NONE) + auth = cupsdFindPolicyOp(printer->op_policy_ptr, + con->request ? + con->request->request.op.operation_id : + IPP_PRINT_JOB); + + if (auth) + { + if (auth->type == CUPSD_AUTH_DEFAULT) + auth_type = DefaultAuthType; + else + auth_type = auth->type; + } + } cupsdSendError(con, status, auth_type); } @@ -9961,7 +10245,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ *attr2; /* Job attribute */ int jobid; /* Job ID */ cupsd_job_t *job; /* Current job */ - char method[HTTP_MAX_URI], + char scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ @@ -9971,6 +10255,7 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ /* Resource portion of URI */ int port; /* Port portion of URI */ int event; /* Events? */ + int check_jobs; /* Check jobs? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con, @@ -10008,8 +10293,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Got a job URI; parse it to get the job ID... */ - httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, + httpSeparateURI(HTTP_URI_CODING_ALL, uri->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); if (strncmp(resource, "/jobs/", 6)) @@ -10072,7 +10357,8 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ cupsdLoadJob(job); - event = 0; + check_jobs = 0; + event = 0; for (attr = con->request->attrs; attr; attr = attr->next) { @@ -10138,9 +10424,13 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ } else if (con->response->request.status.status_code == IPP_OK) { + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-priority to %d", + attr->values[0].integer); cupsdSetJobPriority(job, attr->values[0].integer); - event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | - CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED; + + check_jobs = 1; + event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | + CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED; } } else if (!strcmp(attr->name, "job-state")) @@ -10170,10 +10460,12 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ } else if (con->response->request.status.status_code == IPP_OK) { - job->state->values[0].integer = attr->values[0].integer; - job->state_value = (ipp_jstate_t)attr->values[0].integer; - - event |= CUPSD_EVENT_JOB_STATE; + 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); + check_jobs = 1; } break; @@ -10197,7 +10489,14 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ return; } else if (con->response->request.status.status_code == IPP_OK) - cupsdCancelJob(job, 0, (ipp_jstate_t)attr->values[0].integer); + { + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d", + attr->values[0].integer); + cupsdSetJobState(job, (ipp_jstate_t)attr->values[0].integer, + CUPSD_JOB_DEFAULT, + "Job state changed by \"%s\"", username); + check_jobs = 1; + } break; } } @@ -10233,12 +10532,18 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ if (!strcmp(attr->name, "job-hold-until")) { - cupsdSetJobHoldUntil(job, attr->values[0].string.text); + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", + attr->values[0].string.text); + cupsdSetJobHoldUntil(job, attr->values[0].string.text, 0); if (!strcmp(attr->values[0].string.text, "no-hold")) + { cupsdReleaseJob(job); + check_jobs = 1; + } else - cupsdHoldJob(job); + cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, + "Job held by \"%s\".", username); event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE; } @@ -10306,7 +10611,91 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ * Start jobs if possible... */ - cupsdCheckJobs(); + if (check_jobs) + cupsdCheckJobs(); +} + + +/* + * 'set_printer_attrs()' - Set printer attributes. + */ + +static void +set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer */ +{ + http_status_t status; /* Policy status */ + cups_ptype_t dtype; /* Destination type (printer/class) */ + cupsd_printer_t *printer; /* Printer/class */ + ipp_attribute_t *attr; /* Printer attribute */ + int changed = 0; /* Was anything changed? */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + if (!cupsdValidateDest(uri->values[0].string.text, &dtype, &printer)) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status, printer); + return; + } + + /* + * Return a list of attributes that can be set via Set-Printer-Attributes. + */ + + if ((attr = ippFindAttribute(con->request, "printer-location", + IPP_TAG_TEXT)) != NULL) + { + cupsdSetString(&printer->location, attr->values[0].string.text); + changed = 1; + } + + if ((attr = ippFindAttribute(con->request, "printer-info", + IPP_TAG_TEXT)) != NULL) + { + cupsdSetString(&printer->info, attr->values[0].string.text); + changed = 1; + } + + /* + * Update the printer attributes and return... + */ + + if (changed) + { + cupsdSetPrinterAttrs(printer); + cupsdMarkDirty(CUPSD_DIRTY_PRINTERS); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_CONFIG, printer, NULL, + "Printer \"%s\" description or location changed by \"%s\".", + printer->name, get_username(con)); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Printer \"%s\" description or location changed by \"%s\".", + printer->name, get_username(con)); + } + + con->response->request.status.status_code = IPP_OK; } @@ -10451,9 +10840,11 @@ set_printer_defaults( if (attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_KEYWORD) continue; - if (strcmp(attr->values[0].string.text, "abort-job") && - strcmp(attr->values[0].string.text, "retry-job") && - strcmp(attr->values[0].string.text, "stop-printer")) + if (strcmp(attr->values[0].string.text, "retry-current-job") && + ((printer->type & (CUPS_PRINTER_IMPLICIT | 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")))) { send_ipp_status(con, IPP_NOT_POSSIBLE, _("Unknown printer-error-policy \"%s\"."), @@ -11026,5 +11417,5 @@ validate_user(cupsd_job_t *job, /* I - Job */ /* - * End of "$Id: ipp.c 7682 2008-06-21 00:06:02Z mike $". + * End of "$Id: ipp.c 7944 2008-09-16 22:32:42Z mike $". */