X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fcups.git;a=blobdiff_plain;f=scheduler%2Fjob.c;h=1b12fe5a152826774544c93db180c94678e0b82b;hp=2af8785ce1063e6e7f2bfbb1a0540e880a07fe5b;hb=57b7b66b58a66426494ec13ffb18f730afeab8b5;hpb=8fe0183a710b1daacad419e617ddd3601085bfcf diff --git a/scheduler/job.c b/scheduler/job.c index 2af8785ce..1b12fe5a1 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1,16 +1,14 @@ /* - * "$Id$" - * * Job management routines for the CUPS scheduler. * - * Copyright 2007-2014 by Apple Inc. + * Copyright 2007-2016 by Apple Inc. * Copyright 1997-2007 by Easy Software Products, all rights reserved. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright * law. Distribution and use rights are outlined in the file "LICENSE.txt" * which should have been included with this file. If this file is - * file is missing or damaged, see the license at "http://www.cups.org/". + * missing or damaged, see the license at "http://www.cups.org/". */ /* @@ -119,6 +117,7 @@ static mime_filter_t gziptoany_filter = */ static int compare_active_jobs(void *first, void *second, void *data); +static int compare_completed_jobs(void *first, void *second, void *data); static int compare_jobs(void *first, void *second, void *data); static void dump_job_history(cupsd_job_t *job); static void finalize_job(cupsd_job_t *job, int set_job_state); @@ -212,8 +211,6 @@ cupsdCancelJobs(const char *dest, /* I - Destination to cancel */ "Job canceled by user."); } } - - cupsdCheckJobs(); } @@ -230,14 +227,12 @@ cupsdCheckJobs(void) *pclass; /* Printer class destination */ ipp_attribute_t *attr; /* Job attribute */ time_t curtime; /* Current time */ + const char *reasons; /* job-state-reasons value */ curtime = time(NULL); - cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdCheckJobs: %d active jobs, sleeping=%d, reload=%d, " - "curtime=%ld", cupsArrayCount(ActiveJobs), Sleeping, - NeedReload, (long)curtime); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckJobs: %d active jobs, sleeping=%d, ac-power=%d, reload=%d, curtime=%ld", cupsArrayCount(ActiveJobs), Sleeping, ACPower, NeedReload, (long)curtime); for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; @@ -326,12 +321,31 @@ cupsdCheckJobs(void) ((FilterLevel + job->pending_cost) < FilterLimit || FilterLevel == 0)) cupsdContinueJob(job); + /* + * Skip jobs that where held-on-create + */ + + reasons = ippGetString(job->reasons, 0, NULL); + if (reasons && !strcmp(reasons, "job-held-on-create")) + { + /* + * Check whether the printer is still holding new jobs... + */ + + printer = cupsdFindDest(job->dest); + + if (printer->holding_new_jobs) + continue; + + ippSetString(job->attrs, &job->reasons, 0, "none"); + } + /* * Start pending jobs if the destination is available... */ if (job->state_value == IPP_JOB_PENDING && !NeedReload && - !Sleeping && !DoingShutdown && !job->printer) + (!Sleeping || ACPower) && !DoingShutdown && !job->printer) { printer = cupsdFindDest(job->dest); pclass = NULL; @@ -363,7 +377,7 @@ cupsdCheckJobs(void) "Job aborted because the destination printer/class " "has gone away."); } - else if (printer && !printer->holding_new_jobs) + else if (printer) { /* * See if the printer is available or remote and not printing a job; @@ -373,16 +387,14 @@ cupsdCheckJobs(void) if (pclass) { /* - * Add/update a job-actual-printer-uri attribute for this job + * Add/update a job-printer-uri-actual attribute for this job * so that we know which printer actually printed the job... */ - if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri", - IPP_TAG_URI)) != NULL) - cupsdSetString(&attr->values[0].string.text, printer->uri); + if ((attr = ippFindAttribute(job->attrs, "job-printer-uri-actual", IPP_TAG_URI)) != NULL) + ippSetString(job->attrs, &attr, 0, printer->uri); else - ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, - "job-actual-printer-uri", NULL, printer->uri); + ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri-actual", NULL, printer->uri); job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); @@ -394,7 +406,9 @@ cupsdCheckJobs(void) * Start the job... */ + cupsArraySave(ActiveJobs); start_job(job, printer); + cupsArrayRestore(ActiveJobs); } } } @@ -444,6 +458,8 @@ cupsdCleanJobs(void) cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing document files."); remove_job_files(job); + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate) JobHistoryUpdate = job->history_time; } @@ -491,7 +507,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ /* Pipes used between filters */ int envc; /* Number of environment variables */ struct stat fileinfo; /* Job file information */ - int argc; /* Number of arguments */ + int argc = 0; /* Number of arguments */ char **argv = NULL, /* Filter command-line arguments */ filename[1024], /* Job filename */ command[1024], /* Full path to command */ @@ -563,12 +579,37 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ * Local jobs get filtered... */ + mime_type_t *dst = job->printer->filetype; + /* Destination file type */ + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, job->current_file + 1); if (stat(filename, &fileinfo)) fileinfo.st_size = 0; - filters = mimeFilter2(MimeDatabase, job->filetypes[job->current_file], (size_t)fileinfo.st_size, job->printer->filetype, &(job->cost)); + if (job->retry_as_raster) + { + /* + * Need to figure out whether the printer supports image/pwg-raster or + * image/urf, and use the corresponding type... + */ + + char type[MIME_MAX_TYPE]; /* MIME media type for printer */ + + snprintf(type, sizeof(type), "%s/image/urf", job->printer->name); + if ((dst = mimeType(MimeDatabase, "printer", type)) == NULL) + { + snprintf(type, sizeof(type), "%s/image/pwg-raster", job->printer->name); + dst = mimeType(MimeDatabase, "printer", type); + } + + if (dst) + cupsdLogJob(job, CUPSD_LOG_DEBUG, "Retrying job as \"%s\".", strchr(dst->type, '/') + 1); + else + cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to retry job using a supported raster format."); + } + + filters = mimeFilter2(MimeDatabase, job->filetypes[job->current_file], (size_t)fileinfo.st_size, dst, &(job->cost)); if (!filters) { @@ -707,8 +748,8 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ * Add decompression/raw filter as needed... */ - if (job->compressions[job->current_file] && - (!job->printer->remote || job->num_files == 1)) + if ((job->compressions[job->current_file] && (!job->printer->remote || job->num_files == 1)) || + (!job->printer->remote && job->printer->raw && job->num_files > 1)) { /* * Add gziptoany filter to the front of the list... @@ -1208,7 +1249,7 @@ cupsdContinueJob(cupsd_job_t *job) /* I - Job */ else if (stat(command, &backinfo)) backroot = 0; else - backroot = !(backinfo.st_mode & (S_IRWXG | S_IRWXO)); + backroot = !(backinfo.st_mode & (S_IWGRP | S_IRWXO)); argv[0] = job->printer->sanitized_device_uri; @@ -1430,6 +1471,30 @@ cupsdFindJob(int id) /* I - Job ID */ } +/* + * 'cupsdGetCompletedJobs()'- Generate a completed jobs list. + */ + +cups_array_t * /* O - Array of jobs */ +cupsdGetCompletedJobs( + cupsd_printer_t *p) /* I - Printer */ +{ + cups_array_t *list; /* Array of jobs */ + cupsd_job_t *job; /* Current job */ + + + list = cupsArrayNew(compare_completed_jobs, NULL); + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + if ((!p || !_cups_strcasecmp(p->name, job->dest)) && job->state_value >= IPP_JOB_STOPPED && job->completed_time) + cupsArrayAdd(list, job); + + return (list); +} + + /* * 'cupsdGetPrinterJobCount()' - Get the number of pending, processing, * or held jobs in a printer or class. @@ -1484,9 +1549,10 @@ void cupsdLoadAllJobs(void) { char filename[1024]; /* Full filename of job.cache file */ - struct stat fileinfo, /* Information on job.cache file */ - dirinfo; /* Information on RequestRoot dir */ - + struct stat fileinfo; /* Information on job.cache file */ + cups_dir_t *dir; /* RequestRoot dir */ + cups_dentry_t *dent; /* Entry in RequestRoot */ + int load_cache = 1; /* Load the job.cache file? */ /* @@ -1510,36 +1576,65 @@ cupsdLoadAllJobs(void) if (stat(filename, &fileinfo)) { - fileinfo.st_mtime = 0; + /* + * No job.cache file... + */ + + load_cache = 0; if (errno != ENOENT) cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get file information for \"%s\" - %s", filename, strerror(errno)); } + else if ((dir = cupsDirOpen(RequestRoot)) == NULL) + { + /* + * No spool directory... + */ - if (stat(RequestRoot, &dirinfo)) + load_cache = 0; + } + else { - dirinfo.st_mtime = 0; + while ((dent = cupsDirRead(dir)) != NULL) + { + if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c' && dent->fileinfo.st_mtime > fileinfo.st_mtime) + { + /* + * Job history file is newer than job.cache file... + */ - if (errno != ENOENT) - cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to get directory information for \"%s\" - %s", - RequestRoot, strerror(errno)); + load_cache = 0; + break; + } + } + + cupsDirClose(dir); } /* * Load the most recent source for job data... */ - if (dirinfo.st_mtime > fileinfo.st_mtime) + if (load_cache) { + /* + * Load the job.cache file... + */ + + load_job_cache(filename); + } + else + { + /* + * Load the job history files... + */ + load_request_root(); load_next_job_id(filename); } - else - load_job_cache(filename); /* * Clean out old jobs as needed... @@ -1625,10 +1720,13 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ job->file_time = 0; job->history_time = 0; - if (job->state_value >= IPP_JOB_CANCELED && - (attr = ippFindAttribute(job->attrs, "time-at-completed", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER)) != NULL) + job->creation_time = attr->values[0].integer; + + if (job->state_value >= IPP_JOB_CANCELED && (attr = ippFindAttribute(job->attrs, "time-at-completed", IPP_TAG_INTEGER)) != NULL) { + job->completed_time = attr->values[0].integer; + if (JobHistory < INT_MAX) job->history_time = attr->values[0].integer + JobHistory; else @@ -1743,9 +1841,12 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ ippSetString(job->attrs, &job->reasons, 0, "none"); } - job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", - IPP_TAG_INTEGER); - job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); + job->impressions = ippFindAttribute(job->attrs, "job-impressions-completed", IPP_TAG_INTEGER); + job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", IPP_TAG_INTEGER); + job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); + + if (!job->impressions) + job->impressions = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", 0); if (!job->priority) { @@ -1774,6 +1875,12 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ cupsdSetString(&job->username, attr->values[0].string.text); } + if (!job->name) + { + if ((attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL) + cupsdSetString(&job->name, attr->values[0].string.text); + } + /* * Set the job hold-until time and state... */ @@ -1798,6 +1905,9 @@ cupsdLoadJob(cupsd_job_t *job) /* I - Job */ job->state_value = IPP_JOB_PENDING; } + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) + job->koctets = attr->values[0].integer; + if (!job->num_files) { /* @@ -2007,7 +2117,7 @@ cupsdMoveJob(cupsd_job_t *job, /* I - Job */ if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL) - cupsdSetString(&(attr->values[0].string.text), p->uri); + ippSetString(job->attrs, &attr, 0, p->uri); cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job, "Job #%d moved from %s to %s.", job->id, olddest, @@ -2101,13 +2211,29 @@ cupsdSaveAllJobs(void) job; job = (cupsd_job_t *)cupsArrayNext(Jobs)) { + if (job->printer && job->printer->temporary) + { + /* + * Don't save jobs on temporary printers... + */ + + continue; + } + cupsFilePrintf(fp, "\n", job->id); cupsFilePrintf(fp, "State %d\n", job->state_value); + cupsFilePrintf(fp, "Created %ld\n", (long)job->creation_time); + if (job->completed_time) + cupsFilePrintf(fp, "Completed %ld\n", (long)job->completed_time); cupsFilePrintf(fp, "Priority %d\n", job->priority); - cupsFilePrintf(fp, "HoldUntil %d\n", (int)job->hold_until); + if (job->hold_until) + cupsFilePrintf(fp, "HoldUntil %ld\n", (long)job->hold_until); cupsFilePrintf(fp, "Username %s\n", job->username); + if (job->name) + cupsFilePutConf(fp, "Name", job->name); cupsFilePrintf(fp, "Destination %s\n", job->dest); cupsFilePrintf(fp, "DestType %d\n", job->dtype); + cupsFilePrintf(fp, "KOctets %d\n", job->koctets); cupsFilePrintf(fp, "NumFiles %d\n", job->num_files); for (i = 0; i < job->num_files; i ++) cupsFilePrintf(fp, "File %d %s/%s %d\n", i + 1, job->filetypes[i]->super, @@ -2133,6 +2259,16 @@ cupsdSaveJob(cupsd_job_t *job) /* I - Job */ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p", job, job->id, job->attrs); + if (job->printer && job->printer->temporary) + { + /* + * Don't save jobs on temporary printers... + */ + + job->dirty = 0; + return; + } + snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id); if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL) @@ -2197,7 +2333,7 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); if (attr) - cupsdSetString(&(attr->values[0].string.text), when); + ippSetString(job->attrs, &attr, 0, when); else attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-hold-until", NULL, when); @@ -2213,9 +2349,13 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ cupsdMarkDirty(CUPSD_DIRTY_JOBS); } - ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified"); } + if (strcmp(when, "no-hold")) + ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified"); + else + ippSetString(job->attrs, &job->reasons, 0, "none"); + /* * Update the hold time... */ @@ -2451,8 +2591,8 @@ cupsdSetJobState( if (attr) { - attr->value_tag = IPP_TAG_KEYWORD; - cupsdSetString(&(attr->values[0].string.text), "no-hold"); + ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD); + ippSetString(job->attrs, &attr, 0, "no-hold"); } default : @@ -2684,7 +2824,8 @@ cupsdUnloadCompletedJobs(void) if (job->dirty) cupsdSaveJob(job); - unload_job(job); + if (!job->dirty) + unload_job(job); } } @@ -2767,6 +2908,28 @@ compare_active_jobs(void *first, /* I - First job */ } +/* + * 'compare_completed_jobs()' - Compare the job IDs and completion times of two jobs. + */ + +static int /* O - Difference */ +compare_completed_jobs(void *first, /* I - First job */ + void *second, /* I - Second job */ + void *data) /* I - App data (not used) */ +{ + int diff; /* Difference */ + + + (void)data; + + if ((diff = ((cupsd_job_t *)second)->completed_time - + ((cupsd_job_t *)first)->completed_time) != 0) + return (diff); + else + return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id); +} + + /* * 'compare_jobs()' - Compare the job IDs of two jobs. */ @@ -3043,7 +3206,7 @@ finalize_job(cupsd_job_t *job, /* I - Job */ /* * Convert the status to an exit code. Due to the way the W* macros are - * implemented on MacOS X (bug?), we have to store the exit status in a + * implemented on macOS (bug?), we have to store the exit status in a * variable first and then convert... */ @@ -3381,6 +3544,13 @@ finalize_job(cupsd_job_t *job, /* I - Job */ cupsArrayRemove(PrintingJobs, job); + /* + * Clear informational messages... + */ + + if (job->status_level > CUPSD_LOG_ERROR) + job->printer->state_message[0] = '\0'; + /* * Apply any PPD updates... */ @@ -3402,13 +3572,6 @@ finalize_job(cupsd_job_t *job, /* I - Job */ job->printer->job = NULL; job->printer = NULL; - - /* - * Try printing another job... - */ - - if (printer_state != IPP_PRINTER_STOPPED) - cupsdCheckJobs(); } @@ -3970,14 +4133,13 @@ load_job_cache(const char *filename) /* I - job.cache filename */ { if (job) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing directive on line %d.", - linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing directive on line %d of %s.", linenum, filename); continue; } if (!value) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing job ID on line %d.", linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing job ID on line %d of %s.", linenum, filename); continue; } @@ -3985,8 +4147,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (jobid < 1) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad job ID %d on line %d.", jobid, - linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad job ID %d on line %d of %s.", jobid, linenum, filename); continue; } @@ -3998,7 +4159,15 @@ load_job_cache(const char *filename) /* I - job.cache filename */ { cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Files have gone away.", jobid); - continue; + + /* + * job.cache file is out-of-date compared to spool directory; load + * that instead... + */ + + cupsFileClose(fp); + load_request_root(); + return; } } @@ -4025,7 +4194,7 @@ load_job_cache(const char *filename) /* I - job.cache filename */ else if (!job) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing directive on line %d.", linenum); + "Missing directive on line %d of %s.", linenum, filename); continue; } else if (!_cups_strcasecmp(line, "")) @@ -4034,12 +4203,20 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (job->state_value <= IPP_JOB_STOPPED && cupsdLoadJob(job)) cupsArrayAdd(ActiveJobs, job); + else if (job->state_value > IPP_JOB_STOPPED) + { + if (!job->completed_time || !job->creation_time || !job->name || !job->koctets) + { + cupsdLoadJob(job); + unload_job(job); + } + } job = NULL; } else if (!value) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d.", linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d of %s.", linenum, filename); continue; } else if (!_cups_strcasecmp(line, "State")) @@ -4051,9 +4228,21 @@ load_job_cache(const char *filename) /* I - job.cache filename */ else if (job->state_value > IPP_JOB_COMPLETED) job->state_value = IPP_JOB_COMPLETED; } + else if (!_cups_strcasecmp(line, "Name")) + { + cupsdSetString(&(job->name), value); + } + else if (!_cups_strcasecmp(line, "Created")) + { + job->creation_time = strtol(value, NULL, 10); + } + else if (!_cups_strcasecmp(line, "Completed")) + { + job->completed_time = strtol(value, NULL, 10); + } else if (!_cups_strcasecmp(line, "HoldUntil")) { - job->hold_until = atoi(value); + job->hold_until = strtol(value, NULL, 10); } else if (!_cups_strcasecmp(line, "Priority")) { @@ -4071,14 +4260,17 @@ load_job_cache(const char *filename) /* I - job.cache filename */ { job->dtype = (cups_ptype_t)atoi(value); } + else if (!_cups_strcasecmp(line, "KOctets")) + { + job->koctets = atoi(value); + } else if (!_cups_strcasecmp(line, "NumFiles")) { job->num_files = atoi(value); if (job->num_files < 0) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad NumFiles value %d on line %d.", - job->num_files, linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad NumFiles value %d on line %d of %s.", job->num_files, linenum, filename); job->num_files = 0; continue; } @@ -4117,14 +4309,13 @@ load_job_cache(const char *filename) /* I - job.cache filename */ if (sscanf(value, "%d%*[ \t]%15[^/]/%255s%d", &number, super, type, &compression) != 4) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File on line %d.", linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File on line %d of %s.", linenum, filename); continue; } if (number < 1 || number > job->num_files) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File number %d on line %d.", - number, linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File number %d on line %d of %s.", number, linenum, filename); continue; } @@ -4158,14 +4349,13 @@ load_job_cache(const char *filename) /* I - job.cache filename */ } } else - cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown %s directive on line %d.", - line, linenum); + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown %s directive on line %d of %s.", line, linenum, filename); } if (job) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Missing directive on line %d.", linenum); + "Missing directive on line %d of %s.", linenum, filename); cupsdDeleteJob(job, CUPSD_JOB_PURGE); } @@ -4375,6 +4565,7 @@ static void set_time(cupsd_job_t *job, /* I - Job to update */ const char *name) /* I - Name of attribute */ { + char date_name[128]; /* date-time-at-xxx */ ipp_attribute_t *attr; /* Time attribute */ time_t curtime; /* Current time */ @@ -4389,8 +4580,18 @@ set_time(cupsd_job_t *job, /* I - Job to update */ attr->values[0].integer = curtime; } + snprintf(date_name, sizeof(date_name), "date-%s", name); + + if ((attr = ippFindAttribute(job->attrs, date_name, IPP_TAG_ZERO)) != NULL) + { + attr->value_tag = IPP_TAG_DATE; + ippSetDate(job->attrs, &attr, 0, ippTimeToDate(curtime)); + } + if (!strcmp(name, "time-at-completed")) { + job->completed_time = curtime; + if (JobHistory < INT_MAX && attr) job->history_time = attr->values[0].integer + JobHistory; else @@ -4455,7 +4656,7 @@ start_job(cupsd_job_t *job, /* I - Job ID */ "job-printer-state-message", IPP_TAG_TEXT); if (job->printer_message) - cupsdSetString(&(job->printer_message->values[0].string.text), ""); + ippSetString(job->attrs, &job->printer_message, 0, ""); ippSetString(job->attrs, &job->reasons, 0, "job-printing"); cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL); @@ -4623,7 +4824,7 @@ stop_job(cupsd_job_t *job, /* I - Job */ FilterLevel -= job->cost; job->cost = 0; - if (action == CUPSD_JOB_DEFAULT && !job->kill_time) + if (action == CUPSD_JOB_DEFAULT && !job->kill_time && job->backend > 0) job->kill_time = time(NULL) + JobKillDelay; else if (action >= CUPSD_JOB_FORCE) job->kill_time = 0; @@ -4673,6 +4874,7 @@ unload_job(cupsd_job_t *job) /* I - Job */ job->attrs = NULL; job->state = NULL; job->reasons = NULL; + job->impressions = NULL; job->sheets = NULL; job->job_sheets = NULL; job->printer_message = NULL; @@ -4694,6 +4896,8 @@ update_job(cupsd_job_t *job) /* I - Job to check */ *ptr; /* Pointer update... */ int loglevel, /* Log level for message */ event = 0; /* Events? */ + cupsd_printer_t *printer = job->printer; + /* Printer */ static const char * const levels[] = /* Log levels */ { "NONE", @@ -4731,6 +4935,25 @@ update_job(cupsd_job_t *job) /* I - Job to check */ cupsdLogJob(job, CUPSD_LOG_DEBUG, "PAGE: %s", message); + if (job->impressions) + { + if (!_cups_strncasecmp(message, "total ", 6)) + { + /* + * Got a total count of pages from a backend or filter... + */ + + copies = atoi(message + 6); + copies -= ippGetInteger(job->impressions, 0); /* Just track the delta */ + } + else if (!sscanf(message, "%*d%d", &copies)) + copies = 1; + + ippSetInteger(job->attrs, &job->impressions, 0, ippGetInteger(job->impressions, 0) + copies); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); + } + if (job->sheets) { if (!_cups_strncasecmp(message, "total ", 6)) @@ -4740,12 +4963,14 @@ update_job(cupsd_job_t *job) /* I - Job to check */ */ copies = atoi(message + 6); - copies -= job->sheets->values[0].integer; /* Just track the delta */ + copies -= ippGetInteger(job->sheets, 0); /* Just track the delta */ } else if (!sscanf(message, "%*d%d", &copies)) copies = 1; - job->sheets->values[0].integer += copies; + ippSetInteger(job->attrs, &job->sheets, 0, ippGetInteger(job->sheets, 0) + copies); + job->dirty = 1; + cupsdMarkDirty(CUPSD_DIRTY_JOBS); if (job->printer->page_limit) cupsdUpdateQuota(job->printer, job->username, copies, 0); @@ -4754,8 +4979,7 @@ update_job(cupsd_job_t *job) /* I - Job to check */ cupsdLogPage(job, message); if (job->sheets) - cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, - "Printed %d page(s).", job->sheets->values[0].integer); + cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, "Printed %d page(s).", ippGetInteger(job->sheets, 0)); } else if (loglevel == CUPSD_LOG_JOBSTATE) { @@ -4766,7 +4990,10 @@ update_job(cupsd_job_t *job) /* I - Job to check */ cupsdLogJob(job, CUPSD_LOG_DEBUG, "JOBSTATE: %s", message); - ippSetString(job->attrs, &job->reasons, 0, message); + if (!strcmp(message, "cups-retry-as-raster")) + job->retry_as_raster = 1; + else + ippSetString(job->attrs, &job->reasons, 0, message); } else if (loglevel == CUPSD_LOG_STATE) { @@ -4963,7 +5190,7 @@ update_job(cupsd_job_t *job) /* I - Job to check */ ptr = message; if (*ptr) - cupsdLogJob(job, loglevel, "%s", ptr); + cupsdLogJob(job, loglevel == CUPSD_LOG_INFO ? CUPSD_LOG_DEBUG : loglevel, "%s", ptr); if (loglevel < CUPSD_LOG_DEBUG && strcmp(job->printer->state_message, ptr)) @@ -5044,10 +5271,11 @@ update_job(cupsd_job_t *job) /* I - Job to check */ finalize_job(job, 1); /* - * Check for new jobs... + * Try printing another job... */ - cupsdCheckJobs(); + if (printer->state != IPP_PRINTER_STOPPED) + cupsdCheckJobs(); } } @@ -5092,15 +5320,14 @@ update_job_attrs(cupsd_job_t *job, /* I - Job to update */ if (job->state_value != IPP_JOB_PROCESSING && job->status_level == CUPSD_LOG_INFO) { - cupsdSetString(&(job->printer_message->values[0].string.text), ""); + ippSetString(job->attrs, &job->printer_message, 0, ""); job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); } else if (job->printer->state_message[0] && do_message) { - cupsdSetString(&(job->printer_message->values[0].string.text), - job->printer->state_message); + ippSetString(job->attrs, &job->printer_message, 0, job->printer->state_message); job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); @@ -5165,8 +5392,3 @@ update_job_attrs(cupsd_job_t *job, /* I - Job to update */ job->dirty = 1; cupsdMarkDirty(CUPSD_DIRTY_JOBS); } - - -/* - * End of "$Id$". - */