/*
- * "$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-2017 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.
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more information.
*/
/*
*/
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);
}
}
}
else if (job->file_time && job->file_time <= curtime)
{
cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing document files.");
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "curtime=%ld, job->file_time=%ld", (long)curtime, (long)job->file_time);
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 */
* 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)
{
"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);
}
/*
* 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);
}
}
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
else
job->file_time = INT_MAX;
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "cupsdLoadJob: job->file_time=%ld, time-at-completed=%ld, JobFiles=%d", (long)job->file_time, (long)attr->values[0].integer, JobFiles);
+
if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
JobHistoryUpdate = job->file_time;
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)
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 ((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;
}
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...
*/
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 :
* Update the server "busy" state...
*/
- cupsdSetBusyState();
+ cupsdSetBusyState(0);
}
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);
}
}
else
job->file_time = INT_MAX;
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "cupsdUpdateJobs: job->file_time=%ld, time-at-completed=%ld, JobFiles=%d", (long)job->file_time, (long)attr->values[0].integer, JobFiles);
+
if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
JobHistoryUpdate = job->file_time;
}
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdUpdateAllJobs: JobHistoryUpdate=%ld",
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdUpdateJobs: JobHistoryUpdate=%ld",
(long)JobHistoryUpdate);
}
}
+/*
+ * '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,"
cupsdDestroyProfile(job->profile);
job->profile = NULL;
+ cupsdDestroyProfile(job->bprofile);
+ job->bprofile = NULL;
/*
* Clear the unresponsive job watchdog timers...
/*
* 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...
*/
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();
}
pwgppds = NULL;
if (pc &&
- !ippFindAttribute(job->attrs,
- "com.apple.print.DocumentTicket.PMSpoolFormat",
- IPP_TAG_ZERO) &&
+ !ippFindAttribute(job->attrs, "com.apple.print.DocumentTicket.PMSpoolFormat", IPP_TAG_ZERO) &&
!ippFindAttribute(job->attrs, "APPrinterPreset", IPP_TAG_ZERO) &&
- (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) ||
- ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO)))
+ (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_ZERO)))
{
/*
* Map print-color-mode and print-quality to a preset...
else
print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
- if ((attr = ippFindAttribute(job->attrs, "print-quality",
- IPP_TAG_ENUM)) != NULL &&
- attr->values[0].integer >= IPP_QUALITY_DRAFT &&
- attr->values[0].integer <= IPP_QUALITY_HIGH)
- print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT;
+ if ((attr = ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM)) != NULL)
+ {
+ ipp_quality_t pq = (ipp_quality_t)ippGetInteger(attr, 0);
+
+ if (pq >= IPP_QUALITY_DRAFT && pq <= IPP_QUALITY_HIGH)
+ print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT;
+ else
+ print_quality = _PWG_PRINT_QUALITY_NORMAL;
+ }
+ else if ((attr = ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_NAME)) != NULL)
+ {
+ const char *pq = ippGetString(attr, 0, NULL);
+
+ if (!_cups_strcasecmp(pq, "draft"))
+ print_quality = _PWG_PRINT_QUALITY_DRAFT;
+ else if (!_cups_strcasecmp(pq, "high"))
+ print_quality = _PWG_PRINT_QUALITY_HIGH;
+ else
+ print_quality = _PWG_PRINT_QUALITY_NORMAL;
+
+ if (!ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping cupsPrintQuality=%s to print-quality=%d", pq, print_quality + IPP_QUALITY_DRAFT);
+ num_pwgppds = cupsAddIntegerOption("print-quality", print_quality + IPP_QUALITY_DRAFT, num_pwgppds, &pwgppds);
+ }
+ }
else
+ {
print_quality = _PWG_PRINT_QUALITY_NORMAL;
+ }
if (pc->num_presets[print_color_mode][print_quality] == 0)
{
i --, preset ++)
{
if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO))
- num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds,
- &pwgppds);
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding preset option %s=%s", preset->name, preset->value);
+
+ num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds, &pwgppds);
+ }
}
}
}
if (pc)
{
+ if ((attr = ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM)) != NULL)
+ {
+ int pq = ippGetInteger(attr, 0);
+ static const char * const pqs[] = { "Draft", "Normal", "High" };
+
+ if (pq >= IPP_QUALITY_DRAFT && pq <= IPP_QUALITY_HIGH)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping print-quality=%d to cupsPrintQuality=%s", pq, pqs[pq - IPP_QUALITY_DRAFT]);
+
+ num_pwgppds = cupsAddOption("cupsPrintQuality", pqs[pq - IPP_QUALITY_DRAFT], num_pwgppds, &pwgppds);
+ }
+ }
+
if (!ippFindAttribute(job->attrs, "InputSlot", IPP_TAG_ZERO) &&
!ippFindAttribute(job->attrs, "HPPaperSource", IPP_TAG_ZERO))
{
}
if (!ippFindAttribute(job->attrs, "MediaType", IPP_TAG_ZERO) &&
(ppd = _ppdCacheGetMediaType(pc, job->attrs, NULL)) != NULL)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping media to MediaType=%s", ppd);
+
num_pwgppds = cupsAddOption("MediaType", ppd, num_pwgppds, &pwgppds);
+ }
if (!ippFindAttribute(job->attrs, "PageRegion", IPP_TAG_ZERO) &&
!ippFindAttribute(job->attrs, "PageSize", IPP_TAG_ZERO) &&
(ppd = _ppdCacheGetPageSize(pc, job->attrs, NULL, &exact)) != NULL)
{
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping media to Pagesize=%s", ppd);
+
num_pwgppds = cupsAddOption("PageSize", ppd, num_pwgppds, &pwgppds);
if (!ippFindAttribute(job->attrs, "media", IPP_TAG_ZERO))
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding media=%s", ppd);
+
num_pwgppds = cupsAddOption("media", ppd, num_pwgppds, &pwgppds);
+ }
}
if (!ippFindAttribute(job->attrs, "OutputBin", IPP_TAG_ZERO) &&
* Map output-bin to OutputBin option...
*/
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping output-bin to OutputBin=%s", ppd);
+
num_pwgppds = cupsAddOption("OutputBin", ppd, num_pwgppds, &pwgppds);
}
*/
if (!strcmp(attr->values[0].string.text, "one-sided"))
- num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_1sided,
- num_pwgppds, &pwgppds);
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_1sided);
+
+ num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_1sided, num_pwgppds, &pwgppds);
+ }
else if (!strcmp(attr->values[0].string.text, "two-sided-long-edge"))
- num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_long,
- num_pwgppds, &pwgppds);
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_2sided_long);
+
+ num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_long, num_pwgppds, &pwgppds);
+ }
else if (!strcmp(attr->values[0].string.text, "two-sided-short-edge"))
- num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_short,
- num_pwgppds, &pwgppds);
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_2sided_short);
+
+ num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_short, num_pwgppds, &pwgppds);
+ }
}
/*
* Map finishings values...
*/
- num_pwgppds = _ppdCacheGetFinishingOptions(pc, job->attrs,
- IPP_FINISHINGS_NONE, num_pwgppds,
- &pwgppds);
+ num_pwgppds = _ppdCacheGetFinishingOptions(pc, job->attrs, IPP_FINISHINGS_NONE, num_pwgppds, &pwgppds);
+
+ for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "After mapping finishings %s=%s", pwgppd->name, pwgppd->value);
}
/*
*/
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.", linenum);
+ "Missing </Job> directive on line %d of %s.", linenum, filename);
cupsdDeleteJob(job, CUPSD_JOB_PURGE);
}
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"))
{
+ job->completed_time = curtime;
+
if (JobHistory < INT_MAX && attr)
job->history_time = attr->values[0].integer + JobHistory;
else
JobHistoryUpdate = job->history_time;
if (JobFiles < INT_MAX && attr)
- job->file_time = attr->values[0].integer + JobFiles;
+ job->file_time = curtime + JobFiles;
else
job->file_time = INT_MAX;
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-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;
* 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)
{
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)
{
{
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 $".
- */