/*
- * "$Id: job.c 5719 2006-07-11 21:04:48Z mike $"
+ * "$Id: job.c 7682 2008-06-21 00:06:02Z mike $"
*
* Job management routines for the Common UNIX Printing System (CUPS).
*
- * Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ * 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:
*
* cupsdCheckJobs() - Check the pending jobs and start any if
* the destination is available.
* cupsdCleanJobs() - Clean out old jobs.
+ * cupsdDeleteJob() - Free all memory used by a job.
* cupsdFinishJob() - Finish a job.
* cupsdFreeAllJobs() - Free all jobs from memory.
* cupsdFindJob() - Find the specified job.
* 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.
- * free_job() - Free all memory used by a job.
* 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.
* attribute...
* 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 int compare_active_jobs(void *first, void *second, void *data);
static int compare_jobs(void *first, void *second, void *data);
-static void free_job(cupsd_job_t *job);
static int ipp_length(ipp_t *ipp);
static void load_job_cache(const char *filename);
static void load_next_job_id(const char *filename);
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);
+static void update_job_attrs(cupsd_job_t *job, int do_message);
/*
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;
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);
/*
- * Remove the job from the active list...
+ * Remove the job from the active and printing lists...
*/
cupsArrayRemove(ActiveJobs, job);
+ cupsArrayRemove(PrintingJobs, job);
/*
* Remove any authentication data...
*/
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
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...
*/
- cupsdSaveJob(job);
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
else
{
* Free all memory used...
*/
- free_job(job);
+ cupsdDeleteJob(job);
}
+
+ cupsdSetBusyState();
}
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)))
{
* 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();
}
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()");
*/
cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdCheckJobs: Job %d: state_value=%d, loaded=%s",
- job->id, job->state_value, job->attrs ? "yes" : "no");
+ "cupsdCheckJobs: Job %d: dest=%s, dtype=%x, "
+ "state_value=%d, loaded=%s", job->id, job->dest, job->dtype,
+ job->state_value, job->attrs ? "yes" : "no");
if (job->state_value == IPP_JOB_HELD &&
job->hold_until &&
job->hold_until < time(NULL))
{
+ if (job->pending_timeout)
+ {
+ /* 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");
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+ }
}
/*
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)
* cancel the job...
*/
- cupsdLogMessage(CUPSD_LOG_WARN,
- "Printer/class %s has gone away; cancelling job %d!",
- job->dest, job->id);
+ cupsdLogJob(job, CUPSD_LOG_WARN,
+ "Printer/class %s has gone away; canceling job!",
+ job->dest);
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)
{
* 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);
else
ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
"job-actual-printer-uri", NULL, printer->uri);
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
- if ((!(printer->type & CUPS_PRINTER_REMOTE) && /* Printer is local */
+ if ((!(printer->type & CUPS_PRINTER_DISCOVERED) && /* Printer is local */
printer->state == IPP_PRINTER_IDLE) || /* and idle */
- ((printer->type & CUPS_PRINTER_REMOTE) && /* Printer is remote */
+ ((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);
+ }
}
}
}
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);
+}
+
+
+/*
+ * 'cupsdDeleteJob()' - Free all memory used by a job.
+ */
+
+void
+cupsdDeleteJob(cupsd_job_t *job) /* I - Job */
+{
+ cupsdClearString(&job->username);
+ cupsdClearString(&job->dest);
+ 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 */
+
+ if (job->num_files > 0)
+ {
+ free(job->compressions);
+ free(job->filetypes);
+ }
+
+ ippDelete(job->attrs);
+
+ free(job);
}
void
cupsdFinishJob(cupsd_job_t *job) /* I - Job */
{
- int job_history; /* Did cupsdCancelJob() keep the job? */
cupsd_printer_t *printer; /* Current printer */
+ ipp_attribute_t *attr; /* job-hold-until attribute */
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] File %d is complete.",
- job->id, job->current_file - 1);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "File %d is complete.",
+ job->current_file - 1);
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishJob: job->status is %d",
- job->status);
+ cupsdLogJob(job, 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 ]...",
- job->status_pipes[0], job->status_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "cupsdFinishJob: Closing status pipes [ %d %d ]...",
+ job->status_pipes[0], job->status_pipes[1]);
cupsdClosePipe(job->status_pipes);
cupsdStatBufDelete(job->status_buffer);
printer = job->printer;
+ update_job_attrs(job, 0);
+
if (job->status < 0)
{
/*
else
exit_code = job->status;
- cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Backend returned status %d (%s)",
- job->id, exit_code,
- exit_code == CUPS_BACKEND_FAILED ? "failed" :
- exit_code == CUPS_BACKEND_AUTH_REQUIRED ?
- "authentication required" :
- exit_code == CUPS_BACKEND_HOLD ? "hold job" :
- exit_code == CUPS_BACKEND_STOP ? "stop printer" :
- exit_code == CUPS_BACKEND_CANCEL ? "cancel job" :
- exit_code < 0 ? "crashed" : "unknown");
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Backend returned status %d (%s)",
+ exit_code,
+ exit_code == CUPS_BACKEND_FAILED ? "failed" :
+ exit_code == CUPS_BACKEND_AUTH_REQUIRED ?
+ "authentication required" :
+ exit_code == CUPS_BACKEND_HOLD ? "hold job" :
+ exit_code == CUPS_BACKEND_STOP ? "stop printer" :
+ exit_code == CUPS_BACKEND_CANCEL ? "cancel job" :
+ exit_code < 0 ? "crashed" : "unknown");
/*
* Do what needs to be done...
cupsdStopJob(job, 0);
- if (!(printer->type & CUPS_PRINTER_REMOTE) ||
- (printer->type & CUPS_PRINTER_IMPLICIT))
+ if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
{
/*
* Mark the job as pending again - we'll retry on another
job->state_value = IPP_JOB_PENDING;
}
- cupsdSaveJob(job);
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
/*
- * If the job was queued to a class, try requeuing it... For
- * faxes and retry-job queues, hold the current job for 5 minutes.
+ * If the job was queued to a class or the error policy is
+ * "retry-current-job", try requeuing it... For faxes and retry-job
+ * queues, hold the current job for 5 minutes.
*/
- if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+ if ((job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) ||
+ !strcmp(printer->error_policy, "retry-current-job"))
cupsdCheckJobs();
else if ((printer->type & CUPS_PRINTER_FAX) ||
!strcmp(printer->error_policy, "retry-job"))
* Too many tries...
*/
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Canceling job %d since it could not be sent "
- "after %d tries.",
- job->id, JobRetryLimit);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Canceling job since it could not be "
+ "sent after %d tries.",
+ 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");
- cupsdSaveJob(job);
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ 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);
- cupsdSaveJob(job);
+
+ job->state->values[0].integer = IPP_JOB_PENDING;
+ job->state_value = IPP_JOB_PENDING;
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
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");
- cupsdSaveJob(job);
+
+ cupsdSetJobHoldUntil(job, "auth-info-required");
+
+ 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),
+ "auth-info-required");
+ }
+
+ job->state->values[0].integer = IPP_JOB_HELD;
+ job->state_value = IPP_JOB_HELD;
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
"Authentication is required for job %d.", job->id);
* Filter had errors; stop job...
*/
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Job stopped due to filter errors.");
cupsdStopJob(job, 1);
- cupsdSaveJob(job);
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
"Job stopped due to filter errors; please consult the "
"error_log file for details.");
* 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, "");
-
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Completed successfully.");
+ cupsdCancelJob(job, 0, IPP_JOB_COMPLETED);
cupsdCheckJobs();
}
}
cupsdHoldSignals();
- cupsdStopAllJobs();
+ cupsdStopAllJobs(1);
cupsdSaveAllJobs();
for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
{
cupsArrayRemove(Jobs, job);
cupsArrayRemove(ActiveJobs, job);
+ cupsArrayRemove(PrintingJobs, job);
- free_job(job);
+ cupsdDeleteJob(job);
}
cupsdReleaseSignals();
job->state->values[0].integer = IPP_JOB_HELD;
job->state_value = IPP_JOB_HELD;
+ job->current_file = 0;
- cupsdSaveJob(job);
-
- cupsdCheckJobs();
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
if (!ActiveJobs)
ActiveJobs = cupsArrayNew(compare_active_jobs, NULL);
+ if (!PrintingJobs)
+ PrintingJobs = cupsArrayNew(compare_jobs, NULL);
+
/*
* See whether the job.cache file is older than the RequestRoot directory...
*/
cups_file_t *fp; /* Job file */
int fileid; /* Current file ID */
ipp_attribute_t *attr; /* Job attribute */
- char scheme[32], /* Scheme portion of URI */
- username[64], /* Username portion of URI */
- host[HTTP_MAX_HOST],
- /* Host portion of URI */
- resource[HTTP_MAX_URI];
- /* Resource portion of URI */
- int port; /* Port portion of URI */
- const char *dest; /* Destination */
+ const char *dest; /* Destination name */
+ cupsd_printer_t *destptr; /* Pointer to destination */
mime_type_t **filetypes; /* New filetypes array */
int *compressions; /* New compressions array */
if ((job->attrs = ippNew()) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Ran out of memory for job attributes!");
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Ran out of memory for job attributes!");
return;
}
* Load job attributes...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading attributes for job %d...",
- job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading attributes...");
snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, job->id);
if ((fp = cupsFileOpen(jobfile, "r")) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to open job control file \"%s\" - %s!",
- jobfile, strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to open job control file \"%s\" - %s!",
+ jobfile, strerror(errno));
ippDelete(job->attrs);
job->attrs = NULL;
return;
if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, job->attrs) != IPP_DATA)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to read job control file \"%s\"!",
- jobfile);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to read job control file \"%s\"!",
+ jobfile);
cupsFileClose(fp);
ippDelete(job->attrs);
job->attrs = NULL;
if ((job->state = ippFindAttribute(job->attrs, "job-state",
IPP_TAG_ENUM)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Missing or bad job-state attribute in control "
- "file \"%s\"!",
- jobfile);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Missing or bad job-state attribute in control file!");
ippDelete(job->attrs);
job->attrs = NULL;
unlink(jobfile);
if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
IPP_TAG_URI)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "No job-printer-uri attribute in control file \"%s\"!",
- jobfile);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "No job-printer-uri attribute in control file!");
ippDelete(job->attrs);
job->attrs = NULL;
unlink(jobfile);
return;
}
- httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, scheme,
- sizeof(scheme), username, sizeof(username), host,
- sizeof(host), &port, resource, sizeof(resource));
-
- if ((dest = cupsdValidateDest(host, resource, &(job->dtype),
- NULL)) == NULL)
+ if ((dest = cupsdValidateDest(attr->values[0].string.text, &(job->dtype),
+ &destptr)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to queue job for destination \"%s\"!",
- attr->values[0].string.text);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to queue job for destination \"%s\"!",
+ attr->values[0].string.text);
ippDelete(job->attrs);
job->attrs = NULL;
unlink(jobfile);
cupsdSetString(&job->dest, dest);
}
+ else if ((destptr = cupsdFindDest(job->dest)) == NULL)
+ {
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to queue job for destination \"%s\"!", job->dest);
+ ippDelete(job->attrs);
+ job->attrs = NULL;
+ unlink(jobfile);
+ return;
+ }
job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
IPP_TAG_INTEGER);
if ((attr = ippFindAttribute(job->attrs, "job-priority",
IPP_TAG_INTEGER)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Missing or bad job-priority attribute in control "
- "file \"%s\"!", jobfile);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Missing or bad job-priority attribute in control file!");
ippDelete(job->attrs);
job->attrs = NULL;
unlink(jobfile);
if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name",
IPP_TAG_NAME)) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Missing or bad job-originating-user-name attribute "
- "in control file \"%s\"!", jobfile);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Missing or bad job-originating-user-name attribute in "
+ "control file!");
ippDelete(job->attrs);
job->attrs = NULL;
unlink(jobfile);
if (access(jobfile, 0))
break;
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Auto-typing document file \"%s\"...",
- jobfile);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "Auto-typing document file \"%s\"...", jobfile);
if (fileid > job->num_files)
{
if (!compressions || !filetypes)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Ran out of memory for job file types!");
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Ran out of memory for job file types!");
return;
}
}
}
+ /*
+ * Load authentication information as needed...
+ */
+
+ if (job->state_value < IPP_JOB_STOPPED)
+ {
+ snprintf(jobfile, sizeof(jobfile), "%s/a%05d", RequestRoot, job->id);
+
+ cupsdClearString(&job->auth_username);
+ cupsdClearString(&job->auth_domain);
+ cupsdClearString(&job->auth_password);
+
+ if ((fp = cupsFileOpen(jobfile, "r")) != NULL)
+ {
+ int i, /* Looping var */
+ bytes; /* Size of auth data */
+ char line[255], /* Line from file */
+ data[255]; /* Decoded data */
+
+
+ for (i = 0;
+ i < destptr->num_auth_info_required &&
+ cupsFileGets(fp, line, sizeof(line));
+ i ++)
+ {
+ bytes = sizeof(data);
+ httpDecode64_2(data, &bytes, line);
+
+ if (!strcmp(destptr->auth_info_required[i], "username"))
+ cupsdSetStringf(&job->auth_username, "AUTH_USERNAME=%s", data);
+ else if (!strcmp(destptr->auth_info_required[i], "domain"))
+ cupsdSetStringf(&job->auth_domain, "AUTH_DOMAIN=%s", data);
+ else if (!strcmp(destptr->auth_info_required[i], "password"))
+ cupsdSetStringf(&job->auth_password, "AUTH_PASSWORD=%s", data);
+ }
+
+ cupsFileClose(fp);
+ }
+ }
job->access_time = time(NULL);
}
* 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 #%d moved from %s to %s.", job->id, olddest,
p->name);
- cupsdSaveJob(job);
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
if (job->state_value == IPP_JOB_HELD)
{
+ /*
+ * Add trailing banner as needed...
+ */
+
+ if (job->pending_timeout)
+ cupsdTimeoutJob(job);
+
DEBUG_puts("cupsdReleaseJob: setting state to pending...");
job->state->values[0].integer = IPP_JOB_PENDING;
job->state_value = IPP_JOB_PENDING;
- cupsdSaveJob(job);
- cupsdCheckJobs();
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_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);
- cupsdCheckJobs();
+
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+
+ if (old_state > IPP_JOB_STOPPED)
+ cupsArrayAdd(ActiveJobs, job);
}
}
if ((fp = cupsFileOpen(filename, "w")) == NULL)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to create job control file \"%s\" - %s.",
- filename, strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to create job control file \"%s\" - %s.",
+ filename, strerror(errno));
return;
}
if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
job->attrs) != IPP_DATA)
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write job control file \"%s\"!",
- filename);
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to write job control file!");
cupsFileClose(fp);
+
+ job->dirty = 0;
}
second = 0;
- if (!strcmp(when, "indefinite") || !strcmp(when, "authenticated"))
+ if (!strcmp(when, "indefinite") || !strcmp(when, "auth-info-required"))
{
/*
* Hold indefinitely...
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",
cupsArrayAdd(ActiveJobs, job);
- cupsdSaveJob(job);
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
*/
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;
}
int i; /* Looping var */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopJob: id = %d, force = %d",
- job->id, force);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "cupsdStopJob: force = %d", force);
if (job->state_value != IPP_JOB_PROCESSING)
return;
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;
job->backend = 0;
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopJob: Closing print pipes [ %d %d ]...",
- job->print_pipes[0], job->print_pipes[1]);
+ cupsdDestroyProfile(job->profile);
+ job->profile = NULL;
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Closing print pipes [ %d %d ]...",
+ job->print_pipes[0], job->print_pipes[1]);
cupsdClosePipe(job->print_pipes);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "cupsdStopJob: Closing back pipes [ %d %d ]...",
- job->back_pipes[0], job->back_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Closing back pipes [ %d %d ]...",
+ job->back_pipes[0], job->back_pipes[1]);
cupsdClosePipe(job->back_pipes);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "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 ]...",
- job->status_pipes[0], job->status_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Closing status pipes [ %d %d ]...",
+ job->status_pipes[0], job->status_pipes[1]);
cupsdClosePipe(job->status_pipes);
cupsdStatBufDelete(job->status_buffer);
job = (cupsd_job_t *)cupsArrayNext(Jobs))
if (job->attrs && job->state_value >= IPP_JOB_STOPPED &&
job->access_time < expire)
+ {
+ if (job->dirty)
+ cupsdSaveJob(job);
+
unload_job(job);
+ }
}
/*
- * 'cupsdUpdateJob()' - Read a status update from a job's filters.
+ * 'compare_active_jobs()' - Compare the job IDs and priorities of two jobs.
*/
-void
-cupsdUpdateJob(cupsd_job_t *job) /* I - Job to check */
+static int /* O - Difference */
+compare_active_jobs(void *first, /* I - First job */
+ void *second, /* I - Second job */
+ void *data) /* I - App data (not used) */
{
- int i; /* Looping var */
- int copies; /* Number of copies printed */
- char message[1024], /* Message text */
- *ptr; /* Pointer update... */
- int loglevel; /* Log level for message */
+ int diff; /* Difference */
- while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel,
- message, sizeof(message))) != NULL)
- {
- /*
- * Process page and printer state messages as needed...
- */
+ 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);
+}
- 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...
- */
+/*
+ * 'compare_jobs()' - Compare the job IDs of two jobs.
+ */
- 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;
+static int /* O - Difference */
+compare_jobs(void *first, /* I - First job */
+ void *second, /* I - Second job */
+ void *data) /* I - App data (not used) */
+{
+ return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
+}
- 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.
- */
-
-static int /* O - Difference */
-compare_active_jobs(void *first, /* I - First job */
- void *second, /* I - Second job */
- void *data) /* I - App data (not used) */
-{
- int diff; /* Difference */
-
-
- 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);
-}
-
-
-/*
- * 'compare_jobs()' - Compare the job IDs of two jobs.
- */
-
-static int /* O - Difference */
-compare_jobs(void *first, /* I - First job */
- void *second, /* I - Second job */
- void *data) /* I - App data (not used) */
-{
- return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
-}
-
-
-/*
- * 'free_job()' - Free all memory used by a job.
- */
-
-static void
-free_job(cupsd_job_t *job) /* I - Job */
-{
- cupsdClearString(&job->username);
- cupsdClearString(&job->dest);
-
- if (job->num_files > 0)
- {
- free(job->compressions);
- free(job->filetypes);
- }
-
- ippDelete(job->attrs);
-
- free(job);
-}
-
-
-/*
- * 'ipp_length()' - Compute the size of the buffer needed to hold
- * the textual IPP attributes.
- */
+/*
+ * 'ipp_length()' - Compute the size of the buffer needed to hold
+ * the textual IPP attributes.
+ */
static int /* O - Size of attribute buffer */
ipp_length(ipp_t *ipp) /* I - IPP request */
snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, jobid);
if (access(jobfile, 0))
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Job %d files have gone away!", jobid);
+ cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Files have gone away!",
+ jobid);
continue;
}
if (!job)
{
cupsdLogMessage(CUPSD_LOG_EMERG,
- "Unable to allocate memory for job %d!", jobid);
+ "[Job %d] Unable to allocate memory for job!", jobid);
break;
}
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;
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading job %d from cache...", job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading from cache...");
}
else if (!job)
{
}
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->id);
if (access(jobfile, 0))
{
- cupsdLogMessage(CUPSD_LOG_INFO,
- "Data files for job %d have gone away!", job->id);
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Data files have gone away!");
job->num_files = 0;
continue;
}
if (!job->filetypes || !job->compressions)
{
- cupsdLogMessage(CUPSD_LOG_EMERG,
- "Unable to allocate memory for %d files!",
- job->num_files);
+ cupsdLogJob(job, CUPSD_LOG_EMERG,
+ "Unable to allocate memory for %d files!",
+ job->num_files);
break;
}
}
* If the original MIME type is unknown, auto-type it!
*/
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unknown MIME type %s/%s for file %d of job %d!",
- super, type, number + 1, job->id);
+ 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);
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",
*/
if (attr == NULL)
- attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
- "job-hold-until", NULL, holdstr);
+ ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-hold-until",
+ NULL, holdstr);
else
cupsdSetString(&attr->values[0].string.text, holdstr);
- cupsdSaveJob(job);
+ job->dirty = 1;
+ cupsdMarkDirty(CUPSD_DIRTY_JOBS);
}
{
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 + 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 */
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 */
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: id = %d, file = %d/%d",
- job->id, job->current_file, job->num_files);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "start_job: file = %d/%d",
+ job->current_file, job->num_files);
if (job->num_files == 0)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Job ID %d has no files! Cancelling 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);
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "No files, canceling job!");
+ cupsdCancelJob(job, 0, IPP_JOB_ABORTED);
return;
}
* filtering...
*/
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Job %d] Sending job to queue tagged as raw...", job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Sending job to queue tagged as raw...");
filters = NULL;
}
if (!filters)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to convert file %d to printable format for "
- "job %d!",
- job->current_file, job->id);
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to convert file %d to printable format!",
+ job->current_file);
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,
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;
+ }
}
/*
cupsArrayDelete(filters);
- cupsdLogMessage(CUPSD_LOG_INFO,
- "Holding job %d because filter limit has been reached.",
- job->id);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: id=%d, file=%d, cost=%d, level=%d, "
- "limit=%d",
- job->id, job->current_file, job->cost, FilterLevel,
- FilterLimit);
+ cupsdLogJob(job, CUPSD_LOG_INFO,
+ "Holding because filter limit has been reached.");
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: file=%d, cost=%d, level=%d, limit=%d",
+ job->current_file, job->cost, FilterLevel,
+ FilterLimit);
return;
}
FilterLevel += job->cost;
/*
- * Determine if we are printing to a remote printer...
+ * Add decompression/raw filter as needed...
*/
- remote_job = printer->raw && job->num_files > 1 &&
- !strncmp(printer->device_uri, "ipp://", 6);
-
- /*
- * Add decompression filters, if any...
- */
-
- 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,
- "Unable to add decompression filter - %s",
- strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to add decompression filter - %s", strerror(errno));
cupsArrayDelete(filters);
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);
+
+ port_monitor.src = NULL;
+ port_monitor.dst = NULL;
+ port_monitor.cost = 0;
+
+ snprintf(port_monitor.filter, sizeof(port_monitor.filter),
+ "%s/monitor/%s", ServerBin, printer->port_monitor);
+
if (!cupsArrayAdd(filters, &port_monitor))
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add port monitor - %s",
- strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to add port monitor - %s", strerror(errno));
cupsArrayDelete(filters);
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;
}
+ }
- snprintf(port_monitor.filter, sizeof(port_monitor.filter),
- "%s/monitor/%s", ServerBin, printer->port_monitor);
+ /*
+ * Make sure we don't go over the "MAX_FILTERS" limit...
+ */
+
+ if (cupsArrayCount(filters) > MAX_FILTERS)
+ {
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Too many filters (%d > %d), unable to print!",
+ cupsArrayCount(filters), MAX_FILTERS);
+
+ cupsArrayDelete(filters);
+ cupsdCancelJob(job, 0, IPP_JOB_STOPPED);
+
+ 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)
{
+ /*
+ * Add to the printing list...
+ */
+
+ cupsArrayAdd(PrintingJobs, job);
+ cupsdSetBusyState();
+
/*
* Set the processing time...
*/
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);
}
/*
if (job->job_sheets == NULL)
{
- cupsdLogMessage(CUPSD_LOG_DEBUG, "No job-sheets attribute.");
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "No job-sheets attribute.");
if ((job->job_sheets =
ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "... but someone added one without setting job_sheets!");
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "... but someone added one without setting job_sheets!");
}
else if (job->job_sheets->num_values == 1)
- cupsdLogMessage(CUPSD_LOG_DEBUG, "job-sheets=%s",
- job->job_sheets->values[0].string.text);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-sheets=%s",
+ job->job_sheets->values[0].string.text);
else
- cupsdLogMessage(CUPSD_LOG_DEBUG, "job-sheets=%s,%s",
- job->job_sheets->values[0].string.text,
- job->job_sheets->values[1].string.text);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-sheets=%s,%s",
+ job->job_sheets->values[0].string.text,
+ job->job_sheets->values[1].string.text);
if (printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
banner_page = 0;
else
banner_page = 0;
- cupsdLogMessage(CUPSD_LOG_DEBUG, "banner_page = %d", banner_page);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "banner_page = %d", banner_page);
/*
* Building the options string is harder than it needs to be, but
i = ipp_length(job->attrs);
- if (i > optlength)
+ if (i > optlength || !options)
{
if (optlength == 0)
optptr = malloc(i);
if (optptr == NULL)
{
- cupsdLogMessage(CUPSD_LOG_CRIT,
- "Unable to allocate %d bytes for option buffer for "
- "job %d!", i, job->id);
+ cupsdLogJob(job, CUPSD_LOG_CRIT,
+ "Unable to allocate %d bytes for option buffer!", i);
cupsArrayDelete(filters);
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;
}
continue;
if (!strncmp(attr->name, "job-", 4) && strcmp(attr->name, "job-uuid") &&
+ strcmp(attr->name, "job-impressions") &&
+ strcmp(attr->name, "job-originating-host-name") &&
!(printer->type & CUPS_PRINTER_REMOTE))
continue;
if (!strncmp(attr->name, "job-", 4) &&
strcmp(attr->name, "job-uuid") &&
strcmp(attr->name, "job-billing") &&
+ strcmp(attr->name, "job-impressions") &&
strcmp(attr->name, "job-sheets") &&
strcmp(attr->name, "job-hold-until") &&
strcmp(attr->name, "job-priority"))
continue;
- if ((!strcmp(attr->name, "page-label") ||
+ if ((!strcmp(attr->name, "job-impressions") ||
+ !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")) &&
+ !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;
* 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 *));
+ 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;
argv[4] = copies;
argv[5] = options;
- if (remote_job)
+ if (printer->remote && job->num_files > 1)
{
for (i = 0; i < job->num_files; i ++)
{
}
for (i = 0; argv[i]; i ++)
- cupsdLogMessage(CUPSD_LOG_DEBUG,
- "[Job %d] argv[%d]=\"%s\"", job->id, i, argv[i]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG,
+ "argv[%d]=\"%s\"", i, argv[i]);
/*
* Create environment variable strings for the filters...
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 ++] = device_uri;
envp[envc ++] = printer_name;
- if ((filter = (mime_filter_t *)cupsArrayLast(filters)) != NULL)
+ if (!printer->remote && !printer->raw)
{
- snprintf(final_content_type, sizeof(final_content_type),
- "FINAL_CONTENT_TYPE=%s/%s",
- filter->src->super, filter->src->type);
- envp[envc ++] = final_content_type;
+ filter = (mime_filter_t *)cupsArrayLast(filters);
+
+ if (printer->port_monitor)
+ filter = (mime_filter_t *)cupsArrayPrev(filters);
+
+ if (filter && filter->dst)
+ {
+ snprintf(final_content_type, sizeof(final_content_type),
+ "FINAL_CONTENT_TYPE=%s/%s",
+ filter->dst->super, filter->dst->type);
+ envp[envc ++] = final_content_type;
+ }
}
if (Classification && !banner_page)
envp[envc ++] = class_name;
}
+ if (job->auth_username)
+ envp[envc ++] = job->auth_username;
+ if (job->auth_domain)
+ envp[envc ++] = job->auth_domain;
+ if (job->auth_password)
+ envp[envc ++] = job->auth_password;
+
+#ifdef HAVE_GSSAPI
+ if (job->ccname)
+ envp[envc ++] = job->ccname;
+#endif /* HAVE_GSSAPI */
+
envp[envc] = NULL;
for (i = 0; i < envc; i ++)
- if (strncmp(envp[i], "DEVICE_URI=", 11))
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"%s\"",
- job->id, i, envp[i]);
+ if (!strncmp(envp[i], "AUTH_", 5))
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"AUTH_%c****\"", i,
+ envp[i][5]);
+ else if (strncmp(envp[i], "DEVICE_URI=", 11))
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"%s\"", i, envp[i]);
else
- cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"DEVICE_URI=%s\"",
- job->id, i, sani_uri);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"DEVICE_URI=%s\"", i,
+ sani_uri);
- if (remote_job)
+ if (printer->remote)
job->current_file = job->num_files;
else
job->current_file ++;
{
if (cupsdOpenPipe(job->status_pipes))
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create job status pipes - %s.",
- strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to create job status pipes - %s.", 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);
+
+ cupsdLogJob(job, 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], NULL);
+ job->status_level = CUPSD_LOG_INFO;
}
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))
{
if (cupsdOpenPipe(filterfds[slot]))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to create job filter pipes - %s.",
- strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to create job filter pipes - %s.", strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to create filter pipes - %s.", strerror(errno));
cupsdAddPrinterHistory(printer);
{
if (cupsdOpenPipe(job->print_pipes))
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to create job backend pipes - %s.",
- strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR,
+ "Unable to create job backend pipes - %s.",
+ strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to create backend pipes - %s.", strerror(errno));
cupsdAddPrinterHistory(printer);
if (job->print_pipes[1] < 0)
{
- cupsdLogMessage(CUPSD_LOG_ERROR,
- "Unable to open output file \"%s\" - %s.",
- printer->device_uri, strerror(errno));
+ cupsdLogJob(job, 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));
}
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: print_pipes = [ %d %d ]",
- job->print_pipes[0], job->print_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: print_pipes = [ %d %d ]",
+ job->print_pipes[0], job->print_pipes[1]);
}
filterfds[slot][0] = job->print_pipes[0];
filterfds[slot][1] = job->print_pipes[1];
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: filter=\"%s\"",
- command);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: filterfds[%d]=[ %d %d ]",
- slot, filterfds[slot][0], filterfds[slot][1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "start_job: filter=\"%s\"", command);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "start_job: filterfds[%d]=[ %d %d ]",
+ slot, filterfds[slot][0], filterfds[slot][1]);
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->profile, job->filters + i);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing filter pipes for slot %d "
- "[ %d %d ]...",
- !slot, filterfds[!slot][0], filterfds[!slot][1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing filter pipes for slot %d [ %d %d ]...",
+ !slot, filterfds[!slot][0], filterfds[!slot][1]);
cupsdClosePipe(filterfds[!slot]);
if (pid == 0)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to start filter \"%s\" - %s.",
- filter->filter, strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to start filter \"%s\" - %s.",
+ filter->filter, strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to start filter \"%s\" - %s.",
filter->filter, strerror(errno));
goto abort_job;
}
- cupsdLogMessage(CUPSD_LOG_INFO, "Started filter %s (PID %d) for job %d.",
- command, pid, job->id);
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Started filter %s (PID %d)", command,
+ pid);
argv[6] = NULL;
slot = !slot;
}
cupsArrayDelete(filters);
+ filters = NULL;
/*
* Finally, pipe the final output into a backend process if needed...
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);
filterfds[slot][0] = -1;
filterfds[slot][1] = -1;
- cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job: backend=\"%s\"",
- command);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: filterfds[%d] = [ %d %d ]",
- slot, filterfds[slot][0], filterfds[slot][1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "start_job: backend=\"%s\"", command);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2, "start_job: filterfds[%d] = [ %d %d ]",
+ slot, filterfds[slot][0], filterfds[slot][1]);
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->profile, &(job->backend));
if (pid == 0)
{
- cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to start backend \"%s\" - %s.",
- method, strerror(errno));
+ cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to start backend \"%s\" - %s.",
+ method, strerror(errno));
snprintf(printer->state_message, sizeof(printer->state_message),
"Unable to start backend \"%s\" - %s.", method,
strerror(errno));
}
else
{
- cupsdLogMessage(CUPSD_LOG_INFO,
- "Started backend %s (PID %d) for job %d.",
- command, pid, job->id);
+ cupsdLogJob(job, CUPSD_LOG_INFO, "Started backend %s (PID %d)",
+ command, pid);
}
}
if (job->current_file == job->num_files)
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing print pipes [ %d %d ]...",
- job->print_pipes[0], job->print_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing print pipes [ %d %d ]...",
+ job->print_pipes[0], job->print_pipes[1]);
cupsdClosePipe(job->print_pipes);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing back pipes [ %d %d ]...",
- job->back_pipes[0], job->back_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing back pipes [ %d %d ]...",
+ job->back_pipes[0], job->back_pipes[1]);
cupsdClosePipe(job->back_pipes);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing status output pipe %d...",
- job->status_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing side pipes [ %d %d ]...",
+ job->side_pipes[0], job->side_pipes[1]);
+
+ cupsdClosePipe(job->side_pipes);
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing status output pipe %d...",
+ job->status_pipes[1]);
close(job->status_pipes[1]);
job->status_pipes[1] = -1;
if (job->current_file == job->num_files)
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing print pipes [ %d %d ]...",
- job->print_pipes[0], job->print_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing print pipes [ %d %d ]...",
+ job->print_pipes[0], job->print_pipes[1]);
cupsdClosePipe(job->print_pipes);
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing status output pipe %d...",
- job->status_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing status output pipe %d...",
+ job->status_pipes[1]);
close(job->status_pipes[1]);
job->status_pipes[1] = -1;
}
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing filter pipes for slot %d "
- "[ %d %d ]...",
- slot, filterfds[slot][0], filterfds[slot][1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing filter pipes for slot %d [ %d %d ]...",
+ 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);
for (slot = 0; slot < 2; slot ++)
{
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing filter pipes for slot %d "
- "[ %d %d ]...",
- slot, filterfds[slot][0], filterfds[slot][1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing filter pipes for slot %d [ %d %d ]...",
+ slot, filterfds[slot][0], filterfds[slot][1]);
cupsdClosePipe(filterfds[slot]);
}
- cupsdLogMessage(CUPSD_LOG_DEBUG2,
- "start_job: Closing status pipes [ %d %d ]...",
- job->status_pipes[0], job->status_pipes[1]);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG2,
+ "start_job: Closing status pipes [ %d %d ]...",
+ job->status_pipes[0], job->status_pipes[1]);
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]);
if (!job->attrs)
return;
- cupsdLogMessage(CUPSD_LOG_DEBUG, "Unloading job %d...", job->id);
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "Unloading...");
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;
+}
+
+
+/*
+ * '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...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "PAGE: %s", message);
+
+ if (job->sheets)
+ {
+ 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...
+ */
+
+ cupsdLogJob(job, CUPSD_LOG_INFO,
+ "Canceled because pages exceed user %s "
+ "quota limit on printer %s (%s).",
+ job->username, job->printer->name,
+ job->printer->info);
+
+ cupsdCancelJob(job, 1, IPP_JOB_CANCELED);
+ return;
+ }
+#else
+ (void)q;
+#endif /* __APPLE__ */
+ }
+ }
+
+ cupsdLogPage(job, message);
+
+ 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)
+ {
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "STATE: %s", message);
+
+ if (!strcmp(message, "paused"))
+ {
+ cupsdStopPrinter(job->printer, 1);
+ return;
+ }
+ else
+ {
+ cupsdSetPrinterReasons(job->printer, message);
+ cupsdAddPrinterHistory(job->printer);
+ event |= CUPSD_EVENT_PRINTER_STATE;
+ }
+
+ update_job_attrs(job, 0);
+ }
+ else if (loglevel == CUPSD_LOG_ATTR)
+ {
+ /*
+ * Set attribute(s)...
+ */
+
+ int num_attrs; /* Number of attributes */
+ cups_option_t *attrs; /* Attributes */
+ const char *attr; /* Attribute */
+
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "ATTR: %s", message);
+
+ num_attrs = cupsParseOptions(message, 0, &attrs);
+
+ if ((attr = cupsGetOption("auth-info-required", num_attrs,
+ attrs)) != NULL)
+ {
+ cupsdSetAuthInfoRequired(job->printer, attr, NULL);
+ cupsdSetPrinterAttrs(job->printer);
+
+ if (job->printer->type & CUPS_PRINTER_DISCOVERED)
+ cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
+ else
+ cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+ }
+
+ if ((attr = cupsGetOption("printer-alert", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetString(&job->printer->alert, attr);
+ 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;
+ }
+
+ 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-message", num_attrs, attrs)) != NULL)
+ {
+ cupsdSetPrinterAttr(job->printer, "marker-message", (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);
+ }
+ else if (loglevel == CUPSD_LOG_PPD)
+ {
+ /*
+ * Set attribute(s)...
+ */
+
+ int num_keywords; /* Number of keywords */
+ cups_option_t *keywords; /* Keywords */
+
+
+ cupsdLogJob(job, CUPSD_LOG_DEBUG, "PPD: %s", message);
+
+ num_keywords = cupsParseOptions(message, 0, &keywords);
+
+ if (cupsdUpdatePrinterPPD(job->printer, num_keywords, keywords))
+ cupsdSetPrinterAttrs(job->printer);
+
+ cupsFreeOptions(num_keywords, keywords);
+ }
+#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;
+ }
+ 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;
+ }
+#endif /* __APPLE__ */
+ else
+ {
+ cupsdLogJob(job, loglevel, "%s", message);
+
+ if (loglevel < CUPSD_LOG_DEBUG)
+ {
+ strlcpy(job->printer->state_message, message,
+ sizeof(job->printer->state_message));
+ cupsdAddPrinterHistory(job->printer);
+
+ event |= CUPSD_EVENT_PRINTER_STATE;
+
+ if (loglevel <= job->status_level)
+ {
+ /*
+ * Some messages show in the printer-state-message attribute...
+ */
+
+ if (loglevel != CUPSD_LOG_NOTICE)
+ job->status_level = loglevel;
+
+ update_job_attrs(job, 1);
+ }
+ }
+ }
+
+ if (!strchr(job->status_buffer->buffer, '\n'))
+ break;
+ }
+
+ 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.",
+ 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);
+ }
+}
+
+
+/*
+ * 'update_job_attrs()' - Update the job-printer-* attributes.
+ */
+
+void
+update_job_attrs(cupsd_job_t *job, /* I - Job to update */
+ int do_message)/* I - 1 = update job-printer-state message */
+{
+ 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] &&
+ (do_message || !job->printer_message->values[0].string.text[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 5719 2006-07-11 21:04:48Z mike $".
+ * End of "$Id: job.c 7682 2008-06-21 00:06:02Z mike $".
*/