*
* Job management routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 2007-2009 by Apple Inc.
+ * Copyright 2007-2010 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
static int compare_active_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);
+static void finalize_job(cupsd_job_t *job, int set_job_state);
static void free_job_history(cupsd_job_t *job);
static char *get_options(cupsd_job_t *job, int banner_page, char *copies,
size_t copies_size, char *title,
if (purge)
cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_PURGE,
"Job purged by user.");
- else
+ else if (job->state_value < IPP_JOB_CANCELED)
cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
"Job canceled by user.");
}
cupsd_job_t *job; /* Current job */
- if (MaxJobs <= 0)
+ if (MaxJobs <= 0 && JobHistory)
return;
for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
- job && cupsArrayCount(Jobs) >= MaxJobs;
+ job && (cupsArrayCount(Jobs) >= MaxJobs || !JobHistory);
job = (cupsd_job_t *)cupsArrayNext(Jobs))
if (job->state_value >= IPP_JOB_CANCELED && !job->printer)
cupsdDeleteJob(job, CUPSD_JOB_PURGE);
cupsd_jobaction_t action)/* I - Action */
{
if (job->printer)
- finalize_job(job);
+ finalize_job(job, 1);
if (action == CUPSD_JOB_PURGE)
{
cupsdLogMessage(CUPSD_LOG_ERROR,
"[Job %d] Ran out of memory for job file types!",
job->id);
- return (1);
+
+ ippDelete(job->attrs);
+ job->attrs = NULL;
+
+ if (compressions)
+ free(compressions);
+
+ if (filetypes)
+ free(filetypes);
+
+ if (job->compressions)
+ {
+ free(job->compressions);
+ job->compressions = NULL;
+ }
+
+ if (job->filetypes)
+ {
+ free(job->filetypes);
+ job->filetypes = NULL;
+ }
+
+ job->num_files = 0;
+ return (0);
}
job->compressions = compressions;
ippDelete(job->attrs);
job->attrs = NULL;
+
+ if (job->compressions)
+ {
+ free(job->compressions);
+ job->compressions = NULL;
+ }
+
+ if (job->filetypes)
+ {
+ free(job->filetypes);
+ job->filetypes = NULL;
+ }
+
+ job->num_files = 0;
+
unlink(jobfile);
return (0);
if (!cupsdLoadJob(job))
return;
- /*
- * Don't do anything if the state is unchanged...
- */
+ /*
+ * Don't do anything if the state is unchanged and we aren't purging the
+ * job...
+ */
- if (newstate == (oldstate = job->state_value))
- return;
+ oldstate = job->state_value;
+ if (newstate == oldstate && action != CUPSD_JOB_PURGE)
+ return;
/*
* Stop any processes that are working on the current job...
*/
if (oldstate == IPP_JOB_PROCESSING)
- stop_job(job, action != CUPSD_JOB_DEFAULT);
+ stop_job(job, action);
/*
* Set the new job state...
case IPP_JOB_ABORTED :
case IPP_JOB_CANCELED :
case IPP_JOB_COMPLETED :
- /*
- * Expire job subscriptions since the job is now "completed"...
- */
+ if (newstate == IPP_JOB_CANCELED)
+ {
+ /*
+ * Remove the job from the active list if there are no processes still
+ * running for it...
+ */
- cupsdExpireSubscriptions(NULL, job);
+ for (i = 0; job->filters[i] < 0; i++);
+
+ if (!job->filters[i] && job->backend <= 0)
+ cupsArrayRemove(ActiveJobs, job);
+ }
+ else
+ {
+ /*
+ * Otherwise just remove the job from the active list immediately...
+ */
+
+ cupsArrayRemove(ActiveJobs, job);
+ }
/*
- * Remove the job from the active list...
+ * Expire job subscriptions since the job is now "completed"...
*/
- cupsArrayRemove(ActiveJobs, job);
+ cupsdExpireSubscriptions(NULL, job);
#ifdef __APPLE__
/*
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
else if (!job->printer)
+ {
+ /*
+ * Delete the job immediately if not actively printing...
+ */
+
cupsdDeleteJob(job, CUPSD_JOB_PURGE);
+ job = NULL;
+ }
break;
}
* Finalize the job immediately if we forced things...
*/
- if (action == CUPSD_JOB_FORCE)
- finalize_job(job);
+ if (action >= CUPSD_JOB_FORCE && job && job->printer)
+ finalize_job(job, 0);
/*
* Update the server "busy" state...
*/
static void
-finalize_job(cupsd_job_t *job) /* I - Job */
+finalize_job(cupsd_job_t *job, /* I - Job */
+ int set_job_state) /* I - 1 = set the job state */
{
ipp_pstate_t printer_state; /* New printer state value */
ipp_jstate_t job_state; /* New job state value */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "finalize_job(job=%p(%d))", job, job->id);
/*
- * Clear the "connecting-to-device" and "com.apple.print.recoverable-warning"
- * reasons, which are only valid when a printer is processing...
+ * Clear the "connecting-to-device" reason, which is only valid when a printer
+ * is processing...
*/
cupsdSetPrinterReasons(job->printer, "-connecting-to-device");
- cupsdSetPrinterReasons(job->printer, "-com.apple.print.recoverable-warning");
/*
* Similarly, clear the "offline-report" reason for non-USB devices since we
* Update the printer and job state.
*/
- cupsdSetJobState(job, job_state, CUPSD_JOB_DEFAULT, "%s", message);
+ if (job_state != job->state_value)
+ cupsdSetJobState(job, job_state, CUPSD_JOB_DEFAULT, "%s", message);
+
cupsdSetPrinterState(job->printer, printer_state,
printer_state == IPP_PRINTER_STOPPED);
update_job_attrs(job, 0);
attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */
continue;
- if (!strncmp(attr->name, "time-", 5))
+ if (!strncmp(attr->name, "time-", 5) ||
+ !strcmp(attr->name, "job-hold-until"))
continue;
if (!strncmp(attr->name, "job-", 4) &&
fcntl(job->side_pipes[1], F_SETFL,
fcntl(job->side_pipes[1], F_GETFL) | O_NONBLOCK);
+ fcntl(job->side_pipes[0], F_SETFD,
+ fcntl(job->side_pipes[0], F_GETFD) | FD_CLOEXEC);
+ fcntl(job->side_pipes[1], F_SETFD,
+ fcntl(job->side_pipes[1], F_GETFD) | FD_CLOEXEC);
+
/*
* Now start the first file in the job...
*/
if (action == CUPSD_JOB_DEFAULT && !job->kill_time)
job->kill_time = time(NULL) + JobKillDelay;
- else if (action == CUPSD_JOB_FORCE)
+ else if (action >= CUPSD_JOB_FORCE)
job->kill_time = 0;
for (i = 0; job->filters[i]; i ++)
if (job->filters[i] > 0)
- cupsdEndProcess(job->filters[i], action == CUPSD_JOB_FORCE);
+ {
+ cupsdEndProcess(job->filters[i], action >= CUPSD_JOB_FORCE);
+
+ if (action >= CUPSD_JOB_FORCE)
+ job->filters[i] = -job->filters[i];
+ }
if (job->backend > 0)
- cupsdEndProcess(job->backend, action == CUPSD_JOB_FORCE);
+ {
+ cupsdEndProcess(job->backend, action >= CUPSD_JOB_FORCE);
+
+ if (action >= CUPSD_JOB_FORCE)
+ job->backend = -job->backend;
+ }
+
+ if (action >= CUPSD_JOB_FORCE)
+ {
+ /*
+ * Clear job status...
+ */
+
+ job->status = 0;
+ }
}
job->sheets->values[0].integer += copies;
if (job->printer->page_limit)
- {
- cupsd_quota_t *q = cupsdUpdateQuota(job->printer, job->username,
- copies, 0);
-
-#ifdef __APPLE__
- if (AppleQuotas && q->page_count == -3)
- {
- /*
- * Quota limit exceeded, cancel job in progress immediately...
- */
-
- cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
- "Canceled job because pages exceed user %s "
- "quota limit on printer %s (%s).",
- job->username, job->printer->name,
- job->printer->info);
- return;
- }
-#else
- (void)q;
-#endif /* __APPLE__ */
- }
+ cupsdUpdateQuota(job->printer, job->username, copies, 0);
}
cupsdLogPage(job, message);
cupsFreeOptions(num_keywords, keywords);
}
- else if (!strncmp(message, "recoverable:", 12))
+ else
{
- ptr = message + 12;
- while (isspace(*ptr & 255))
- ptr ++;
+ /*
+ * Strip legacy message prefix...
+ */
- if (*ptr)
+ if (!strncmp(message, "recoverable:", 12))
{
- if (cupsdSetPrinterReasons(job->printer,
- "+com.apple.print.recoverable-warning") ||
- !job->printer->recoverable ||
- strcmp(job->printer->recoverable, ptr))
- {
- cupsdSetString(&(job->printer->recoverable), ptr);
- cupsdAddPrinterHistory(job->printer);
- event |= CUPSD_EVENT_PRINTER_STATE;
- }
+ ptr = message + 12;
+ while (isspace(*ptr & 255))
+ ptr ++;
}
- }
- else if (!strncmp(message, "recovered:", 10))
- {
- ptr = message + 10;
- while (isspace(*ptr & 255))
- ptr ++;
-
- if (cupsdSetPrinterReasons(job->printer,
- "-com.apple.print.recoverable-warning") ||
- !job->printer->recoverable || strcmp(job->printer->recoverable, ptr))
+ else if (!strncmp(message, "recovered:", 10))
{
- cupsdSetString(&(job->printer->recoverable), ptr);
- cupsdAddPrinterHistory(job->printer);
- event |= CUPSD_EVENT_PRINTER_STATE;
+ ptr = message + 10;
+ while (isspace(*ptr & 255))
+ ptr ++;
}
- }
- else
- {
- cupsdLogJob(job, loglevel, "%s", message);
+ else
+ ptr = message;
- if (loglevel < CUPSD_LOG_DEBUG)
+ cupsdLogJob(job, loglevel, "%s", ptr);
+
+ if (loglevel < CUPSD_LOG_DEBUG &&
+ strcmp(job->printer->state_message, ptr))
{
- strlcpy(job->printer->state_message, message,
+ strlcpy(job->printer->state_message, ptr,
sizeof(job->printer->state_message));
cupsdAddPrinterHistory(job->printer);
break;
}
+ if (event & CUPSD_EVENT_JOB_PROGRESS)
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
+ "%s", job->printer->state_message);
if (event & CUPSD_EVENT_PRINTER_STATE)
cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, job->printer, NULL,
(job->printer->type & CUPS_PRINTER_CLASS) ?
"Printer \"%s\" state changed.",
job->printer->name);
- if (event & CUPSD_EVENT_JOB_PROGRESS)
- cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
- "%s", job->printer->state_message);
if (ptr == NULL && !job->status_buffer->bufused)
{
* Handle the end of job stuff...
*/
- finalize_job(job);
+ finalize_job(job, 1);
/*
* Check for new jobs...
else if (job->printer->state_message[0] && do_message)
cupsdSetString(&(job->printer_message->values[0].string.text),
job->printer->state_message);
-
+
/*
* ... and the printer-state-reasons value...
*/