X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=scheduler%2Fipp.c;h=637d760b4fdf7120c6b68a88a485cbad2cfe0d7c;hp=a867cbbc8e31b2fc8fcfc1f24fb29c8ad2b3d979;hb=f11a948a02771f78f50b530880a0269d4b4f58eb;hpb=d1c13e168660dfc384ead2efe29eb20a7abc5950 diff --git a/scheduler/ipp.c b/scheduler/ipp.c index a867cbbc8..637d760b4 100644 --- a/scheduler/ipp.c +++ b/scheduler/ipp.c @@ -299,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, @@ -346,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 @@ -355,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 @@ -1202,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) @@ -1285,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, @@ -1359,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); @@ -1724,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; } @@ -1882,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); } @@ -2641,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) { @@ -2674,8 +2685,9 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer->reasons[printer->num_reasons] = _cupsStrRetain(attr->values[i].string.text); + printer->num_reasons ++; - if (!strcmp(printer->reasons[printer->num_reasons], "paused") && + if (!strcmp(attr->values[i].string.text, "paused") && printer->state != IPP_PRINTER_STOPPED) { cupsdLogMessage(CUPSD_LOG_INFO, @@ -2683,8 +2695,6 @@ add_printer(cupsd_client_t *con, /* I - Client connection */ printer->name, IPP_PRINTER_STOPPED, printer->state); cupsdStopPrinter(printer, 0); } - - printer->num_reasons ++; } if (PrintcapFormat == PRINTCAP_PLIST) @@ -2912,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) @@ -2972,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, @@ -3418,8 +3418,10 @@ apple_register_profiles( * Use the default colorspace... */ - num_profiles = 2; + 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, @@ -3447,8 +3449,11 @@ apple_register_profiles( _ppdHashName("CMYK.."), "CMYK", "CMYK", NULL); break; + case PPD_CS_GRAY : + if (attr) + break; + case PPD_CS_N : - default : apple_init_profile(ppd, NULL, profiles->profiles + 1, _ppdHashName("DeviceN.."), "DeviceN", "DeviceN", NULL); @@ -3956,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; @@ -3978,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; } } } @@ -4091,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) @@ -4910,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; @@ -5110,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); @@ -5491,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); @@ -6849,7 +6873,7 @@ get_jobs(cupsd_client_t *con, /* I - Client connection */ sizeof(scheme), username, sizeof(username), host, sizeof(host), &port, resource, sizeof(resource)); - if (!strcmp(resource, "/")) + if (!strcmp(resource, "/") || !strcmp(resource, "/jobs")) { dest = NULL; dtype = (cups_ptype_t)0; @@ -7610,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, @@ -7667,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; @@ -7699,6 +7726,9 @@ 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 || @@ -7977,8 +8007,8 @@ 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 scheme[HTTP_MAX_URI], /* Method portion of URI */ username[HTTP_MAX_URI], /* Username portion of URI */ @@ -8064,50 +8094,23 @@ hold_job(cupsd_client_t *con, /* I - Client connection */ * Hold the job and return... */ - cupsdHoldJob(job); - - cupsdAddEvent(CUPSD_EVENT_JOB_STATE, cupsdFindDest(job->dest), job, - "Job held by user."); - - if ((newattr = ippFindAttribute(con->request, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - newattr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME); - - if ((attr = ippFindAttribute(job->attrs, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); + if ((attr = ippFindAttribute(con->request, "job-hold-until", + IPP_TAG_KEYWORD)) == NULL) + attr = ippFindAttribute(con->request, "job-hold-until", IPP_TAG_NAME); if (attr) { - /* - * Free the old hold value and copy the new one over... - */ - - _cupsStrFree(attr->values[0].string.text); - - if (newattr) - { - attr->value_tag = newattr->value_tag; - attr->values[0].string.text = - _cupsStrRetain(newattr->values[0].string.text); - } - else - { - attr->value_tag = IPP_TAG_KEYWORD; - attr->values[0].string.text = _cupsStrAlloc("indefinite"); - } - - /* - * Hold job until specified time... - */ - - cupsdSetJobHoldUntil(job, attr->values[0].string.text); + when = attr->values[0].string.text; cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, cupsdFindDest(job->dest), job, - "Job job-hold-until value changed by user."); + "Job job-hold-until value changed by user."); } + else + when = "indefinite"; - cupsdLogJob(job, CUPSD_LOG_INFO, "Held by \"%s\".", username); + cupsdSetJobHoldUntil(job, when, 1); + cupsdSetJobState(job, IPP_JOB_HELD, CUPSD_JOB_DEFAULT, "Job held by \"%s\".", + username); con->response->request.status.status_code = IPP_OK; } @@ -9329,12 +9332,12 @@ restart_job(cupsd_client_t *con, /* I - Client connection */ { ipp_attribute_t *attr; /* Current attribute */ int jobid; /* Job ID */ + 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, @@ -9442,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); @@ -9578,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)); @@ -9595,121 +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__ */ - - if (!KerberosInitialized) - { - /* - * Setup a Kerberos context for the scheduler to use... - */ - - KerberosInitialized = 1; - - if (krb5_init_context(&KerberosContext)) - { - KerberosContext = NULL; - - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize Kerberos context"); - return; - } - } - - /* - * 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 */ @@ -10063,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); @@ -10527,11 +10462,9 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d", attr->values[0].integer); - - job->state->values[0].integer = attr->values[0].integer; - job->state_value = (ipp_jstate_t)attr->values[0].integer; - - event |= CUPSD_EVENT_JOB_STATE; + cupsdSetJobState(job, attr->values[0].integer, + CUPSD_JOB_DEFAULT, + "Job state changed by \"%s\"", username); check_jobs = 1; } break; @@ -10559,8 +10492,9 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d", attr->values[0].integer); - cupsdCancelJob(job, 0, (ipp_jstate_t)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; @@ -10600,15 +10534,18 @@ set_job_attrs(cupsd_client_t *con, /* I - Client connection */ { cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s", attr->values[0].string.text); - cupsdSetJobHoldUntil(job, 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); - check_jobs = 1; - event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE; + event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE; } } else if (attr->value_tag == IPP_TAG_DELETEATTR) @@ -10691,7 +10628,7 @@ set_printer_attrs(cupsd_client_t *con, /* I - Client connection */ cups_ptype_t dtype; /* Destination type (printer/class) */ cupsd_printer_t *printer; /* Printer/class */ ipp_attribute_t *attr; /* Printer attribute */ - int changed; /* Was anything changed? */ + int changed = 0; /* Was anything changed? */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_printer_attrs(%p[%d], %s)", con, @@ -10903,10 +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-current-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\"."),