/*
- * "$Id: job.c 5543 2006-05-18 20:51:33Z mike $"
+ * "$Id: job.c 6462 2007-04-23 19:25:13Z mike $"
*
* Job management routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * 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
* cupsdStopAllJobs() - Stop all print jobs.
* cupsdStopJob() - Stop a print job.
* cupsdUnloadCompletedJobs() - Flush completed job history from memory.
- * cupsdUpdateJob() - Read a status update from a jobs filters.
* compare_active_jobs() - Compare the job IDs and priorities of two
* jobs.
* compare_jobs() - Compare the job IDs of two jobs.
* attribute...
* start_job() - Start a print job.
* unload_job() - Unload a job from memory.
+ * update_job() - Read a status update from a jobs filters.
*/
/*
static void set_hold_until(cupsd_job_t *job, time_t holdtime);
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);
/*
job->back_pipes[1] = -1;
job->print_pipes[0] = -1;
job->print_pipes[1] = -1;
+ job->side_pipes[0] = -1;
+ job->side_pipes[1] = -1;
job->status_pipes[0] = -1;
job->status_pipes[1] = -1;
*/
void
-cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */
- int purge) /* I - Purge jobs? */
+cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */
+ int purge, /* I - Purge jobs? */
+ ipp_jstate_t newstate) /* I - New job state */
{
int i; /* Looping var */
char filename[1024]; /* Job filename */
+ cupsd_printer_t *printer; /* Printer used by job */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCancelJob: id = %d", job->id);
* Stop any processes that are working on the current job...
*/
+ printer = job->printer;
+
if (job->state_value == IPP_JOB_PROCESSING)
cupsdStopJob(job, 0);
cupsdLoadJob(job);
if (job->attrs)
- job->state->values[0].integer = IPP_JOB_CANCELLED;
+ job->state->values[0].integer = newstate;
- job->state_value = IPP_JOB_CANCELLED;
+ job->state_value = newstate;
set_time(job, "time-at-completed");
+ /*
+ * Send any pending notifications and then expire them...
+ */
+
+ switch (newstate)
+ {
+ default :
+ break;
+
+ case IPP_JOB_CANCELED :
+ cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, printer, job,
+ purge ? "Job purged." : "Job canceled.");
+ break;
+
+ case IPP_JOB_ABORTED :
+ cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, printer, job,
+ "Job aborted; please consult the error_log file "
+ "for details.");
+ break;
+
+ case IPP_JOB_COMPLETED :
+ /*
+ * Clear the printer's printer-state-message and move on...
+ */
+
+ printer->state_message[0] = '\0';
+
+ cupsdSetPrinterState(printer, IPP_PRINTER_IDLE, 0);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, printer, job,
+ "Job completed.");
+ break;
+ }
+
cupsdExpireSubscriptions(NULL, job);
/*
* Cancel all jobs matching this destination/user...
*/
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- purge ? "Job purged." : "Job canceled.");
-
- cupsdCancelJob(job, purge);
+ cupsdCancelJob(job, purge, IPP_JOB_CANCELED);
}
cupsdCheckJobs();
pclass = printer;
- if (!(pclass->type & CUPS_PRINTER_REMOTE))
- {
- if (pclass->state != IPP_PRINTER_STOPPED)
- printer = cupsdFindAvailablePrinter(job->dest);
- else
- printer = NULL;
- }
+ if (pclass->state == IPP_PRINTER_STOPPED)
+ printer = NULL;
+ else if (pclass->type & CUPS_PRINTER_REMOTE)
+ break;
+ else
+ printer = cupsdFindAvailablePrinter(printer->name);
}
if (!printer && !pclass)
*/
cupsdLogMessage(CUPSD_LOG_WARN,
- "Printer/class %s has gone away; cancelling job %d!",
+ "Printer/class %s has gone away; canceling job %d!",
job->dest, job->id);
cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
"Job canceled because the destination printer/class has "
"gone away.");
- cupsdCancelJob(job, 1);
+ cupsdCancelJob(job, 1, IPP_JOB_ABORTED);
}
else if (printer)
{
for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
job && cupsArrayCount(Jobs) >= MaxJobs;
job = (cupsd_job_t *)cupsArrayNext(Jobs))
- if (job->state_value >= IPP_JOB_CANCELLED)
- cupsdCancelJob(job, 1);
+ if (job->state_value >= IPP_JOB_CANCELED)
+ cupsdCancelJob(job, 1, IPP_JOB_CANCELED);
}
void
cupsdFinishJob(cupsd_job_t *job) /* I - Job */
{
- int job_history; /* Did cupsdCancelJob() keep the job? */
cupsd_printer_t *printer; /* Current printer */
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishJob: job->status is %d",
job->status);
- if (job->status_buffer && job->current_file >= job->num_files)
+ if (job->status_buffer &&
+ (job->status < 0 || job->current_file >= job->num_files))
{
/*
* Close the pipe and clear the input bit.
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdFinishJob: Removing fd %d from InputSet...",
- job->status_buffer->fd);
-
- FD_CLR(job->status_buffer->fd, InputSet);
+ cupsdRemoveSelect(job->status_buffer->fd);
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdFinishJob: Closing status pipes [ %d %d ]...",
*/
cupsdStopJob(job, 0);
- job->state->values[0].integer = IPP_JOB_PENDING;
- job->state_value = IPP_JOB_PENDING;
+
+ if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ {
+ /*
+ * Mark the job as pending again - we'll retry on another
+ * printer...
+ */
+
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+ }
+
cupsdSaveJob(job);
/*
"after %d tries.",
job->id, JobRetryLimit);
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, printer, job,
- "Job canceled since it could not be sent after %d "
- "tries.",
- JobRetryLimit);
-
- cupsdCancelJob(job, 0);
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
}
else
{
*/
set_hold_until(job, time(NULL) + JobRetryInterval);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job,
+ "Job held due to fax errors; please consult "
+ "the error_log file for details.");
+ cupsdSetPrinterState(printer, IPP_PRINTER_IDLE, 0);
}
}
else if (!strcmp(printer->error_policy, "abort-job"))
- cupsdCancelJob(job, 0);
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
+ else
+ {
+ cupsdSetPrinterState(printer, IPP_PRINTER_STOPPED, 1);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
+ "Job stopped due to backend errors; please consult "
+ "the error_log file for details.");
+ }
break;
case CUPS_BACKEND_CANCEL :
* Cancel the job...
*/
- cupsdCancelJob(job, 0);
+ cupsdCancelJob(job, 0, IPP_JOB_CANCELED);
break;
case CUPS_BACKEND_HOLD :
*/
cupsdStopJob(job, 0);
+
cupsdSetJobHoldUntil(job, "indefinite");
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+
cupsdSaveJob(job);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
+ "Job held due to backend errors; please consult "
+ "the error_log file for details.");
break;
case CUPS_BACKEND_STOP :
*/
cupsdStopJob(job, 0);
+
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+
cupsdSaveJob(job);
cupsdSetPrinterState(printer, IPP_PRINTER_STOPPED, 1);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
+ "Job stopped due to backend errors; please consult "
+ "the error_log file for details.");
break;
case CUPS_BACKEND_AUTH_REQUIRED :
cupsdStopJob(job, 0);
+
cupsdSetJobHoldUntil(job, "authenticated");
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+
cupsdSaveJob(job);
cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
* Close out this job...
*/
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, printer, job,
- "Job completed successfully.");
-
- job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE);
-
- cupsdCancelJob(job, 0);
-
- if (job_history)
- {
- job->state->values[0].integer = IPP_JOB_COMPLETED;
- job->state_value = IPP_JOB_COMPLETED;
- cupsdSaveJob(job);
- }
-
- /*
- * Clear the printer's state_message and state_reasons and move on...
- */
-
- printer->state_message[0] = '\0';
-
- cupsdSetPrinterReasons(printer, "");
-
+ cupsdCancelJob(job, 0, IPP_JOB_COMPLETED);
cupsdCheckJobs();
}
}
cupsdHoldSignals();
- cupsdStopAllJobs();
+ cupsdStopAllJobs(1);
cupsdSaveAllJobs();
for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
if (job->state_value == IPP_JOB_STOPPED || job->num_files)
{
+ ipp_jstate_t old_state; /* Old job state */
+
+
cupsdLoadJob(job);
+ old_state = job->state_value;
+
job->tries = 0;
job->state->values[0].integer = IPP_JOB_PENDING;
job->state_value = IPP_JOB_PENDING;
+
cupsdSaveJob(job);
+
+ if (old_state > IPP_JOB_STOPPED)
+ cupsArrayAdd(ActiveJobs, job);
+
cupsdCheckJobs();
}
}
job->hold_until = curtime +
((17 - curdate->tm_hour) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
- }
+ }
else if (!strcmp(when, "second-shift"))
{
/*
job->hold_until = curtime +
((15 - curdate->tm_hour) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
- }
+ }
else if (!strcmp(when, "third-shift"))
{
/*
job->hold_until = curtime +
((23 - curdate->tm_hour) * 60 + 59 -
curdate->tm_min) * 60 + 60 - curdate->tm_sec;
- }
+ }
else if (!strcmp(when, "weekend"))
{
/*
*/
if (job->hold_until < curtime)
- job->hold_until += 24 * 60 * 60 * 60;
+ job->hold_until += 24 * 60 * 60;
}
cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSetJobHoldUntil: hold_until = %d",
*/
void
-cupsdStopAllJobs(void)
+cupsdStopAllJobs(int force) /* I - 1 = Force all filters to stop */
{
cupsd_job_t *job; /* Current job */
job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
if (job->state_value == IPP_JOB_PROCESSING)
{
- cupsdStopJob(job, 1);
+ cupsdStopJob(job, force);
job->state->values[0].integer = IPP_JOB_PENDING;
job->state_value = IPP_JOB_PENDING;
}
FilterLevel -= job->cost;
- if (job->status < 0 &&
- !(job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) &&
- !(job->printer->type & CUPS_PRINTER_FAX) &&
- !strcmp(job->printer->error_policy, "stop-printer"))
- cupsdSetPrinterState(job->printer, IPP_PRINTER_STOPPED, 1);
- else if (job->printer->state != IPP_PRINTER_STOPPED)
+ if (job->printer->state == IPP_PRINTER_PROCESSING)
cupsdSetPrinterState(job->printer, IPP_PRINTER_IDLE, 0);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopJob: printer state is %d",
- job->printer->state);
-
job->state->values[0].integer = IPP_JOB_STOPPED;
job->state_value = IPP_JOB_STOPPED;
job->printer->job = NULL;
cupsdClosePipe(job->back_pipes);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "cupsdStopJob: Closing side pipes [ %d %d ]...",
+ job->side_pipes[0], job->side_pipes[1]);
+
+ cupsdClosePipe(job->side_pipes);
+
if (job->status_buffer)
{
/*
* Close the pipe and clear the input bit.
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopJob: Removing fd %d from InputSet...",
- job->status_buffer->fd);
-
- FD_CLR(job->status_buffer->fd, InputSet);
+ cupsdRemoveSelect(job->status_buffer->fd);
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"cupsdStopJob: Closing status pipes [ %d %d ]...",
}
-/*
- * 'cupsdUpdateJob()' - Read a status update from a job's filters.
- */
-
-void
-cupsdUpdateJob(cupsd_job_t *job) /* I - Job to check */
-{
- int i; /* Looping var */
- int copies; /* Number of copies printed */
- char message[1024], /* Message text */
- *ptr; /* Pointer update... */
- int loglevel; /* Log level for message */
-
-
- while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel,
- message, sizeof(message))) != NULL)
- {
- /*
- * Process page and printer state messages as needed...
- */
-
- if (loglevel == CUPSD_LOG_PAGE)
- {
- /*
- * Page message; send the message to the page_log file and update the
- * job sheet count...
- */
-
- if (job->sheets != NULL)
- {
- if (!strncasecmp(message, "total ", 6))
- {
- /*
- * Got a total count of pages from a backend or filter...
- */
-
- copies = atoi(message + 6);
- copies -= job->sheets->values[0].integer; /* Just track the delta */
- }
- else if (!sscanf(message, "%*d%d", &copies))
- copies = 1;
-
- job->sheets->values[0].integer += copies;
-
- if (job->printer->page_limit)
- cupsdUpdateQuota(job->printer, job->username, copies, 0);
- }
-
- cupsdLogPage(job, message);
-
- cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
- "Printed %d page(s).", job->sheets->values[0].integer);
- }
- else if (loglevel == CUPSD_LOG_STATE)
- {
- cupsdSetPrinterReasons(job->printer, message);
- cupsdAddPrinterHistory(job->printer);
- }
- else if (loglevel == CUPSD_LOG_ATTR)
- {
- /*
- * Set attribute(s)...
- */
-
- /**** TODO ****/
- }
-#ifdef __APPLE__
- else if (!strncmp(message, "recoverable:", 12))
- {
- cupsdSetPrinterReasons(job->printer,
- "+com.apple.print.recoverable-warning");
-
- ptr = message + 12;
- while (isspace(*ptr & 255))
- ptr ++;
-
- cupsdSetString(&job->printer->recoverable, ptr);
- cupsdAddPrinterHistory(job->printer);
- }
- else if (!strncmp(message, "recovered:", 10))
- {
- cupsdSetPrinterReasons(job->printer,
- "-com.apple.print.recoverable-warning");
-
- ptr = message + 10;
- while (isspace(*ptr & 255))
- ptr ++;
-
- cupsdSetString(&job->printer->recoverable, ptr);
- cupsdAddPrinterHistory(job->printer);
- }
-#endif /* __APPLE__ */
- else if (loglevel <= CUPSD_LOG_INFO)
- {
- /*
- * Some message to show in the printer-state-message attribute...
- */
-
- strlcpy(job->printer->state_message, message,
- sizeof(job->printer->state_message));
- cupsdAddPrinterHistory(job->printer);
- }
-
- if (!strchr(job->status_buffer->buffer, '\n'))
- break;
- }
-
- if (ptr == NULL)
- {
- /*
- * See if all of the filters and the backend have returned their
- * exit statuses.
- */
-
- for (i = 0; job->filters[i] < 0; i ++);
-
- if (job->filters[i])
- return;
-
- if (job->current_file >= job->num_files && job->backend > 0)
- return;
-
- /*
- * Handle the end of job stuff...
- */
-
- cupsdFinishJob(job);
- }
-}
-
-
/*
* 'compare_active_jobs()' - Compare the job IDs and priorities of two jobs.
*/
int diff; /* Difference */
- if ((diff = ((cupsd_job_t *)first)->priority -
- ((cupsd_job_t *)second)->priority) != 0)
+ if ((diff = ((cupsd_job_t *)second)->priority -
+ ((cupsd_job_t *)first)->priority) != 0)
return (diff);
else
return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
{
cupsdClearString(&job->username);
cupsdClearString(&job->dest);
+#ifdef HAVE_GSSAPI
+ cupsdClearString(&job->ccname);
+#endif /* HAVE_GSSAPI */
if (job->num_files > 0)
{
/*
- * 'ipp_length()' - Compute the size of the buffer needed to hold
+ * 'ipp_length()' - Compute the size of the buffer needed to hold
* the textual IPP attributes.
*/
job->back_pipes[1] = -1;
job->print_pipes[0] = -1;
job->print_pipes[1] = -1;
+ job->side_pipes[0] = -1;
+ job->side_pipes[1] = -1;
job->status_pipes[0] = -1;
job->status_pipes[1] = -1;
}
else if (!strcasecmp(line, "State"))
{
- job->state_value = atoi(value);
+ job->state_value = (ipp_jstate_t)atoi(value);
if (job->state_value < IPP_JOB_PENDING)
job->state_value = IPP_JOB_PENDING;
job->back_pipes[1] = -1;
job->print_pipes[0] = -1;
job->print_pipes[1] = -1;
+ job->side_pipes[0] = -1;
+ job->side_pipes[1] = -1;
job->status_pipes[0] = -1;
job->status_pipes[1] = -1;
cupsArrayAdd(Jobs, job);
if (job->state_value <= IPP_JOB_STOPPED)
- cupsArrayAdd(ActiveJobs,job);
+ cupsArrayAdd(ActiveJobs, job);
else
unload_job(job);
}
* 'set_hold_until()' - Set the hold time and update job-hold-until attribute...
*/
-static void
+static void
set_hold_until(cupsd_job_t *job, /* I - Job to update */
time_t holdtime) /* I - Hold until time */
{
*/
holddate = gmtime(&holdtime);
- snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour,
+ snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour,
holddate->tm_min, holddate->tm_sec);
if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
{
int i; /* Looping var */
int slot; /* Pipe slot */
- cups_array_t *filters; /* Filters for job */
+ cups_array_t *filters, /* Filters for job */
+ *prefilters; /* Filters with prefilters */
mime_filter_t *filter, /* Current filter */
+ *prefilter, /* Prefilter */
port_monitor; /* Port monitor filter */
char method[255], /* Method for output */
*optptr, /* Pointer to options */
title[IPP_MAX_NAME],
/* Job title string */
copies[255], /* # copies string */
- *envp[MAX_ENV + 11],
+ *envp[MAX_ENV + 12],
/* Environment variables */
charset[255], /* CHARSET env variable */
class_name[255],/* CLASS env variable */
/* PRINTER env variable */
rip_max_cache[255];
/* RIP_MAX_CACHE env variable */
- int remote_job; /* Remote print job? */
static char *options = NULL;/* Full list of options */
static int optlength = 0; /* Length of option buffer */
if (job->num_files == 0)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Job ID %d has no files! Cancelling it!",
+ cupsdLogMessage(CUPSD_LOG_ERROR, "Job ID %d has no files! Canceling it!",
job->id);
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because it has no files.");
-
- cupsdCancelJob(job, 0);
- return;
- }
-
- if (printer->raw && !strncmp(printer->device_uri, "file:", 5))
- {
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Job ID %d cannot be printed to raw queue pointing to "
- "a file!",
- job->id);
-
- strlcpy(printer->state_message, "Raw printers cannot use file: devices!",
- sizeof(printer->state_message));
- cupsdStopPrinter(printer, 1);
- cupsdAddPrinterHistory(printer);
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
return;
}
job->current_file ++;
if (job->current_file == job->num_files)
- {
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because it has no files that can be "
- "printed.");
-
- cupsdCancelJob(job, 0);
- }
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
return;
}
cupsArrayDelete(filters);
filters = NULL;
}
+
+ /*
+ * If this printer has any pre-filters, insert the required pre-filter
+ * in the filters array...
+ */
+
+ if (printer->prefiltertype && filters)
+ {
+ prefilters = cupsArrayNew(NULL, NULL);
+
+ for (filter = (mime_filter_t *)cupsArrayFirst(filters);
+ filter;
+ filter = (mime_filter_t *)cupsArrayNext(filters))
+ {
+ if ((prefilter = mimeFilterLookup(MimeDatabase, filter->src,
+ printer->prefiltertype)))
+ {
+ cupsArrayAdd(prefilters, prefilter);
+ job->cost += prefilter->cost;
+ }
+
+ cupsArrayAdd(prefilters, filter);
+ }
+
+ cupsArrayDelete(filters);
+ filters = prefilters;
+ }
}
/*
FilterLevel += job->cost;
/*
- * Determine if we are printing to a remote printer...
- */
-
- remote_job = printer->raw && job->num_files > 1 &&
- !strncmp(printer->device_uri, "ipp://", 6);
-
- /*
- * Add decompression filters, if any...
+ * Add decompression/raw filter as needed...
*/
- if (!remote_job && job->compressions[job->current_file])
+ if ((!printer->raw && job->compressions[job->current_file]) ||
+ (!filters && !printer->remote &&
+ (job->num_files > 1 || !strncmp(printer->device_uri, "file:", 5))))
{
/*
* Add gziptoany filter to the front of the list...
*/
+ if (!filters)
+ filters = cupsArrayNew(NULL, NULL);
+
if (!cupsArrayInsert(filters, &gziptoany_filter))
{
cupsdLogMessage(CUPSD_LOG_ERROR,
job->current_file ++;
if (job->current_file == job->num_files)
- {
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because the print file could not be "
- "decompressed.");
-
- cupsdCancelJob(job, 0);
- }
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
return;
}
* Add port monitor to the end of the list...
*/
+ if (!filters)
+ filters = cupsArrayNew(NULL, NULL);
+
if (!cupsArrayAdd(filters, &port_monitor))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add port monitor - %s",
job->current_file ++;
if (job->current_file == job->num_files)
- {
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because the port monitor could not be "
- "added.");
-
- cupsdCancelJob(job, 0);
- }
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
return;
}
job->state->values[0].integer = IPP_JOB_PROCESSING;
job->state_value = IPP_JOB_PROCESSING;
+
job->status = 0;
job->printer = printer;
printer->job = job;
+
cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0);
if (job->current_file == 0)
fcntl(job->back_pipes[1], F_SETFL,
fcntl(job->back_pipes[1], F_GETFL) | O_NONBLOCK);
+
+ /*
+ * Create the side-channel pipes and make them non-blocking...
+ */
+
+ socketpair(AF_LOCAL, SOCK_STREAM, 0, job->side_pipes);
+
+ fcntl(job->side_pipes[0], F_SETFL,
+ fcntl(job->side_pipes[0], F_GETFL) | O_NONBLOCK);
+
+ fcntl(job->side_pipes[1], F_SETFL,
+ fcntl(job->side_pipes[1], F_GETFL) | O_NONBLOCK);
}
/*
FilterLevel -= job->cost;
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because the server ran out of memory.");
-
- cupsdCancelJob(job, 0);
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
return;
}
if ((!strcmp(attr->name, "page-label") ||
!strcmp(attr->name, "page-border") ||
!strncmp(attr->name, "number-up", 9) ||
+ !strcmp(attr->name, "page-ranges") ||
!strcmp(attr->name, "page-set") ||
!strcasecmp(attr->name, "AP_FIRSTPAGE_InputSlot") ||
!strcasecmp(attr->name, "AP_FIRSTPAGE_ManualFeed")) &&
* For remote jobs, we send all of the files in the argument list.
*/
- if (remote_job)
+ if (printer->remote && job->num_files > 1)
argv = calloc(7 + job->num_files, sizeof(char *));
else
argv = calloc(8, sizeof(char *));
argv[4] = copies;
argv[5] = options;
- if (remote_job)
+ if (printer->remote && job->num_files > 1)
{
for (i = 0; i < job->num_files; i ++)
{
envp[envc ++] = device_uri;
envp[envc ++] = printer_name;
- if ((filter = (mime_filter_t *)cupsArrayLast(filters)) != NULL)
+ if (!printer->remote && !printer->raw &&
+ (filter = (mime_filter_t *)cupsArrayLast(filters)) != NULL &&
+ filter->dst)
{
snprintf(final_content_type, sizeof(final_content_type),
"FINAL_CONTENT_TYPE=%s/%s",
envp[envc ++] = class_name;
}
+#ifdef HAVE_GSSAPI
+ if (job->ccname)
+ envp[envc ++] = job->ccname;
+#endif /* HAVE_GSSAPI */
+
envp[envc] = NULL;
for (i = 0; i < envc; i ++)
cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"DEVICE_URI=%s\"",
job->id, i, sani_uri);
- if (remote_job)
+ if (printer->remote)
job->current_file = job->num_files;
else
job->current_file ++;
strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to create status pipes - %s.", strerror(errno));
-
+
cupsdAddPrinterHistory(printer);
-
+
cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
"Job canceled because the server could not create the job "
"status pipes.");
-
+
goto abort_job;
}
-
+
cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: status_pipes = [ %d %d ]",
job->status_pipes[0], job->status_pipes[1]);
-
+
job->status_buffer = cupsdStatBufNew(job->status_pipes[0], "[Job %d]",
job->id);
}
job->status = 0;
memset(job->filters, 0, sizeof(job->filters));
- filterfds[1][0] = open("/dev/null", O_RDONLY);
-
- if (filterfds[1][0] < 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"/dev/null\" - %s.",
- strerror(errno));
- snprintf(printer->state_message, sizeof(printer->state_message),
- "Unable to open \"/dev/null\" - %s.", strerror(errno));
-
- cupsdAddPrinterHistory(printer);
-
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because the server could not open /dev/null.");
-
- goto abort_job;
- }
-
- fcntl(filterfds[1][0], F_SETFD, fcntl(filterfds[1][0], F_GETFD) | FD_CLOEXEC);
-
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: filterfds[%d] = [ %d %d ]",
- 1, filterfds[1][0], filterfds[1][1]);
-
for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters);
filter;
i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
else
{
job->print_pipes[0] = -1;
- if (!strncmp(printer->device_uri, "file:/dev/", 10) &&
- strcmp(printer->device_uri, "file:/dev/null"))
- job->print_pipes[1] = open(printer->device_uri + 5,
- O_WRONLY | O_EXCL);
- else if (!strncmp(printer->device_uri, "file:///dev/", 12) &&
- strcmp(printer->device_uri, "file:///dev/null"))
- job->print_pipes[1] = open(printer->device_uri + 7,
- O_WRONLY | O_EXCL);
+ if (!strcmp(printer->device_uri, "file:/dev/null") ||
+ !strcmp(printer->device_uri, "file:///dev/null"))
+ job->print_pipes[1] = -1;
else
- job->print_pipes[1] = open(printer->device_uri + 5,
- O_WRONLY | O_CREAT | O_TRUNC, 0600);
-
- if (job->print_pipes[1] < 0)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to open output file \"%s\" - %s.",
- printer->device_uri, strerror(errno));
- snprintf(printer->state_message, sizeof(printer->state_message),
- "Unable to open output file \"%s\" - %s.",
- printer->device_uri, strerror(errno));
-
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because the server could not open the "
- "output file.");
+ if (!strncmp(printer->device_uri, "file:/dev/", 10))
+ job->print_pipes[1] = open(printer->device_uri + 5,
+ O_WRONLY | O_EXCL);
+ else if (!strncmp(printer->device_uri, "file:///dev/", 12))
+ job->print_pipes[1] = open(printer->device_uri + 7,
+ O_WRONLY | O_EXCL);
+ else if (!strncmp(printer->device_uri, "file:///", 8))
+ job->print_pipes[1] = open(printer->device_uri + 7,
+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ else
+ job->print_pipes[1] = open(printer->device_uri + 5,
+ O_WRONLY | O_CREAT | O_TRUNC, 0600);
- goto abort_job;
- }
+ if (job->print_pipes[1] < 0)
+ {
+ cupsdLogMessage(CUPSD_LOG_ERROR,
+ "Unable to open output file \"%s\" - %s.",
+ printer->device_uri, strerror(errno));
+ snprintf(printer->state_message, sizeof(printer->state_message),
+ "Unable to open output file \"%s\" - %s.",
+ printer->device_uri, strerror(errno));
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
+ "Job canceled because the server could not open the "
+ "output file.");
+
+ goto abort_job;
+ }
- fcntl(job->print_pipes[1], F_SETFD,
- fcntl(job->print_pipes[1], F_GETFD) | FD_CLOEXEC);
+ fcntl(job->print_pipes[1], F_SETFD,
+ fcntl(job->print_pipes[1], F_GETFD) | FD_CLOEXEC);
+ }
}
cupsdLogMessage(CUPSD_LOG_DEBUG2,
pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
filterfds[slot][1], job->status_pipes[1],
- job->back_pipes[0], 0, job->filters + i);
+ job->back_pipes[0], job->side_pipes[0], 0,
+ job->filters + i);
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"start_job: Closing filter pipes for slot %d "
argv[0] = sani_uri;
filterfds[slot][0] = -1;
- filterfds[slot][1] = open("/dev/null", O_WRONLY);
-
- if (filterfds[slot][1] < 0)
- {
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"/dev/null\" - %s.",
- strerror(errno));
- snprintf(printer->state_message, sizeof(printer->state_message),
- "Unable to open \"/dev/null\" - %s.", strerror(errno));
-
- cupsdAddPrinterHistory(printer);
-
- cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
- "Job canceled because the server could not open a file.");
-
- goto abort_job;
- }
-
- fcntl(filterfds[slot][1], F_SETFD,
- fcntl(filterfds[slot][1], F_GETFD) | FD_CLOEXEC);
+ filterfds[slot][1] = -1;
cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: backend=\"%s\"",
command);
pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
filterfds[slot][1], job->status_pipes[1],
- job->back_pipes[1], backroot,
- &(job->backend));
+ job->back_pipes[1], job->side_pipes[1],
+ backroot, &(job->backend));
if (pid == 0)
{
cupsdClosePipe(job->back_pipes);
+ cupsdLogMessage(CUPSD_LOG_DEBUG2,
+ "start_job: Closing side pipes [ %d %d ]...",
+ job->side_pipes[0], job->side_pipes[1]);
+
+ cupsdClosePipe(job->side_pipes);
+
cupsdLogMessage(CUPSD_LOG_DEBUG2,
"start_job: Closing status output pipe %d...",
job->status_pipes[1]);
slot, filterfds[slot][0], filterfds[slot][1]);
cupsdClosePipe(filterfds[slot]);
- if (remote_job)
+ if (printer->remote && job->num_files > 1)
{
for (i = 0; i < job->num_files; i ++)
free(argv[i + 6]);
free(argv);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Adding fd %d to InputSet...",
- job->status_buffer->fd);
-
- FD_SET(job->status_buffer->fd, InputSet);
+ cupsdAddSelect(job->status_buffer->fd, (cupsd_selfunc_t)update_job, NULL,
+ job);
cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "Job #%d started.",
job->id);
cupsdClosePipe(job->status_pipes);
cupsdStatBufDelete(job->status_buffer);
+ job->status_buffer = NULL;
+
cupsArrayDelete(filters);
- if (remote_job)
+ if (printer->remote && job->num_files > 1)
{
for (i = 0; i < job->num_files; i ++)
free(argv[i + 6]);
/*
- * End of "$Id: job.c 5543 2006-05-18 20:51:33Z mike $".
+ * 'update_job()' - Read a status update from a job's filters.
+ */
+
+void
+update_job(cupsd_job_t *job) /* I - Job to check */
+{
+ int i; /* Looping var */
+ int copies; /* Number of copies printed */
+ char message[1024], /* Message text */
+ *ptr; /* Pointer update... */
+ int loglevel, /* Log level for message */
+ event = 0; /* Events? */
+
+
+ while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel,
+ message, sizeof(message))) != NULL)
+ {
+ /*
+ * Process page and printer state messages as needed...
+ */
+
+ if (loglevel == CUPSD_LOG_PAGE)
+ {
+ /*
+ * Page message; send the message to the page_log file and update the
+ * job sheet count...
+ */
+
+ if (job->sheets != NULL)
+ {
+ if (!strncasecmp(message, "total ", 6))
+ {
+ /*
+ * Got a total count of pages from a backend or filter...
+ */
+
+ copies = atoi(message + 6);
+ copies -= job->sheets->values[0].integer; /* Just track the delta */
+ }
+ else if (!sscanf(message, "%*d%d", &copies))
+ copies = 1;
+
+ 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...
+ */
+
+ cupsdLogMessage(CUPSD_LOG_INFO,
+ "Job %d canceled: pages exceed user %s quota "
+ "limit on printer %s (%s).",
+ job->id, job->username, job->printer->name,
+ job->printer->info);
+
+ cupsdCancelJob(job, 1, IPP_JOB_CANCELED);
+ return;
+ }
+#else
+ (void)q;
+#endif /* __APPLE__ */
+ }
+ }
+
+ cupsdLogPage(job, message);
+
+ cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
+ "Printed %d page(s).", job->sheets->values[0].integer);
+ }
+ else if (loglevel == CUPSD_LOG_STATE)
+ {
+ cupsdSetPrinterReasons(job->printer, message);
+ cupsdAddPrinterHistory(job->printer);
+ event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ }
+ else if (loglevel == CUPSD_LOG_ATTR)
+ {
+ /*
+ * Set attribute(s)...
+ */
+
+ int num_attrs; /* Number of attributes */
+ cups_option_t *attrs; /* Attributes */
+ const char *attr; /* Attribute */
+
+
+ num_attrs = cupsParseOptions(message, 0, &attrs);
+
+ if ((attr = cupsGetOption("auth-info-required", num_attrs,
+ attrs)) != NULL)
+ cupsdSetAuthInfoRequired(job->printer, attr, NULL);
+
+ if ((attr = cupsGetOption("printer-alert", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetString(&job->printer->alert, attr);
+ event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ }
+
+ if ((attr = cupsGetOption("printer-alert-description", num_attrs,
+ attrs)) != NULL)
+ {
+ cupsdSetString(&job->printer->alert_description, attr);
+ event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ }
+
+ cupsFreeOptions(num_attrs, attrs);
+ }
+#ifdef __APPLE__
+ else if (!strncmp(message, "recoverable:", 12))
+ {
+ cupsdSetPrinterReasons(job->printer,
+ "+com.apple.print.recoverable-warning");
+
+ ptr = message + 12;
+ while (isspace(*ptr & 255))
+ ptr ++;
+
+ cupsdSetString(&job->printer->recoverable, ptr);
+ cupsdAddPrinterHistory(job->printer);
+ event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ }
+ else if (!strncmp(message, "recovered:", 10))
+ {
+ cupsdSetPrinterReasons(job->printer,
+ "-com.apple.print.recoverable-warning");
+
+ ptr = message + 10;
+ while (isspace(*ptr & 255))
+ ptr ++;
+
+ cupsdSetString(&job->printer->recoverable, ptr);
+ cupsdAddPrinterHistory(job->printer);
+ event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ }
+#endif /* __APPLE__ */
+ else if (loglevel <= CUPSD_LOG_INFO)
+ {
+ /*
+ * Some message to show in the printer-state-message attribute...
+ */
+
+ strlcpy(job->printer->state_message, message,
+ sizeof(job->printer->state_message));
+ cupsdAddPrinterHistory(job->printer);
+ event |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
+ }
+
+ if (!strchr(job->status_buffer->buffer, '\n'))
+ break;
+ }
+
+ if ((event & CUPSD_EVENT_PRINTER_STATE_CHANGED))
+ cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE_CHANGED, job->printer, NULL,
+ (job->printer->type & CUPS_PRINTER_CLASS) ?
+ "Class \"%s\" state changed." :
+ "Printer \"%s\" state changed.",
+ job->printer->name);
+
+ if (ptr == NULL && !job->status_buffer->bufused)
+ {
+ /*
+ * See if all of the filters and the backend have returned their
+ * exit statuses.
+ */
+
+ for (i = 0; job->filters[i] < 0; i ++);
+
+ if (job->filters[i])
+ return;
+
+ if (job->current_file >= job->num_files && job->backend > 0)
+ return;
+
+ /*
+ * Handle the end of job stuff...
+ */
+
+ cupsdFinishJob(job);
+ }
+}
+
+
+/*
+ * End of "$Id: job.c 6462 2007-04-23 19:25:13Z mike $".
*/