/*
- * "$Id: job.c 6600 2007-06-22 18:19:20Z mike $"
+ * "$Id: job.c 7005 2007-10-01 23:45:48Z mike $"
*
* Job management routines for the Common UNIX Printing System (CUPS).
*
+ * Copyright 2007-2008 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
- * property of Easy Software Products 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 please contact Easy Software Products
- * at:
- *
- * Attn: CUPS Licensing Information
- * Easy Software Products
- * 44141 Airport View Drive, Suite 204
- * Hollywood, Maryland 20636 USA
- *
- * Voice: (301) 373-9600
- * EMail: cups-info@cups.org
- * WWW: http://www.cups.org
+ * 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:
*
* start_job() - Start a print job.
* unload_job() - Unload a job from memory.
* update_job() - Read a status update from a jobs filters.
+ * update_job_attrs() - Update the job-printer-* attributes.
*/
/*
static void start_job(cupsd_job_t *job, cupsd_printer_t *printer);
static void unload_job(cupsd_job_t *job);
static void update_job(cupsd_job_t *job);
+static void update_job_attrs(cupsd_job_t *job);
/*
cupsd_job_t *job; /* New job record */
- job = calloc(sizeof(cupsd_job_t), 1);
+ if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL)
+ return (NULL);
job->id = NextJobId ++;
job->priority = priority;
*/
snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id);
- unlink(filename);
+ if (cupsdRemoveFile(filename) && errno != ENOENT)
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to remove authentication cache: %s",
+ strerror(errno));
cupsdClearString(&job->auth_username);
cupsdClearString(&job->auth_domain);
cupsdClearString(&job->auth_password);
+#ifdef HAVE_GSSAPI
+ /*
+ * Destroy the credential cache and clear the KRB5CCNAME env var string.
+ */
+
+ if (job->ccache)
+ {
+ krb5_cc_destroy(KerberosContext, job->ccache);
+ job->ccache = NULL;
+ }
+
+ cupsdClearString(&job->ccname);
+#endif /* HAVE_GSSAPI */
+
/*
* Remove the print file for good if we aren't preserving jobs or
* files...
job->current_file = 0;
- if (!JobHistory || !JobFiles || purge || (job->dtype & CUPS_PRINTER_REMOTE))
+ if (!JobHistory || !JobFiles || purge)
{
for (i = 1; i <= job->num_files; i ++)
{
}
}
- if (JobHistory && !purge && !(job->dtype & CUPS_PRINTER_REMOTE))
+ if (JobHistory && !purge)
{
/*
* Save job state info...
for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
job;
job = (cupsd_job_t *)cupsArrayNext(Jobs))
+ {
+ if (!job->dest || !job->username)
+ cupsdLoadJob(job);
+
+ if (!job->dest || !job->username)
+ continue;
+
if ((dest == NULL || !strcmp(job->dest, dest)) &&
(username == NULL || !strcmp(job->username, username)))
{
cupsdCancelJob(job, purge, IPP_JOB_CANCELED);
}
+ }
cupsdCheckJobs();
}
cupsd_job_t *job; /* Current job in queue */
cupsd_printer_t *printer, /* Printer destination */
*pclass; /* Printer class destination */
+ ipp_attribute_t *attr; /* Job attribute */
DEBUG_puts("cupsdCheckJobs()");
job->hold_until < time(NULL))
{
if (job->pending_timeout)
- cupsdTimeoutJob(job); /* Add trailing banner as needed */
+ {
+ /* Add trailing banner as needed */
+ if (cupsdTimeoutJob(job))
+ continue;
+ }
job->state->values[0].integer = IPP_JOB_PENDING;
job->state_value = IPP_JOB_PENDING;
+
+ if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
+ IPP_TAG_KEYWORD)) == NULL)
+ attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
+
+ if (attr)
+ {
+ attr->value_tag = IPP_TAG_KEYWORD;
+ cupsdSetString(&(attr->values[0].string.text), "no-hold");
+ cupsdSaveJob(job);
+ }
}
/*
* so that we know which printer actually printed the job...
*/
- ipp_attribute_t *attr; /* job-actual-printer-uri attribute */
-
-
if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
IPP_TAG_URI)) != NULL)
cupsdSetString(&attr->values[0].string.text, printer->uri);
printer->state == IPP_PRINTER_IDLE) || /* and idle */
((printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is remote */
!printer->job)) /* and not printing */
+ {
+ /*
+ * Clear any message and reasons for the queue...
+ */
+
+ printer->state_message[0] = '\0';
+
+ cupsdSetPrinterReasons(printer, "none");
+
+ /*
+ * Start the job...
+ */
+
start_job(job, printer);
+ }
}
}
}
printer = job->printer;
+ update_job_attrs(job);
+
if (job->status < 0)
{
/*
* Filter had errors; stop job...
*/
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Job stopped due to filter errors.", job->id);
cupsdStopJob(job, 1);
cupsdSaveJob(job);
cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
* Close out this job...
*/
+ cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Completed successfully.",
+ job->id);
cupsdCancelJob(job, 0, IPP_JOB_COMPLETED);
cupsdCheckJobs();
}
job->state->values[0].integer = IPP_JOB_HELD;
job->state_value = IPP_JOB_HELD;
+ job->current_file = 0;
cupsdSaveJob(job);
cupsdSetString(&job->dest, dest);
}
- else
- destptr = cupsdFindDest(job->dest);
+ else if ((destptr = cupsdFindDest(job->dest)) == NULL)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "[Job %d] Unable to queue job for destination \"%s\"!",
+ job->id, job->dest);
+ ippDelete(job->attrs);
+ job->attrs = NULL;
+ unlink(jobfile);
+ return;
+ }
job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
IPP_TAG_INTEGER);
* Change the destination information...
*/
- cupsdLoadJob(job);
+ if (job->state_value == IPP_JOB_PROCESSING)
+ cupsdStopJob(job, 0);
+ else
+ cupsdLoadJob(job);
cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, oldp, job,
"Job #%d moved from %s to %s.", job->id, olddest,
job->backend = 0;
}
+ cupsdDestroyProfile(job->profile);
+ job->profile = NULL;
+
cupsdLogMessage(CUPSD_LOG_DEBUG2, "[Job %d] Closing print pipes [ %d %d ]...",
job->id, job->print_pipes[0], job->print_pipes[1]);
cupsdClearString(&job->auth_username);
cupsdClearString(&job->auth_domain);
cupsdClearString(&job->auth_password);
+
#ifdef HAVE_GSSAPI
+ /*
+ * Destroy the credential cache and clear the KRB5CCNAME env var string.
+ */
+
+ if (job->ccache)
+ {
+ krb5_cc_destroy(KerberosContext, job->ccache);
+ job->ccache = NULL;
+ }
+
cupsdClearString(&job->ccname);
#endif /* HAVE_GSSAPI */
title[IPP_MAX_NAME],
/* Job title string */
copies[255], /* # copies string */
- *envp[MAX_ENV + 15],
+ *envp[MAX_ENV + 16],
/* Environment variables */
charset[255], /* CHARSET env variable */
class_name[255],/* CLASS env variable */
final_content_type[1024],
/* FINAL_CONTENT_TYPE env variable */
lang[255], /* LANG env variable */
+#ifdef __APPLE__
+ apple_language[255],
+ /* APPLE_LANGUAGE env variable */
+#endif /* __APPLE__ */
ppd[1024], /* PPD env variable */
printer_name[255],
/* PRINTER env variable */
"[Job %d] Unable to convert file %d to printable format!",
job->current_file, job->id);
cupsdLogMessage(CUPSD_LOG_INFO,
- "Hint: Do you have ESP Ghostscript installed?");
+ "Hint: Do you have Ghostscript installed?");
if (LogLevel < CUPSD_LOG_DEBUG)
cupsdLogMessage(CUPSD_LOG_INFO,
!strcmp(attr->name, "page-ranges") ||
!strcmp(attr->name, "page-set") ||
!strcasecmp(attr->name, "AP_FIRSTPAGE_InputSlot") ||
- !strcasecmp(attr->name, "AP_FIRSTPAGE_ManualFeed")) &&
+ !strcasecmp(attr->name, "AP_FIRSTPAGE_ManualFeed") ||
+ !strcasecmp(attr->name, "com.apple.print.PrintSettings."
+ "PMTotalSidesImaged..n.") ||
+ !strcasecmp(attr->name, "com.apple.print.PrintSettings."
+ "PMTotalBeginPages..n.")) &&
banner_page)
continue;
else
argv = calloc(8, sizeof(char *));
+ if (!argv)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to allocate argument array!");
+ cupsArrayDelete(filters);
+
+ FilterLevel -= job->cost;
+
+ cupsdStopPrinter(printer, 0);
+ return;
+ }
+
sprintf(jobid, "%d", job->id);
argv[0] = printer->name;
attr = ippFindAttribute(job->attrs, "attributes-natural-language",
IPP_TAG_LANGUAGE);
+#ifdef __APPLE__
+ strcpy(apple_language, "APPLE_LANGUAGE=");
+ _cupsAppleLanguage(attr->values[0].string.text,
+ apple_language + 15, sizeof(apple_language) - 15);
+#endif /* __APPLE__ */
+
switch (strlen(attr->values[0].string.text))
{
default :
* Just the language code (ll)...
*/
- snprintf(lang, sizeof(lang), "LANG=%s",
+ snprintf(lang, sizeof(lang), "LANG=%s.UTF8",
attr->values[0].string.text);
break;
* Language and country code (ll-cc)...
*/
- snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c",
+ snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF8",
attr->values[0].string.text[0],
attr->values[0].string.text[1],
toupper(attr->values[0].string.text[3] & 255),
envp[envc ++] = charset;
envp[envc ++] = lang;
+#ifdef __APPLE__
+ envp[envc ++] = apple_language;
+#endif /* __APPLE__ */
envp[envc ++] = ppd;
envp[envc ++] = rip_max_cache;
envp[envc ++] = content_type;
envp[envc] = NULL;
for (i = 0; i < envc; i ++)
- if (!strncmp(envp[i], "AUTH_", 5))
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"AUTH_%c****\"",
+ if (!strncmp(envp[i], "CUPSD_AUTH_", 5))
+ cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"CUPSD_AUTH_%c****\"",
job->id, i, envp[i][5]);
else if (strncmp(envp[i], "DEVICE_URI=", 11))
cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"%s\"",
job->status = 0;
memset(job->filters, 0, sizeof(job->filters));
+ if (!job->profile)
+ job->profile = cupsdCreateProfile(job->id);
+
for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters);
filter;
i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
filterfds[slot][1], job->status_pipes[1],
job->back_pipes[0], job->side_pipes[0], 0,
- job->filters + i);
+ job->profile, job->filters + i);
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"[Job %d] start_job: Closing filter pipes for slot %d "
if (strncmp(printer->device_uri, "file:", 5) != 0)
{
- if (job->current_file == 1)
+ if (job->current_file == 1 || printer->remote)
{
sscanf(printer->device_uri, "%254[^:]", method);
snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, method);
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->backend));
+ backroot, job->profile, &(job->backend));
if (pid == 0)
{
ippDelete(job->attrs);
- job->attrs = NULL;
- job->state = NULL;
- job->sheets = NULL;
- job->job_sheets = NULL;
+ job->attrs = NULL;
+ job->state = NULL;
+ job->sheets = NULL;
+ job->job_sheets = NULL;
+ job->printer_message = NULL;
+ job->printer_reasons = NULL;
}
* job sheet count...
*/
- if (job->sheets != NULL)
+ if (job->sheets)
{
if (!strncasecmp(message, "total ", 6))
{
cupsdLogPage(job, message);
- cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
- "Printed %d page(s).", job->sheets->values[0].integer);
+ if (job->sheets)
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
+ "Printed %d page(s).", job->sheets->values[0].integer);
}
else if (loglevel == CUPSD_LOG_STATE)
{
if (!strcmp(message, "paused"))
+ {
cupsdStopPrinter(job->printer, 1);
+ return;
+ }
else
{
cupsdSetPrinterReasons(job->printer, message);
cupsdAddPrinterHistory(job->printer);
- event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ event |= CUPSD_EVENT_PRINTER_STATE;
}
+
+ update_job_attrs(job);
}
else if (loglevel == CUPSD_LOG_ATTR)
{
if ((attr = cupsGetOption("auth-info-required", num_attrs,
attrs)) != NULL)
+ {
cupsdSetAuthInfoRequired(job->printer, attr, NULL);
+ cupsdSetPrinterAttrs(job->printer);
+ cupsdSaveAllPrinters();
+ }
if ((attr = cupsGetOption("printer-alert", num_attrs, attrs)) != NULL)
{
cupsdSetString(&job->printer->alert, attr);
- event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ event |= CUPSD_EVENT_PRINTER_STATE;
}
if ((attr = cupsGetOption("printer-alert-description", num_attrs,
attrs)) != NULL)
{
cupsdSetString(&job->printer->alert_description, attr);
- event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ }
+
+ if ((attr = cupsGetOption("marker-colors", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-colors", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ }
+
+ if ((attr = cupsGetOption("marker-levels", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-levels", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ }
+
+ if ((attr = cupsGetOption("marker-names", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-names", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ }
+
+ if ((attr = cupsGetOption("marker-types", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-types", (char *)attr);
+ job->printer->marker_time = time(NULL);
+ event |= CUPSD_EVENT_PRINTER_STATE;
}
cupsFreeOptions(num_attrs, attrs);
cupsdSetString(&job->printer->recoverable, ptr);
cupsdAddPrinterHistory(job->printer);
- event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ event |= CUPSD_EVENT_PRINTER_STATE;
}
else if (!strncmp(message, "recovered:", 10))
{
cupsdSetString(&job->printer->recoverable, ptr);
cupsdAddPrinterHistory(job->printer);
- event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ event |= CUPSD_EVENT_PRINTER_STATE;
}
#endif /* __APPLE__ */
else if (loglevel <= job->status_level)
* Some message to show in the printer-state-message attribute...
*/
- job->status_level = loglevel;
+ if (loglevel != CUPSD_LOG_NOTICE)
+ job->status_level = loglevel;
strlcpy(job->printer->state_message, message,
sizeof(job->printer->state_message));
cupsdAddPrinterHistory(job->printer);
- event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ event |= CUPSD_EVENT_PRINTER_STATE;
+
+ update_job_attrs(job);
}
if (!strchr(job->status_buffer->buffer, '\n'))
break;
}
- if ((event & CUPSD_EVENT_PRINTER_STATE_CHANGED))
- cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE_CHANGED, job->printer, NULL,
+ if (event & CUPSD_EVENT_PRINTER_STATE)
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, job->printer, NULL,
(job->printer->type & CUPS_PRINTER_CLASS) ?
"Class \"%s\" state changed." :
"Printer \"%s\" state changed.",
/*
- * End of "$Id: job.c 6600 2007-06-22 18:19:20Z mike $".
+ * 'update_job_attrs()' - Update the job-printer-* attributes.
+ */
+
+void
+update_job_attrs(cupsd_job_t *job) /* I - Job to update */
+{
+ int i; /* Looping var */
+ int num_reasons; /* Actual number of reasons */
+ const char * const *reasons; /* Reasons */
+ static const char *none = "none", /* "none" */
+ *paused = "paused";
+ /* "paused" */
+
+
+ /*
+ * Get/create the job-printer-state-* attributes...
+ */
+
+ if (!job->printer_message)
+ {
+ if ((job->printer_message = ippFindAttribute(job->attrs,
+ "job-printer-state-message",
+ IPP_TAG_TEXT)) == NULL)
+ job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_TEXT,
+ "job-printer-state-message",
+ NULL, "");
+ }
+
+ if (!job->printer_reasons)
+ job->printer_reasons = ippFindAttribute(job->attrs,
+ "job-printer-state-reasons",
+ IPP_TAG_KEYWORD);
+
+ /*
+ * If the job isn't printing, return now...
+ */
+
+ if (!job->printer)
+ return;
+
+ /*
+ * Otherwise copy the printer-state-message value...
+ */
+
+ if (job->printer->state_message[0])
+ cupsdSetString(&(job->printer_message->values[0].string.text),
+ job->printer->state_message);
+
+ /*
+ * ... and the printer-state-reasons value...
+ */
+
+ if (job->printer->num_reasons == 0)
+ {
+ num_reasons = 1;
+ reasons = job->printer->state == IPP_PRINTER_STOPPED ? &paused : &none;
+ }
+ else
+ {
+ num_reasons = job->printer->num_reasons;
+ reasons = (const char * const *)job->printer->reasons;
+ }
+
+ if (!job->printer_reasons || job->printer_reasons->num_values != num_reasons)
+ {
+ ippDeleteAttribute(job->attrs, job->printer_reasons);
+
+ job->printer_reasons = ippAddStrings(job->attrs,
+ IPP_TAG_JOB, IPP_TAG_KEYWORD,
+ "job-printer-state-reasons",
+ num_reasons, NULL, NULL);
+ }
+
+ for (i = 0; i < num_reasons; i ++)
+ cupsdSetString(&(job->printer_reasons->values[i].string.text), reasons[i]);
+}
+
+
+/*
+ * End of "$Id: job.c 7005 2007-10-01 23:45:48Z mike $".
*/