/*
* Job management routines for the CUPS scheduler.
*
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2019 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
* property of Apple Inc. and are protected by Federal copyright
* law. Distribution and use rights are outlined in the file "LICENSE.txt"
* which should have been included with this file. If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
+ * missing or damaged, see the license at "http://www.cups.org/".
*/
/*
curtime = time(NULL);
JobHistoryUpdate = 0;
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: curtime=%d", (int)curtime);
+
for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
job;
job = (cupsd_job_t *)cupsArrayNext(Jobs))
{
+ cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: Job %d, state=%d, printer=%p, history_time=%d, file_time=%d", job->id, (int)job->state_value, (void *)job->printer, (int)job->history_time, (int)job->file_time);
+
+ if ((job->history_time && job->history_time) < JobHistoryUpdate || !JobHistoryUpdate)
+ JobHistoryUpdate = job->history_time;
+
+ if ((job->file_time && job->file_time < JobHistoryUpdate) || !JobHistoryUpdate)
+ JobHistoryUpdate = job->file_time;
+
if (job->state_value >= IPP_JOB_CANCELED && !job->printer)
{
/*
remove_job_files(job);
cupsdMarkDirty(CUPSD_DIRTY_JOBS);
-
- if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
- JobHistoryUpdate = job->history_time;
- }
- else
- {
- if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
- JobHistoryUpdate = job->history_time;
-
- if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
- JobHistoryUpdate = job->file_time;
}
}
}
job->completed_time = attr->values[0].integer;
if (JobHistory < INT_MAX)
- job->history_time = attr->values[0].integer + JobHistory;
+ job->history_time = job->completed_time + JobHistory;
else
job->history_time = INT_MAX;
JobHistoryUpdate = job->history_time;
if (JobFiles < INT_MAX)
- job->file_time = attr->values[0].integer + JobFiles;
+ job->file_time = job->completed_time + JobFiles;
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 (!job->impressions)
job->impressions = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", 0);
+ if (!job->sheets)
+ job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-media-sheets-completed", 0);
if (!job->priority)
{
* Update the server "busy" state...
*/
- cupsdSetBusyState();
+ cupsdSetBusyState(0);
}
* Update history/file expiration times...
*/
+ job->completed_time = attr->values[0].integer;
+
if (JobHistory < INT_MAX)
- job->history_time = attr->values[0].integer + JobHistory;
+ job->history_time = job->completed_time + JobHistory;
else
job->history_time = INT_MAX;
JobHistoryUpdate = job->history_time;
if (JobFiles < INT_MAX)
- job->file_time = attr->values[0].integer + JobFiles;
+ job->file_time = job->completed_time + JobFiles;
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);
}
cupsdStatBufDelete(job->status_buffer);
job->status_buffer = NULL;
+ /*
+ * Log the final impression (page) count...
+ */
+
+ snprintf(buffer, sizeof(buffer), "total %d", ippGetInteger(job->impressions, 0));
+ cupsdLogPage(job, buffer);
+
/*
* Process the exit status...
*/
/*
* 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...
*/
job_state == IPP_JOB_COMPLETED)
{
job_state = IPP_JOB_ABORTED;
- message = "Job aborted due to backend errors; please consult "
- "the error_log file for details.";
+
+ if (ErrorLog)
+ {
+ snprintf(buffer, sizeof(buffer), "Job aborted due to backend errors; please consult the %s file for details.", ErrorLog);
+ message = buffer;
+ }
+ else
+ message = "Job aborted due to backend errors.";
ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system");
}
{
job_state = IPP_JOB_PENDING;
printer_state = IPP_PRINTER_STOPPED;
- message = "Printer stopped due to backend errors; please "
- "consult the error_log file for details.";
+
+ if (ErrorLog)
+ {
+ snprintf(buffer, sizeof(buffer), "Printer stopped due to backend errors; please consult the %s file for details.", ErrorLog);
+ message = buffer;
+ }
+ else
+ message = "Printer stopped due to backend errors.";
ippSetString(job->attrs, &job->reasons, 0, "none");
}
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.";
+
+ if (ErrorLog)
+ {
+ snprintf(buffer, sizeof(buffer), "Job held indefinitely due to backend errors; please consult the %s file for details.", ErrorLog);
+ message = buffer;
+ }
+ else
+ message = "Job held indefinitely due to backend errors.";
}
else if (!strcmp(reason, "account-info-needed"))
{
cupsdSetJobHoldUntil(job, "indefinite", 0);
- message = "Job held indefinitely - account information is "
- "required.";
+ message = "Job held indefinitely - account information is required.";
}
else if (!strcmp(reason, "account-closed"))
{
{
cupsdSetJobHoldUntil(job, "indefinite", 0);
- message = "Job held indefinitely - account limit has been "
- "reached.";
+ message = "Job held indefinitely - account limit has been reached.";
}
else
{
* Stop the printer...
*/
+ if (job_state == IPP_JSTATE_CANCELED || job_state == IPP_JSTATE_ABORTED)
+ {
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Ignored STOP from backend since the job is %s.", job_state == IPP_JSTATE_CANCELED ? "canceled" : "aborted");
+ break;
+ }
+
printer_state = IPP_PRINTER_STOPPED;
- message = "Printer stopped due to backend errors; please "
- "consult the error_log file for details.";
+
+ if (ErrorLog)
+ {
+ snprintf(buffer, sizeof(buffer), "Printer stopped due to backend errors; please consult the %s file for details.", ErrorLog);
+ message = buffer;
+ }
+ else
+ message = "Printer stopped due to backend errors.";
if (job_state == IPP_JOB_COMPLETED)
{
job_state = IPP_JOB_PENDING;
- ippSetString(job->attrs, &job->reasons, 0,
- "resources-are-not-ready");
+ ippSetString(job->attrs, &job->reasons, 0, "resources-are-not-ready");
}
break;
if (job_state == IPP_JOB_COMPLETED)
{
job_state = IPP_JOB_STOPPED;
- message = "Job stopped due to filter errors; please consult the "
- "error_log file for details.";
+
+ if (ErrorLog)
+ {
+ snprintf(buffer, sizeof(buffer), "Job stopped due to filter errors; please consult the %s file for details.", ErrorLog);
+ message = buffer;
+ }
+ else
+ message = "Job stopped due to filter errors.";
if (WIFSIGNALED(job->status))
ippSetString(job->attrs, &job->reasons, 0, "cups-filter-crashed");
cupsArrayRemove(PrintingJobs, job);
+ /*
+ * Clear informational messages...
+ */
+
+ if (job->status_level > CUPSD_LOG_ERROR)
+ job->printer->state_message[0] = '\0';
+
/*
* Apply any PPD updates...
*/
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);
}
/*
job->completed_time = curtime;
if (JobHistory < INT_MAX && attr)
- job->history_time = attr->values[0].integer + JobHistory;
+ job->history_time = job->completed_time + JobHistory;
else
job->history_time = INT_MAX;
JobHistoryUpdate = job->history_time;
if (JobFiles < INT_MAX && attr)
- job->file_time = attr->values[0].integer + JobFiles;
+ job->file_time = job->completed_time + JobFiles;
else
job->file_time = INT_MAX;
job->profile = cupsdCreateProfile(job->id, 0);
job->bprofile = cupsdCreateProfile(job->id, 1);
+#ifdef HAVE_SANDBOX_H
+ if ((!job->profile || !job->bprofile) && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF)
+ {
+ /*
+ * Failure to create the sandbox profile means something really bad has
+ * happened and we need to shutdown immediately.
+ */
+
+ return;
+ }
+#endif /* HAVE_SANDBOX_H */
+
/*
* Create the status pipes and buffer...
*/
update_job(cupsd_job_t *job) /* I - Job to check */
{
int i; /* Looping var */
- int copies; /* Number of copies printed */
char message[CUPSD_SB_BUFFER_SIZE],
/* Message text */
*ptr; /* Pointer update... */
if (loglevel == CUPSD_LOG_PAGE)
{
+ int impressions = ippGetInteger(job->impressions, 0);
+ /* Number of impressions printed */
+ int delta; /* Number of impressions added */
+
/*
* Page message; send the message to the page_log file and update the
* job sheet count...
cupsdLogJob(job, CUPSD_LOG_DEBUG, "PAGE: %s", message);
- if (job->impressions)
+ if (!_cups_strncasecmp(message, "total ", 6))
{
- if (!_cups_strncasecmp(message, "total ", 6))
- {
- /*
- * Got a total count of pages from a backend or filter...
- */
+ /*
+ * Got a total count of pages from a backend or filter...
+ */
- copies = atoi(message + 6);
- copies -= ippGetInteger(job->impressions, 0); /* Just track the delta */
+ int total = atoi(message + 6); /* Total impressions */
+
+ if (total > impressions)
+ {
+ delta = total - impressions;
+ impressions = total;
}
- else if (!sscanf(message, "%*d%d", &copies))
+ else
+ delta = 0;
+ }
+ else
+ {
+ /*
+ * Add the number of copies to the impression count...
+ */
+
+ int copies; /* Number of copies */
+
+ if (!sscanf(message, "%*d%d", &copies) || copies <= 0)
copies = 1;
- ippSetInteger(job->attrs, &job->impressions, 0, ippGetInteger(job->impressions, 0) + copies);
- job->dirty = 1;
- cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ delta = copies;
+ impressions += copies;
}
+ if (job->impressions)
+ ippSetInteger(job->attrs, &job->impressions, 0, impressions);
+
if (job->sheets)
{
- if (!_cups_strncasecmp(message, "total ", 6))
- {
- /*
- * Got a total count of pages from a backend or filter...
- */
+ const char *sides = ippGetString(ippFindAttribute(job->attrs, "sides", IPP_TAG_KEYWORD), 0, NULL);
- copies = atoi(message + 6);
- copies -= ippGetInteger(job->sheets, 0); /* Just track the delta */
- }
- else if (!sscanf(message, "%*d%d", &copies))
- copies = 1;
-
- ippSetInteger(job->attrs, &job->sheets, 0, ippGetInteger(job->sheets, 0) + copies);
- job->dirty = 1;
- cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ if (sides && strcmp(sides, "one-sided"))
+ ippSetInteger(job->attrs, &job->sheets, 0, impressions / 2);
+ else
+ ippSetInteger(job->attrs, &job->sheets, 0, impressions);
- if (job->printer->page_limit)
- cupsdUpdateQuota(job->printer, job->username, copies, 0);
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, "Printed %d page(s).", ippGetInteger(job->sheets, 0));
}
- cupsdLogPage(job, message);
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
- if (job->sheets)
- cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, "Printed %d page(s).", ippGetInteger(job->sheets, 0));
+ if (job->printer->page_limit)
+ cupsdUpdateQuota(job->printer, job->username, delta, 0);
}
else if (loglevel == CUPSD_LOG_JOBSTATE)
{
if (cancel_after)
job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
- else
+ else if (MaxJobTime > 0)
job->cancel_time = time(NULL) + MaxJobTime;
+ else
+ job->cancel_time = 0;
}
}
}