/*
- * "$Id: job.c 7902 2008-09-03 14:20:17Z mike $"
+ * Job management routines for the CUPS scheduler.
*
- * Job management routines for the CUPS scheduler.
+ * Copyright 2007-2016 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
- * Copyright 2007-2012 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/".
- *
- * Contents:
- *
- * cupsdAddJob() - Add a new job to the job queue.
- * cupsdCancelJobs() - Cancel all jobs for the given
- * destination/user.
- * cupsdCheckJobs() - Check the pending jobs and start any if the
- * destination is available.
- * cupsdCleanJobs() - Clean out old jobs.
- * cupsdContinueJob() - Continue printing with the next file in a
- * job.
- * cupsdDeleteJob() - Free all memory used by a job.
- * cupsdFreeAllJobs() - Free all jobs from memory.
- * cupsdFindJob() - Find the specified job.
- * cupsdGetPrinterJobCount() - Get the number of pending, processing, or
- * held jobs in a printer or class.
- * cupsdGetUserJobCount() - Get the number of pending, processing, or
- * held jobs for a user.
- * cupsdLoadAllJobs() - Load all jobs from disk.
- * cupsdLoadJob() - Load a single job.
- * cupsdMoveJob() - Move the specified job to a different
- * destination.
- * cupsdReleaseJob() - Release the specified job.
- * cupsdRestartJob() - Restart the specified job.
- * cupsdSaveAllJobs() - Save a summary of all jobs to disk.
- * cupsdSaveJob() - Save a job to disk.
- * cupsdSetJobHoldUntil() - Set the hold time for a job.
- * cupsdSetJobPriority() - Set the priority of a job, moving it up/down
- * in the list as needed.
- * cupsdSetJobState() - Set the state of the specified print job.
- * cupsdStopAllJobs() - Stop all print jobs.
- * cupsdUnloadCompletedJobs() - Flush completed job history from memory.
- * cupsdUpdateJobs() - Update the history/file files for all jobs.
- * compare_active_jobs() - Compare the job IDs and priorities of two
- * jobs.
- * compare_jobs() - Compare the job IDs of two jobs.
- * dump_job_history() - Dump any debug messages for a job.
- * free_job_history() - Free any log history.
- * finalize_job() - Cleanup after job filter processes and
- * support data.
- * get_options() - Get a string containing the job options.
- * ipp_length() - Compute the size of the buffer needed to hold
- * the textual IPP attributes.
- * load_job_cache() - Load jobs from the job.cache file.
- * load_next_job_id() - Load the NextJobId value from the job.cache
- * file.
- * load_request_root() - Load jobs from the RequestRoot directory.
- * remove_job_files() - Remove the document files for a job.
- * remove_job_history() - Remove the control file for a job.
- * set_time() - Set one of the "time-at-xyz" attributes.
- * start_job() - Start a print job.
- * stop_job() - Stop a print job.
- * unload_job() - Unload a job from memory.
- * update_job() - Read a status update from a job's filters.
- * update_job_attrs() - Update the job-printer-* attributes.
+ * 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
+ * missing or damaged, see the license at "http://www.cups.org/".
*/
/*
*/
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);
"Job canceled by user.");
}
}
-
- cupsdCheckJobs();
}
*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;
if (job->kill_time && job->kill_time <= curtime)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Stopping unresponsive job.",
- job->id);
+ if (!job->completed)
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Stopping unresponsive job.");
stop_job(job, CUPSD_JOB_FORCE);
continue;
if (job->cancel_time && job->cancel_time <= curtime)
{
- cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
- "Canceling stuck job after %d seconds.", MaxJobTime);
+ int cancel_after; /* job-cancel-after value */
+
+ attr = ippFindAttribute(job->attrs, "job-cancel-after", IPP_TAG_INTEGER);
+ cancel_after = attr ? ippGetInteger(attr, 0) : MaxJobTime;
+
+ if (job->completed)
+ cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_FORCE, "Marking stuck job as completed after %d seconds.", cancel_after);
+ else
+ cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT, "Canceling stuck job after %d seconds.", cancel_after);
continue;
}
((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 &&
-#ifndef kIOPMAssertionTypeDenySystemSleep
- !Sleeping &&
-#endif /* !kIOPMAssertionTypeDenySystemSleep */
- !DoingShutdown && !job->printer)
+ (!Sleeping || ACPower) && !DoingShutdown && !job->printer)
{
printer = cupsdFindDest(job->dest);
pclass = NULL;
"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;
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);
* Start the job...
*/
+ cupsArraySave(ActiveJobs);
start_job(job, printer);
+ cupsArrayRestore(ActiveJobs);
}
}
}
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;
}
/* Pipes used between filters */
int envc; /* Number of environment variables */
struct stat fileinfo; /* Job file information */
+ int argc = 0; /* Number of arguments */
char **argv = NULL, /* Filter command-line arguments */
filename[1024], /* Job filename */
command[1024], /* Full path to command */
/* CONTENT_TYPE env variable */
device_uri[1024],
/* DEVICE_URI env variable */
- final_content_type[1024],
+ final_content_type[1024] = "",
/* FINAL_CONTENT_TYPE env variable */
lang[255], /* LANG env variable */
#ifdef __APPLE__
memset(job->filters, 0, sizeof(job->filters));
-
if (job->printer->raw)
{
/*
* 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],
- 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)
{
goto abort_job;
}
+ /*
+ * Figure out the final content type...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "%d filters for job:",
+ cupsArrayCount(filters));
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "%s (%s/%s to %s/%s, cost %d)",
+ filter->filter,
+ filter->src ? filter->src->super : "???",
+ filter->src ? filter->src->type : "???",
+ filter->dst ? filter->dst->super : "???",
+ filter->dst ? filter->dst->type : "???",
+ filter->cost);
+
+ if (!job->printer->remote)
+ {
+ for (filter = (mime_filter_t *)cupsArrayLast(filters);
+ filter && filter->dst;
+ filter = (mime_filter_t *)cupsArrayPrev(filters))
+ if (strcmp(filter->dst->super, "printer") ||
+ strcmp(filter->dst->type, job->printer->name))
+ break;
+
+ if (filter && filter->dst)
+ {
+ if ((ptr = strchr(filter->dst->type, '/')) != NULL)
+ snprintf(final_content_type, sizeof(final_content_type),
+ "FINAL_CONTENT_TYPE=%s", ptr + 1);
+ else
+ snprintf(final_content_type, sizeof(final_content_type),
+ "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super,
+ filter->dst->type);
+ }
+ else
+ snprintf(final_content_type, sizeof(final_content_type),
+ "FINAL_CONTENT_TYPE=printer/%s", job->printer->name);
+ }
+
/*
* Remove NULL ("-") filters...
*/
* Add decompression/raw filter as needed...
*/
- if ((!job->printer->raw && job->compressions[job->current_file]) ||
- (!filters && !job->printer->remote &&
- (job->num_files > 1 || !strncmp(job->printer->device_uri, "file:", 5))))
+ 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...
*/
if (job->printer->remote)
- argv = calloc(7 + job->num_files, sizeof(char *));
+ argc = 6 + job->num_files;
else
- argv = calloc(8, sizeof(char *));
+ argc = 7;
- if (!argv)
+ if ((argv = calloc((size_t)argc + 1, sizeof(char *))) == NULL)
{
cupsdLogMessage(CUPSD_LOG_DEBUG, "Unable to allocate argument array - %s",
strerror(errno));
{
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
job->id, job->current_file + 1);
- argv[6] = filename;
+ argv[6] = strdup(filename);
}
for (i = 0; argv[i]; i ++)
{
if (i)
*psrptr++ = ',';
- strlcpy(psrptr, job->printer->reasons[i],
- psrlen - (psrptr - printer_state_reasons));
+ strlcpy(psrptr, job->printer->reasons[i], psrlen - (size_t)(psrptr - printer_state_reasons));
psrptr += strlen(psrptr);
}
}
envp[envc ++] = banner_page ? "CUPS_FILETYPE=job-sheet" :
"CUPS_FILETYPE=document";
- if (!job->printer->remote && !job->printer->raw)
- {
- filter = (mime_filter_t *)cupsArrayLast(filters);
-
- if (job->printer->port_monitor)
- filter = (mime_filter_t *)cupsArrayPrev(filters);
-
- if (filter && filter->dst)
- {
- if ((ptr = strchr(filter->dst->type, '/')) != NULL)
- snprintf(final_content_type, sizeof(final_content_type),
- "FINAL_CONTENT_TYPE=%s", ptr + 1);
- else
- snprintf(final_content_type, sizeof(final_content_type),
- "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super,
- filter->dst->type);
- envp[envc ++] = final_content_type;
- }
- }
+ if (final_content_type[0])
+ envp[envc ++] = final_content_type;
if (Classification && !banner_page)
{
* Now create processes for all of the filters...
*/
- cupsdSetPrinterReasons(job->printer, "-cups-missing-filter-warning,"
- "cups-insecure-filter-warning");
-
for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters);
filter;
i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
cupsdLogJob(job, CUPSD_LOG_INFO, "Started filter %s (PID %d)", command,
pid);
- argv[6] = NULL;
- slot = !slot;
+ if (argv[6])
+ {
+ free(argv[6]);
+ argv[6] = NULL;
+ }
+
+ slot = !slot;
}
cupsArrayDelete(filters);
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;
pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
filterfds[slot][1], job->status_pipes[1],
job->back_pipes[1], job->side_pipes[1],
- backroot, job->profile, job, &(job->backend));
+ backroot, job->bprofile, job, &(job->backend));
if (pid == 0)
{
cupsdClosePipe(filterfds[slot]);
- if (job->printer->remote && job->num_files > 1)
- {
- for (i = 0; i < job->num_files; i ++)
- free(argv[i + 6]);
- }
+ for (i = 6; i < argc; i ++)
+ if (argv[i])
+ free(argv[i]);
free(argv);
+
if (printer_state_reasons)
free(printer_state_reasons);
if (argv)
{
- if (job->printer->remote && job->num_files > 1)
- {
- for (i = 0; i < job->num_files; i ++)
- free(argv[i + 6]);
- }
-
- free(argv);
+ for (i = 6; i < argc; i ++)
+ if (argv[i])
+ free(argv[i]);
}
if (printer_state_reasons)
}
+/*
+ * '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.
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? */
/*
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...
* Load job attributes...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Loading attributes...", job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading attributes...");
snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, job->id);
if ((fp = cupsdOpenConfFile(jobfile)) == NULL)
if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, job->attrs) != IPP_DATA)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Unable to read job control file \"%s\".", job->id,
- jobfile);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to read job control file \"%s\".", jobfile);
cupsFileClose(fp);
goto error;
}
if (!ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Missing or bad time-at-creation attribute in "
- "control file.", job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Missing or bad time-at-creation attribute in control file.");
goto error;
}
if ((job->state = ippFindAttribute(job->attrs, "job-state",
IPP_TAG_ENUM)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Missing or bad job-state attribute in control "
- "file.", job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Missing or bad job-state attribute in control file.");
goto error;
}
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
if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
IPP_TAG_URI)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] No job-printer-uri attribute in control file.",
- job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "No job-printer-uri attribute in control file.");
goto error;
}
if ((dest = cupsdValidateDest(attr->values[0].string.text, &(job->dtype),
&destptr)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Unable to queue job for destination \"%s\".",
- job->id, attr->values[0].string.text);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to queue job for destination \"%s\".",
+ attr->values[0].string.text);
goto error;
}
}
else if ((destptr = cupsdFindDest(job->dest)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Unable to queue job for destination \"%s\".",
- job->id, job->dest);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to queue job for destination \"%s\".",
+ job->dest);
goto error;
}
{
const char *reason; /* job-state-reason keyword */
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Job %d] Adding missing job-state-reasons attribute to "
- " control file.", job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Adding missing job-state-reasons attribute to control file.");
switch (job->state_value)
{
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)
{
if ((attr = ippFindAttribute(job->attrs, "job-priority",
IPP_TAG_INTEGER)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Missing or bad job-priority attribute in "
- "control file.", job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Missing or bad job-priority attribute in control file.");
goto error;
}
if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name",
IPP_TAG_NAME)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Missing or bad job-originating-user-name "
- "attribute in control file.", job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Missing or bad job-originating-user-name "
+ "attribute in control file.");
goto error;
}
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...
*/
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)
{
/*
if (access(jobfile, 0))
break;
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Job %d] Auto-typing document file \"%s\"...", job->id,
- jobfile);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Auto-typing document file \"%s\"...", jobfile);
if (fileid > job->num_files)
{
if (job->num_files == 0)
{
- compressions = (int *)calloc(fileid, sizeof(int));
- filetypes = (mime_type_t **)calloc(fileid, sizeof(mime_type_t *));
+ compressions = (int *)calloc((size_t)fileid, sizeof(int));
+ filetypes = (mime_type_t **)calloc((size_t)fileid, sizeof(mime_type_t *));
}
else
{
- compressions = (int *)realloc(job->compressions,
- sizeof(int) * fileid);
- filetypes = (mime_type_t **)realloc(job->filetypes,
- sizeof(mime_type_t *) *
- fileid);
+ compressions = (int *)realloc(job->compressions, sizeof(int) * (size_t)fileid);
+ filetypes = (mime_type_t **)realloc(job->filetypes, sizeof(mime_type_t *) * (size_t)fileid);
}
+ if (compressions)
+ job->compressions = compressions;
+
+ if (filetypes)
+ job->filetypes = filetypes;
+
if (!compressions || !filetypes)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Ran out of memory for job file types.",
- job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Ran out of memory for job file types.");
ippDelete(job->attrs);
job->attrs = NULL;
- if (compressions)
- free(compressions);
-
- if (filetypes)
- free(filetypes);
-
if (job->compressions)
{
free(job->compressions);
return (0);
}
- job->compressions = compressions;
- job->filetypes = filetypes;
- job->num_files = fileid;
+ job->num_files = fileid;
}
job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, jobfile, NULL,
if (cupsFileGets(fp, line, sizeof(line)) &&
- !strcmp(line, "CUPSD-AUTH-V2"))
+ !strcmp(line, "CUPSD-AUTH-V3"))
{
i = 0;
while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
* Decode value...
*/
- bytes = sizeof(data);
- httpDecode64_2(data, &bytes, value);
+ if (strcmp(line, "negotiate") && strcmp(line, "uid"))
+ {
+ bytes = sizeof(data);
+ httpDecode64_2(data, &bytes, value);
+ }
/*
* Assign environment variables...
else if (!strcmp(line, "password"))
cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s", data);
else if (!strcmp(line, "negotiate"))
- cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", data);
+ cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", value);
else
continue;
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,
job;
job = (cupsd_job_t *)cupsArrayNext(Jobs))
{
+ if (job->printer && job->printer->temporary)
+ {
+ /*
+ * Don't save jobs on temporary printers...
+ */
+
+ continue;
+ }
+
cupsFilePrintf(fp, "<Job %d>\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,
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)
if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
job->attrs) != IPP_DATA)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Unable to write job control file.", job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to write job control file.");
cupsFileClose(fp);
return;
}
if (!cupsdCloseCreatedConfFile(fp, filename))
+ {
+ /*
+ * Remove backup file and mark this job as clean...
+ */
+
+ strlcat(filename, ".O", sizeof(filename));
+ unlink(filename);
+
job->dirty = 0;
+ }
}
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);
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...
*/
* Set the new job state...
*/
- job->state->values[0].integer = newstate;
- job->state_value = newstate;
+ job->state_value = newstate;
+
+ if (job->state)
+ job->state->values[0].integer = newstate;
switch (newstate)
{
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 :
job;
job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
{
- if (kill_delay)
- job->kill_time = time(NULL) + kill_delay;
+ if (job->completed)
+ {
+ cupsdSetJobState(job, IPP_JOB_COMPLETED, CUPSD_JOB_FORCE, NULL);
+ }
+ else
+ {
+ if (kill_delay)
+ job->kill_time = time(NULL) + kill_delay;
- cupsdSetJobState(job, IPP_JOB_PENDING, action, NULL);
+ cupsdSetJobState(job, IPP_JOB_PENDING, action, NULL);
+ }
}
}
if (job->dirty)
cupsdSaveJob(job);
- unload_job(job);
+ if (!job->dirty)
+ unload_job(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.
*/
snprintf(temp, sizeof(temp), "[Job %d] printer-state-reasons=", job->id);
ptr = temp + strlen(temp);
if (printer->num_reasons == 0)
- strlcpy(ptr, "none", sizeof(temp) - (ptr - temp));
+ strlcpy(ptr, "none", sizeof(temp) - (size_t)(ptr - temp));
else
{
for (i = 0;
if (i)
*ptr++ = ',';
- strlcpy(ptr, printer->reasons[i], sizeof(temp) - (ptr - temp));
+ strlcpy(ptr, printer->reasons[i], sizeof(temp) - (size_t)(ptr - temp));
ptr += strlen(ptr);
}
}
cupsdLogMessage(CUPSD_LOG_DEBUG2, "finalize_job(job=%p(%d))", job, job->id);
/*
- * Clear the "connecting-to-device" reason, which is only valid when a printer
- * is processing, along with any remote printing job state...
+ * Clear the "connecting-to-device" and "cups-waiting-for-job-completed"
+ * reasons, which are only valid when a printer is processing, along with any
+ * remote printing job state...
*/
cupsdSetPrinterReasons(job->printer, "-connecting-to-device,"
+ "cups-waiting-for-job-completed,"
"cups-remote-pending,"
"cups-remote-pending-held,"
"cups-remote-processing,"
* rarely have current information for network devices...
*/
- if (strncmp(job->printer->device_uri, "usb:", 4))
+ if (strncmp(job->printer->device_uri, "usb:", 4) &&
+ strncmp(job->printer->device_uri, "ippusb:", 7))
cupsdSetPrinterReasons(job->printer, "-offline-report");
/*
cupsdDestroyProfile(job->profile);
job->profile = NULL;
+ cupsdDestroyProfile(job->bprofile);
+ job->bprofile = NULL;
/*
- * Clear the unresponsive job watchdog timer...
+ * Clear the unresponsive job watchdog timers...
*/
- job->kill_time = 0;
+ job->cancel_time = 0;
+ job->kill_time = 0;
/*
* Close pipes and status buffer...
job_state = IPP_JOB_COMPLETED;
message = "Job completed.";
- ippSetString(job->attrs, &job->reasons, 0,
- "job-completed-successfully");
+ if (!job->status)
+ ippSetString(job->attrs, &job->reasons, 0,
+ "job-completed-successfully");
break;
case IPP_JOB_STOPPED :
/*
* 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...
*/
exit_code == CUPS_BACKEND_HOLD ? "hold job" :
exit_code == CUPS_BACKEND_STOP ? "stop printer" :
exit_code == CUPS_BACKEND_CANCEL ? "cancel job" :
+ exit_code == CUPS_BACKEND_RETRY ? "retry job later" :
+ exit_code == CUPS_BACKEND_RETRY_CURRENT ? "retry job immediately" :
exit_code < 0 ? "crashed" : "unknown");
/*
* Hold the job...
*/
- cupsdSetJobHoldUntil(job, "indefinite", 1);
- ippSetString(job->attrs, &job->reasons, 0,
- "job-hold-until-specified");
+ const char *reason = ippGetString(job->reasons, 0, NULL);
- job_state = IPP_JOB_HELD;
- message = "Job held indefinitely due to backend errors; please "
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-state-reasons=\"%s\"",
+ reason);
+
+ if (!reason || strncmp(reason, "account-", 8))
+ {
+ cupsdSetJobHoldUntil(job, "indefinite", 1);
+
+ ippSetString(job->attrs, &job->reasons, 0,
+ "job-hold-until-specified");
+ message = "Job held indefinitely due to backend errors; please "
"consult the error_log file for details.";
+ }
+ else if (!strcmp(reason, "account-info-needed"))
+ {
+ cupsdSetJobHoldUntil(job, "indefinite", 0);
+
+ message = "Job held indefinitely - account information is "
+ "required.";
+ }
+ else if (!strcmp(reason, "account-closed"))
+ {
+ cupsdSetJobHoldUntil(job, "indefinite", 0);
+
+ message = "Job held indefinitely - account has been closed.";
+ }
+ else if (!strcmp(reason, "account-limit-reached"))
+ {
+ cupsdSetJobHoldUntil(job, "indefinite", 0);
+
+ message = "Job held indefinitely - account limit has been "
+ "reached.";
+ }
+ else
+ {
+ cupsdSetJobHoldUntil(job, "indefinite", 0);
+
+ message = "Job held indefinitely - account authorization failed.";
+ }
+
+ job_state = IPP_JOB_HELD;
}
break;
job_state = IPP_JOB_HELD;
message = "Job held for authentication.";
- ippSetString(job->attrs, &job->reasons, 0,
- "cups-held-for-authentication");
+ if (strncmp(job->reasons->values[0].string.text, "account-", 8))
+ ippSetString(job->attrs, &job->reasons, 0,
+ "cups-held-for-authentication");
}
break;
cupsArrayRemove(PrintingJobs, job);
+ /*
+ * Clear informational messages...
+ */
+
+ if (job->status_level > CUPSD_LOG_ERROR)
+ job->printer->state_message[0] = '\0';
+
/*
* Apply any PPD updates...
*/
job->printer->job = NULL;
job->printer = NULL;
-
- /*
- * Try printing another job...
- */
-
- if (printer_state != IPP_PRINTER_STOPPED)
- cupsdCheckJobs();
}
attr->value_tag == IPP_TAG_MIMETYPE ||
attr->value_tag == IPP_TAG_NAMELANG ||
attr->value_tag == IPP_TAG_TEXTLANG ||
- (attr->value_tag == IPP_TAG_URI && strcmp(attr->name, "job-uuid")) ||
+ (attr->value_tag == IPP_TAG_URI && strcmp(attr->name, "job-uuid") &&
+ strcmp(attr->name, "job-authorization-uri")) ||
attr->value_tag == IPP_TAG_URISCHEME ||
attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */
continue;
if (!strncmp(attr->name, "job-", 4) &&
strcmp(attr->name, "job-account-id") &&
strcmp(attr->name, "job-accounting-user-id") &&
+ strcmp(attr->name, "job-authorization-uri") &&
strcmp(attr->name, "job-billing") &&
strcmp(attr->name, "job-impressions") &&
strcmp(attr->name, "job-originating-host-name") &&
strcmp(attr->name, "job-password") &&
+ strcmp(attr->name, "job-password-encryption") &&
strcmp(attr->name, "job-uuid") &&
!(job->printer->type & CUPS_PRINTER_REMOTE))
continue;
*/
if (optptr > options)
- strlcat(optptr, " ", optlength - (optptr - options));
+ strlcat(optptr, " ", optlength - (size_t)(optptr - options));
if (attr->value_tag != IPP_TAG_BOOLEAN)
{
- strlcat(optptr, attr->name, optlength - (optptr - options));
- strlcat(optptr, "=", optlength - (optptr - options));
+ strlcat(optptr, attr->name, optlength - (size_t)(optptr - options));
+ strlcat(optptr, "=", optlength - (size_t)(optptr - options));
}
for (i = 0; i < attr->num_values; i ++)
{
if (i)
- strlcat(optptr, ",", optlength - (optptr - options));
+ strlcat(optptr, ",", optlength - (size_t)(optptr - options));
optptr += strlen(optptr);
{
case IPP_TAG_INTEGER :
case IPP_TAG_ENUM :
- snprintf(optptr, optlength - (optptr - options),
+ snprintf(optptr, optlength - (size_t)(optptr - options),
"%d", attr->values[i].integer);
break;
case IPP_TAG_BOOLEAN :
if (!attr->values[i].boolean)
- strlcat(optptr, "no", optlength - (optptr - options));
+ strlcat(optptr, "no", optlength - (size_t)(optptr - options));
- strlcat(optptr, attr->name,
- optlength - (optptr - options));
+ strlcat(optptr, attr->name, optlength - (size_t)(optptr - options));
break;
case IPP_TAG_RANGE :
if (attr->values[i].range.lower == attr->values[i].range.upper)
- snprintf(optptr, optlength - (optptr - options) - 1,
+ snprintf(optptr, optlength - (size_t)(optptr - options) - 1,
"%d", attr->values[i].range.lower);
else
- snprintf(optptr, optlength - (optptr - options) - 1,
+ snprintf(optptr, optlength - (size_t)(optptr - options) - 1,
"%d-%d", attr->values[i].range.lower,
attr->values[i].range.upper);
break;
case IPP_TAG_RESOLUTION :
- snprintf(optptr, optlength - (optptr - options) - 1,
+ snprintf(optptr, optlength - (size_t)(optptr - options) - 1,
"%dx%d%s", attr->values[i].resolution.xres,
attr->values[i].resolution.yres,
attr->values[i].resolution.units == IPP_RES_PER_INCH ?
for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
{
*optptr++ = ' ';
- strlcpy(optptr, pwgppd->name, optlength - (optptr - options));
+ strlcpy(optptr, pwgppd->name, optlength - (size_t)(optptr - options));
optptr += strlen(optptr);
*optptr++ = '=';
- strlcpy(optptr, pwgppd->value, optlength - (optptr - options));
+ strlcpy(optptr, pwgppd->value, optlength - (size_t)(optptr - options));
optptr += strlen(optptr);
}
*/
bytes ++; /* " " separator */
- bytes += attr->num_values; /* "," separators */
+ bytes += (size_t)attr->num_values; /* "," separators */
/*
* Boolean attributes appear as "foo,nofoo,foo,nofoo", while
if (attr->value_tag != IPP_TAG_BOOLEAN)
bytes += strlen(attr->name);
else
- bytes += attr->num_values * strlen(attr->name);
+ bytes += (size_t)attr->num_values * strlen(attr->name);
/*
* Now add the size required for each value in the attribute...
* Minimum value of a signed integer is -2147483647, or 11 digits.
*/
- bytes += attr->num_values * 11;
+ bytes += (size_t)attr->num_values * 11;
break;
case IPP_TAG_BOOLEAN :
* 23 characters max.
*/
- bytes += attr->num_values * 23;
+ bytes += (size_t)attr->num_values * 23;
break;
case IPP_TAG_RESOLUTION :
* suffixed by the units, or 26 characters max.
*/
- bytes += attr->num_values * 26;
+ bytes += (size_t)attr->num_values * 26;
break;
case IPP_TAG_STRING :
{
if (job)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Missing </Job> directive on line %d.",
- linenum);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Missing </Job> 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;
}
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;
}
{
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;
}
}
job->status_pipes[0] = -1;
job->status_pipes[1] = -1;
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Loading from cache...",
- job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading from cache...");
}
else if (!job)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
- "Missing <Job #> directive on line %d.", linenum);
+ "Missing <Job #> directive on line %d of %s.", linenum, filename);
continue;
}
else if (!_cups_strcasecmp(line, "</Job>"))
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"))
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"))
{
{
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;
}
job->id);
if (access(jobfile, 0))
{
- cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Data files have gone away.",
- job->id);
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Data files have gone away.");
job->num_files = 0;
continue;
}
- job->filetypes = calloc(job->num_files, sizeof(mime_type_t *));
- job->compressions = calloc(job->num_files, sizeof(int));
+ job->filetypes = calloc((size_t)job->num_files, sizeof(mime_type_t *));
+ job->compressions = calloc((size_t)job->num_files, sizeof(int));
if (!job->filetypes || !job->compressions)
{
- cupsdLogMessage(CUPSD_LOG_EMERG,
- "[Job %d] Unable to allocate memory for %d files.",
- job->id, job->num_files);
+ cupsdLogJob(job, CUPSD_LOG_EMERG,
+ "Unable to allocate memory for %d files.",
+ job->num_files);
break;
}
}
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;
}
* If the original MIME type is unknown, auto-type it!
*/
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "[Job %d] Unknown MIME type %s/%s for file %d.",
- job->id, super, type, number + 1);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unknown MIME type %s/%s for file %d.",
+ super, type, number + 1);
snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot,
job->id, number + 1);
}
}
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 </Job> directive on line %d of %s.", linenum, filename);
+ cupsdDeleteJob(job, CUPSD_JOB_PURGE);
}
cupsFileClose(fp);
else
unload_job(job);
}
+ else
+ free(job);
}
cupsDirClose(dir);
{
snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
job->id, i);
- if (Classification)
- cupsdRemoveFile(filename);
- else
- unlink(filename);
+ cupsdUnlinkOrRemoveFile(filename);
}
free(job->filetypes);
snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot,
job->id);
- if (Classification)
- cupsdRemoveFile(filename);
- else
- unlink(filename);
+ cupsdUnlinkOrRemoveFile(filename);
LastEvent |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
}
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 */
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"))
{
- if (JobHistory < INT_MAX)
+ job->completed_time = curtime;
+
+ if (JobHistory < INT_MAX && attr)
job->history_time = attr->values[0].integer + JobHistory;
else
job->history_time = INT_MAX;
if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
JobHistoryUpdate = job->history_time;
- if (JobFiles < INT_MAX)
+ if (JobFiles < INT_MAX && attr)
job->file_time = attr->values[0].integer + JobFiles;
else
job->file_time = INT_MAX;
start_job(cupsd_job_t *job, /* I - Job ID */
cupsd_printer_t *printer) /* I - Printer to print job */
{
+ const char *filename; /* Support filename */
+ ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
+ "job-cancel-after",
+ IPP_TAG_INTEGER);
+ /* job-cancel-after attribute */
+
+
cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job(job=%p(%d), printer=%p(%s))",
job, job->id, printer, printer->name);
"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);
job->printer = printer;
printer->job = job;
- if (MaxJobTime > 0)
+ if (cancel_after)
+ job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
+ else if (MaxJobTime > 0)
job->cancel_time = time(NULL) + MaxJobTime;
else
job->cancel_time = 0;
+ /*
+ * Check for support files...
+ */
+
+ cupsdSetPrinterReasons(job->printer, "-cups-missing-filter-warning,"
+ "cups-insecure-filter-warning");
+
+ if (printer->pc)
+ {
+ for (filename = (const char *)cupsArrayFirst(printer->pc->support_files);
+ filename;
+ filename = (const char *)cupsArrayNext(printer->pc->support_files))
+ {
+ if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_FILE, !RunUser,
+ cupsdLogFCMessage, printer))
+ break;
+ }
+ }
+
/*
* Setup the last exit status and security profiles...
*/
- job->status = 0;
- job->profile = cupsdCreateProfile(job->id);
+ job->status = 0;
+ job->profile = cupsdCreateProfile(job->id, 0);
+ job->bprofile = cupsdCreateProfile(job->id, 1);
/*
* Create the status pipes and buffer...
cupsdDestroyProfile(job->profile);
job->profile = NULL;
+ cupsdDestroyProfile(job->bprofile);
+ job->bprofile = NULL;
return;
}
cupsdDestroyProfile(job->profile);
job->profile = NULL;
+ cupsdDestroyProfile(job->bprofile);
+ job->bprofile = NULL;
return;
}
cupsdDestroyProfile(job->profile);
job->profile = NULL;
+ cupsdDestroyProfile(job->bprofile);
+ job->bprofile = NULL;
return;
}
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;
if (!job->attrs)
return;
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Unloading...", job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Unloading...");
ippDelete(job->attrs);
job->attrs = NULL;
job->state = NULL;
job->reasons = NULL;
+ job->impressions = NULL;
job->sheets = NULL;
job->job_sheets = NULL;
job->printer_message = NULL;
*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",
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))
*/
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);
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)
+ {
+ /*
+ * Support "keyword" to set job-state-reasons to the specified keyword.
+ * This is sufficient for the current paid printing stuff.
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "JOBSTATE: %s", 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)
{
cupsdStopPrinter(job->printer, 1);
return;
}
- else if (cupsdSetPrinterReasons(job->printer, message))
+ else if (message[0] && cupsdSetPrinterReasons(job->printer, message))
{
event |= CUPSD_EVENT_PRINTER_STATE;
- if (MaxJobTime > 0 && strstr(message, "connecting-to-device") != NULL)
+ if (MaxJobTime > 0)
{
/*
* Reset cancel time after connecting to the device...
break;
if (i >= job->printer->num_reasons)
- job->cancel_time = time(NULL) + MaxJobTime;
+ {
+ ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
+ "job-cancel-after",
+ IPP_TAG_INTEGER);
+ /* job-cancel-after attribute */
+
+ if (cancel_after)
+ job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
+ else
+ job->cancel_time = time(NULL) + MaxJobTime;
+ }
}
}
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))
finalize_job(job, 1);
/*
- * Check for new jobs...
+ * Try printing another job...
*/
- cupsdCheckJobs();
+ if (printer->state != IPP_PRINTER_STOPPED)
+ cupsdCheckJobs();
}
}
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);
job->dirty = 1;
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
-
-
-/*
- * End of "$Id: job.c 7902 2008-09-03 14:20:17Z mike $".
- */