diff options
Diffstat (limited to 'scheduler/job.c')
-rw-r--r-- | scheduler/job.c | 1467 |
1 files changed, 1075 insertions, 392 deletions
diff --git a/scheduler/job.c b/scheduler/job.c index cdeaec6d6..0c65f3e34 100644 --- a/scheduler/job.c +++ b/scheduler/job.c @@ -1,5 +1,5 @@ /* - * "$Id: job.c 5051 2006-02-02 16:13:16Z mike $" + * "$Id: job.c 5131 2006-02-18 05:31:36Z mike $" * * Job management routines for the Common UNIX Printing System (CUPS). * @@ -25,35 +25,47 @@ * * cupsdAddJob() - Add a new job to the job queue... * cupsdCancelJob() - Cancel the specified print job. - * cupsdCancelJobs() - Cancel all jobs for the given destination/user... - * cupsdCheckJobs() - Check the pending jobs and start any if the - * destination is available. + * cupsdCancelJobs() - Cancel all jobs for the given + * destination/user... + * cupsdCheckJobs() - Check the pending jobs and start any if + * the destination is available. * cupsdCleanJobs() - Clean out old jobs. + * cupsdFinishJob() - Finish a job. * cupsdFreeAllJobs() - Free all jobs from memory. * cupsdFindJob() - Find the specified job. * cupsdGetPrinterJobCount() - Get the number of pending, processing, - * or held jobs in a printer or class. * cupsdGetUserJobCount() - Get the number of pending, processing, - * or held jobs for a user. * cupsdHoldJob() - Hold the specified job. * cupsdLoadAllJobs() - Load all jobs from disk. + * cupsdLoadJob() - Load a single job... * cupsdMoveJob() - Move the specified job to a different * destination. * cupsdReleaseJob() - Release the specified job. * cupsdRestartJob() - Restart the specified job. + * cupsdSaveAllJobs() - Save a summary of all jobs to disk. * cupsdSaveJob() - Save a job to disk. * cupsdSetJobHoldUntil() - Set the hold time for a job... - * cupsdSetJobPriority() - Set the priority of a job, moving it up/down - * in the list as needed. + * cupsdSetJobPriority() - Set the priority of a job, moving it + * up/down in the list as needed. * cupsdStartJob() - Start a print job. * cupsdStopAllJobs() - Stop all print jobs. * cupsdStopJob() - Stop a print job. - * cupsdUpdateJob() - Read a status update from a job's filters. - * compare_active_jobs() - Compare the job IDs and priorities of two jobs. + * cupsdUnloadCompletedJobs() - Flush completed job history from memory. + * cupsdUnloadJob() - Unload a job 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. - * ipp_length() - Compute the size of the buffer needed to hold - * the textual IPP attributes. - * set_hold_until() - Set the hold time and update job-hold-until attribute. + * 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. + * load_next_job_id() - Load the NextJobId value from the + * job.cache file. + * load_request_root() - Load jobs from the RequestRoot directory. + * set_time() - Set one of the "time-at-xyz" attributes... + * set_hold_until() - Set the hold time and update job-hold-until + * attribute... */ /* @@ -85,7 +97,11 @@ static mime_filter_t gziptoany_filter = 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 load_request_root(void); static void set_time(cupsd_job_t *job, const char *name); static void set_hold_until(cupsd_job_t *job, time_t holdtime); @@ -135,35 +151,37 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ char filename[1024]; /* Job filename */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCancelJob: id = %d", job->id); - - /* - * Remove the job from the active list... - */ - - cupsArrayRemove(ActiveJobs, job); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCancelJob: id = %d", job->id); /* * Stop any processes that are working on the current job... */ - if (job->state->values[0].integer == IPP_JOB_PROCESSING) + if (job->state_value == IPP_JOB_PROCESSING) cupsdStopJob(job, 0); - cupsArrayRemove(ActiveJobs, job); + cupsdLoadJob(job); + + if (job->attrs) + job->state->values[0].integer = IPP_JOB_CANCELLED; - job->state->values[0].integer = IPP_JOB_CANCELLED; + job->state_value = IPP_JOB_CANCELLED; set_time(job, "time-at-completed"); cupsdExpireSubscriptions(NULL, job); /* + * Remove the job from the active list... + */ + + cupsArrayRemove(ActiveJobs, job); + + /* * Remove any authentication data... */ - snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, - job->id); + snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id); unlink(filename); /* @@ -173,8 +191,8 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ job->current_file = 0; - if (!JobHistory || !JobFiles || purge || - (job->dtype & CUPS_PRINTER_REMOTE)) + if (!JobHistory || !JobFiles || purge || (job->dtype & CUPS_PRINTER_REMOTE)) + { for (i = 1; i <= job->num_files; i ++) { snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, @@ -182,6 +200,17 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ unlink(filename); } + if (job->num_files > 0) + { + free(job->filetypes); + free(job->compressions); + + job->num_files = 0; + job->filetypes = NULL; + job->compressions = NULL; + } + } + if (JobHistory && !purge && !(job->dtype & CUPS_PRINTER_REMOTE)) { /* @@ -210,19 +239,7 @@ cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ * Free all memory used... */ - if (job->attrs != NULL) - ippDelete(job->attrs); - - if (job->num_files > 0) - { - free(job->compressions); - free(job->filetypes); - } - - cupsdClearString(&job->username); - cupsdClearString(&job->dest); - - free(job); + free_job(job); } } @@ -274,6 +291,10 @@ cupsdCheckJobs(void) DEBUG_puts("cupsdCheckJobs()"); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCheckJobs: %d active jobs, sleeping=%d, reload=%d", + cupsArrayCount(ActiveJobs), Sleeping, NeedReload); + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) @@ -282,17 +303,23 @@ cupsdCheckJobs(void) * Start held jobs if they are ready... */ - if (job->state->values[0].integer == IPP_JOB_HELD && + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCheckJobs: Job %d: state_value=%d, loaded=%s", + job->id, job->state_value, job->attrs ? "yes" : "no"); + + if (job->state_value == IPP_JOB_HELD && job->hold_until && job->hold_until < time(NULL)) + { job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; + } /* * Start pending jobs if the destination is available... */ - if (job->state->values[0].integer == IPP_JOB_PENDING && !NeedReload && - !Sleeping) + if (job->state_value == IPP_JOB_PENDING && !NeedReload && !Sleeping) { printer = cupsdFindDest(job->dest); pclass = NULL; @@ -327,7 +354,8 @@ cupsdCheckJobs(void) job->dest, job->id); cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled because the destination printer/class has gone away."); + "Job canceled because the destination printer/class has " + "gone away."); cupsdCancelJob(job, 1); } @@ -358,7 +386,7 @@ cupsdCheckJobs(void) if (printer->state == IPP_PRINTER_IDLE || /* Printer is idle */ ((printer->type & CUPS_PRINTER_REMOTE) && /* Printer is remote */ - !printer->job)) /* and not printing a job */ + !printer->job)) /* and not printing */ cupsdStartJob(job, printer); } } @@ -376,13 +404,13 @@ cupsdCleanJobs(void) cupsd_job_t *job; /* Current job */ - if (!MaxJobs) + if (MaxJobs <= 0) return; for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); job && cupsArrayCount(Jobs) >= MaxJobs; job = (cupsd_job_t *)cupsArrayNext(Jobs)) - if (job->state->values[0].integer >= IPP_JOB_CANCELLED) + if (job->state_value >= IPP_JOB_CANCELLED) cupsdCancelJob(job, 1); } @@ -398,8 +426,7 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ cupsd_printer_t *printer; /* Current printer */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdFinishJob: job %d, file %d is complete.", + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] File %d is complete.", job->id, job->current_file - 1); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishJob: job->status is %d", @@ -445,6 +472,7 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ cupsdStopJob(job, 0); job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; cupsdSaveJob(job); /* @@ -471,11 +499,13 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ */ cupsdLogMessage(CUPSD_LOG_ERROR, - "Canceling job %d since it could not be sent after %d tries.", + "Canceling job %d since it could not be sent " + "after %d tries.", job->id, JobRetryLimit); - cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled since it could not be sent after %d tries.", + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, printer, job, + "Job canceled since it could not be sent after %d " + "tries.", JobRetryLimit); cupsdCancelJob(job, 0); @@ -545,7 +575,7 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ cupsdStopJob(job, 1); cupsdSaveJob(job); - cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, job->printer, job, + cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, "Job stopped due to filter errors; please consult the " "error_log file for details."); cupsdCheckJobs(); @@ -563,7 +593,7 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ */ FilterLevel -= job->cost; - cupsdStartJob(job, job->printer); + cupsdStartJob(job, printer); } else { @@ -571,7 +601,7 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ * Close out this job... */ - cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, printer, job, "Job completed successfully."); job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE); @@ -581,15 +611,18 @@ cupsdFinishJob(cupsd_job_t *job) /* I - Job */ 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 move on... + * Clear the printer's state_message and state_reasons and move on... */ printer->state_message[0] = '\0'; + cupsdSetPrinterReasons(printer, ""); + cupsdCheckJobs(); } } @@ -606,9 +639,13 @@ cupsdFreeAllJobs(void) cupsd_job_t *job; /* Current job */ + if (!Jobs) + return; + cupsdHoldSignals(); cupsdStopAllJobs(); + cupsdSaveAllJobs(); for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); job; @@ -617,15 +654,7 @@ cupsdFreeAllJobs(void) cupsArrayRemove(Jobs, job); cupsArrayRemove(ActiveJobs, job); - ippDelete(job->attrs); - - if (job->num_files > 0) - { - free(job->compressions); - free(job->filetypes); - } - - free(job); + free_job(job); } cupsdReleaseSignals(); @@ -664,7 +693,7 @@ cupsdGetPrinterJobCount( for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0; job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) - if (!strcasecmp(job->dest, dest)) + if (job->dest && !strcasecmp(job->dest, dest)) count ++; return (count); @@ -701,14 +730,17 @@ cupsdGetUserJobCount( void cupsdHoldJob(cupsd_job_t *job) /* I - Job data */ { - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdHoldJob: id = %d", job->id); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdHoldJob: id = %d", job->id); - if (job->state->values[0].integer == IPP_JOB_PROCESSING) + if (job->state_value == IPP_JOB_PROCESSING) cupsdStopJob(job, 0); + else + cupsdLoadJob(job); DEBUG_puts("cupsdHoldJob: setting state to held..."); job->state->values[0].integer = IPP_JOB_HELD; + job->state_value = IPP_JOB_HELD; cupsdSaveJob(job); @@ -723,30 +755,14 @@ cupsdHoldJob(cupsd_job_t *job) /* I - Job data */ void cupsdLoadAllJobs(void) { - cups_dir_t *dir; /* Directory */ - cups_dentry_t *dent; /* Directory entry */ - char filename[1024]; /* Full filename of job file */ - cups_file_t *fp; /* Job file */ - cupsd_job_t *job; /* New job */ - int jobid, /* Current job ID */ - fileid; /* Current file ID */ - ipp_attribute_t *attr; /* Job attribute */ - char method[HTTP_MAX_URI], - /* Method portion of URI */ - username[HTTP_MAX_URI], - /* Username portion of URI */ - host[HTTP_MAX_URI], - /* Host portion of URI */ - resource[HTTP_MAX_URI]; - /* Resource portion of URI */ - int port; /* Port portion of URI */ - const char *dest; /* Destination */ - mime_type_t **filetypes; /* New filetypes array */ - int *compressions; /* New compressions array */ + char filename[1024]; /* Full filename of job.cache file */ + struct stat fileinfo, /* Information on job.cache file */ + dirinfo; /* Information on RequestRoot dir */ + /* - * First create the job lists... + * Create the job arrays as needed... */ if (!Jobs) @@ -756,234 +772,251 @@ cupsdLoadAllJobs(void) ActiveJobs = cupsArrayNew(compare_active_jobs, NULL); /* - * Then open the requests directory... + * See whether the job.cache file is older than the RequestRoot directory... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdLoadAllJobs: Scanning %s...", - RequestRoot); + snprintf(filename, sizeof(filename), "%s/job.cache", CacheDir); - if ((dir = cupsDirOpen(RequestRoot)) == NULL) + if (stat(filename, &fileinfo)) { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Unable to open spool directory %s: %s", - RequestRoot, strerror(errno)); - return; + fileinfo.st_mtime = 0; + + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to get file information for \"%s\" - %s", + filename, strerror(errno)); + } + + if (stat(RequestRoot, &dirinfo)) + { + dirinfo.st_mtime = 0; + + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to get directory information for \"%s\" - %s", + RequestRoot, strerror(errno)); } /* - * Read all the c##### files... + * Load the most recent source for job data... */ - while ((dent = cupsDirRead(dir)) != NULL) - if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c') - { - /* - * Allocate memory for the job... - */ + if (dirinfo.st_mtime > fileinfo.st_mtime) + { + load_request_root(); - if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Ran out of memory for jobs!"); - cupsDirClose(dir); - return; - } + load_next_job_id(filename); + } + else + load_job_cache(filename); - if ((job->attrs = ippNew()) == NULL) - { - free(job); - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Ran out of memory for job attributes!"); - cupsDirClose(dir); - return; - } + /* + * Clean out old jobs as needed... + */ - /* - * Assign the job ID... - */ + if (MaxJobs > 0 && cupsArrayCount(Jobs) >= MaxJobs) + cupsdCleanJobs(); +} - job->id = atoi(dent->filename + 1); - job->back_pipes[0] = -1; - job->back_pipes[1] = -1; - job->print_pipes[0] = -1; - job->print_pipes[1] = -1; - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdLoadAllJobs: Loading attributes for job %d...", - job->id); +/* + * 'cupsdLoadJob()' - Load a single job... + */ - if (job->id >= NextJobId) - NextJobId = job->id + 1; +void +cupsdLoadJob(cupsd_job_t *job) /* I - Job */ +{ + char jobfile[1024]; /* Job filename */ + 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 */ + mime_type_t **filetypes; /* New filetypes array */ + int *compressions; /* New compressions array */ - /* - * Load the job control file... - */ - snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->filename); - if ((fp = cupsFileOpen(filename, "r")) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Unable to open job control file " - "\"%s\" - %s!", - filename, strerror(errno)); - ippDelete(job->attrs); - free(job); - unlink(filename); - continue; - } - else - { - if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, - job->attrs) != IPP_DATA) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Unable to read job control file " - "\"%s\"!", - filename); - cupsFileClose(fp); - ippDelete(job->attrs); - free(job); - unlink(filename); - continue; - } + if (job->attrs) + { + if (job->state_value >= IPP_JOB_STOPPED) + job->access_time = time(NULL); - cupsFileClose(fp); - } + return; + } - if ((job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Missing or bad job-state attribute " - "in control file \"%s\"!", - filename); - ippDelete(job->attrs); - free(job); - unlink(filename); - continue; - } + if ((job->attrs = ippNew()) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Ran out of memory for job attributes!"); + return; + } - if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: No job-printer-uri attribute in " - "control file \"%s\"!", - filename); - ippDelete(job->attrs); - free(job); - unlink(filename); - continue; - } + /* + * Load job attributes... + */ - httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, method, - sizeof(method), username, sizeof(username), host, - sizeof(host), &port, resource, sizeof(resource)); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading attributes for job %d...", + job->id); - if ((dest = cupsdValidateDest(host, resource, &(job->dtype), - NULL)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Unable to queue job for destination " - "\"%s\"!", - attr->values[0].string.text); - ippDelete(job->attrs); - free(job); - unlink(filename); - continue; - } + 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)); + ippDelete(job->attrs); + job->attrs = NULL; + return; + } - cupsdSetString(&job->dest, dest); + 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); + cupsFileClose(fp); + ippDelete(job->attrs); + job->attrs = NULL; + unlink(jobfile); + return; + } - job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", - IPP_TAG_INTEGER); - job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); + cupsFileClose(fp); - if ((attr = ippFindAttribute(job->attrs, "job-priority", - IPP_TAG_INTEGER)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Missing or bad job-priority " - "attribute in control file \"%s\"!", - filename); - ippDelete(job->attrs); - free(job); - unlink(filename); - continue; - } - job->priority = attr->values[0].integer; + /* + * Copy attribute data to the job object... + */ - if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name", - IPP_TAG_NAME)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Missing or bad " - "job-originating-user-name attribute in control file " - "\"%s\"!", - filename); - ippDelete(job->attrs); - free(job); - unlink(filename); - continue; - } - cupsdSetString(&job->username, attr->values[0].string.text); + 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); + ippDelete(job->attrs); + job->attrs = NULL; + unlink(jobfile); + return; + } - /* - * Insert the job into the array, sorting by job priority and ID... - */ + job->state_value = (ipp_jstate_t)job->state->values[0].integer; - cupsArrayAdd(Jobs, job); - if (job->state->values[0].integer < IPP_JOB_STOPPED) - cupsArrayAdd(ActiveJobs,job); + if (!job->dest) + { + 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); + ippDelete(job->attrs); + job->attrs = NULL; + unlink(jobfile); + return; + } - /* - * Set the job hold-until time and state... - */ + httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, scheme, + sizeof(scheme), username, sizeof(username), host, + sizeof(host), &port, resource, sizeof(resource)); - if (job->state->values[0].integer == IPP_JOB_HELD) - { - if ((attr = ippFindAttribute(job->attrs, "job-hold-until", - IPP_TAG_KEYWORD)) == NULL) - attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); + if ((dest = cupsdValidateDest(host, resource, &(job->dtype), + NULL)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to queue job for destination \"%s\"!", + attr->values[0].string.text); + ippDelete(job->attrs); + job->attrs = NULL; + unlink(jobfile); + return; + } - if (attr == NULL) - job->state->values[0].integer = IPP_JOB_PENDING; - else - cupsdSetJobHoldUntil(job, attr->values[0].string.text); - } - else if (job->state->values[0].integer == IPP_JOB_PROCESSING) - job->state->values[0].integer = IPP_JOB_PENDING; + cupsdSetString(&job->dest, dest); + } + + job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", + IPP_TAG_INTEGER); + job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); + + if (!job->priority) + { + 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); + ippDelete(job->attrs); + job->attrs = NULL; + unlink(jobfile); + return; } + job->priority = attr->values[0].integer; + } + + if (!job->username) + { + 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); + ippDelete(job->attrs); + job->attrs = NULL; + unlink(jobfile); + return; + } + + cupsdSetString(&job->username, attr->values[0].string.text); + } + /* - * Read all the d##### files... + * Set the job hold-until time and state... */ - cupsDirRewind(dir); + if (job->state_value == IPP_JOB_HELD) + { + if ((attr = ippFindAttribute(job->attrs, "job-hold-until", + IPP_TAG_KEYWORD)) == NULL) + attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); - while ((dent = cupsDirRead(dir)) != NULL) - if (strlen(dent->filename) > 7 && dent->filename[0] == 'd' && - strchr(dent->filename, '-')) + if (attr) + cupsdSetJobHoldUntil(job, attr->values[0].string.text); + else { - /* - * Find the job... - */ + job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; + } + } + else if (job->state_value == IPP_JOB_PROCESSING) + { + job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; + } - jobid = atoi(dent->filename + 1); - fileid = atoi(strchr(dent->filename, '-') + 1); + if (!job->num_files) + { + /* + * Find all the d##### files... + */ - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdLoadAllJobs: Auto-typing document file %s...", - dent->filename); + for (fileid = 1; fileid < 10000; fileid ++) + { + snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot, + job->id, fileid); - snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->filename); + if (access(jobfile, 0)) + break; - if ((job = cupsdFindJob(jobid)) == NULL) - { - cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Orphaned print file \"%s\"!", - filename); - unlink(filename); - continue; - } + cupsdLogMessage(CUPSD_LOG_DEBUG, "Auto-typing document file \"%s\"...", + jobfile); if (fileid > job->num_files) { @@ -997,15 +1030,15 @@ cupsdLoadAllJobs(void) compressions = (int *)realloc(job->compressions, sizeof(int) * fileid); filetypes = (mime_type_t **)realloc(job->filetypes, - sizeof(mime_type_t *) * fileid); + sizeof(mime_type_t *) * + fileid); } - if (compressions == NULL || filetypes == NULL) + if (!compressions || !filetypes) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdLoadAllJobs: Ran out of memory for job file " - "types!"); - continue; + "Ran out of memory for job file types!"); + return; } job->compressions = compressions; @@ -1013,21 +1046,16 @@ cupsdLoadAllJobs(void) job->num_files = fileid; } - job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename, NULL, + job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, jobfile, NULL, job->compressions + fileid - 1); - if (job->filetypes[fileid - 1] == NULL) + if (!job->filetypes[fileid - 1]) job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application", "vnd.cups-raw"); } + } - cupsDirClose(dir); - - /* - * Clean out old jobs as needed... - */ - - cupsdCleanJobs(); + job->access_time = time(NULL); } @@ -1054,18 +1082,21 @@ cupsdMoveJob(cupsd_job_t *job, /* I - Job */ * Don't move completed jobs... */ - if (job->state->values[0].integer >= IPP_JOB_PROCESSING) + if (job->state_value >= IPP_JOB_PROCESSING) return; /* * Change the destination information... */ + cupsdLoadJob(job); + cupsdSetString(&job->dest, dest); job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT); - if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL) + if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", + IPP_TAG_URI)) != NULL) cupsdSetString(&(attr->values[0].string.text), p->uri); cupsdSaveJob(job); @@ -1079,13 +1110,14 @@ cupsdMoveJob(cupsd_job_t *job, /* I - Job */ void cupsdReleaseJob(cupsd_job_t *job) /* I - Job */ { - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReleaseJob: id = %d", job->id); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReleaseJob: id = %d", job->id); - if (job->state->values[0].integer == IPP_JOB_HELD) + if (job->state_value == IPP_JOB_HELD) { DEBUG_puts("cupsdReleaseJob: setting state to pending..."); job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; cupsdSaveJob(job); cupsdCheckJobs(); } @@ -1099,12 +1131,15 @@ cupsdReleaseJob(cupsd_job_t *job) /* I - Job */ void cupsdRestartJob(cupsd_job_t *job) /* I - Job */ { - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRestartJob: id = %d", job->id); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRestartJob: id = %d", job->id); - if (job->state->values[0].integer == IPP_JOB_STOPPED || JobFiles) + if (job->state_value == IPP_JOB_STOPPED || job->num_files) { + cupsdLoadJob(job); + job->tries = 0; job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; cupsdSaveJob(job); cupsdCheckJobs(); } @@ -1112,6 +1147,76 @@ cupsdRestartJob(cupsd_job_t *job) /* I - Job */ /* + * 'cupsdSaveAllJobs()' - Save a summary of all jobs to disk. + */ + +void +cupsdSaveAllJobs(void) +{ + int i; /* Looping var */ + cups_file_t *fp; /* Job cache file */ + char temp[1024]; /* Temporary string */ + cupsd_job_t *job; /* Current job */ + time_t curtime; /* Current time */ + struct tm *curdate; /* Current date */ + + + snprintf(temp, sizeof(temp), "%s/job.cache", CacheDir); + if ((fp = cupsFileOpen(temp, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create job cache file \"%s\" - %s", + temp, strerror(errno)); + return; + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Saving job cache file \"%s\"...", temp); + + /* + * Restrict access to the file... + */ + + fchown(cupsFileNumber(fp), getuid(), Group); + fchmod(cupsFileNumber(fp), ConfigFilePerm); + + /* + * Write a small header to the file... + */ + + curtime = time(NULL); + curdate = localtime(&curtime); + strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); + + cupsFilePuts(fp, "# Job cache file for " CUPS_SVERSION "\n"); + cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); + cupsFilePrintf(fp, "NextJobId %d\n", NextJobId); + + /* + * Write each job known to the system... + */ + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + { + cupsFilePrintf(fp, "<Job %d>\n", job->id); + cupsFilePrintf(fp, "State %d\n", job->state_value); + cupsFilePrintf(fp, "Priority %d\n", job->priority); + cupsFilePrintf(fp, "Username %s\n", job->username); + cupsFilePrintf(fp, "Destination %s\n", job->dest); + cupsFilePrintf(fp, "DestType %d\n", job->dtype); + cupsFilePrintf(fp, "NumFiles %d\n", job->num_files); + for (i = 0; i < job->num_files; i ++) + cupsFilePrintf(fp, "File %d %s/%s %d\n", i + 1, job->filetypes[i]->super, + job->filetypes[i]->type, job->compressions[i]); + cupsFilePuts(fp, "</Job>\n"); + } + + cupsFileClose(fp); +} + + +/* * 'cupsdSaveJob()' - Save a job to disk. */ @@ -1122,13 +1227,15 @@ cupsdSaveJob(cupsd_job_t *job) /* I - Job */ cups_file_t *fp; /* Job file */ + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p", + job, job->id, job->attrs); + snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id); if ((fp = cupsFileOpen(filename, "w")) == NULL) { cupsdLogMessage(CUPSD_LOG_ERROR, - "cupsdSaveJob: Unable to create job control file " - "\"%s\" - %s.", + "Unable to create job control file \"%s\" - %s.", filename, strerror(errno)); return; } @@ -1136,7 +1243,12 @@ cupsdSaveJob(cupsd_job_t *job) /* I - Job */ fchmod(cupsFileNumber(fp), 0600); fchown(cupsFileNumber(fp), RunUser, Group); - ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL, job->attrs); + job->attrs->state = IPP_IDLE; + + 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); cupsFileClose(fp); } @@ -1157,7 +1269,7 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ int second; /* Hold second */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetJobHoldUntil(%d, \"%s\")", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSetJobHoldUntil(%d, \"%s\")", job->id, when); second = 0; @@ -1272,7 +1384,7 @@ cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ job->hold_until += 24 * 60 * 60 * 60; } - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetJobHoldUntil: hold_until = %d", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSetJobHoldUntil: hold_until = %d", (int)job->hold_until); } @@ -1294,7 +1406,7 @@ cupsdSetJobPriority( * Don't change completed jobs... */ - if (job->state->values[0].integer >= IPP_JOB_PROCESSING) + if (job->state_value >= IPP_JOB_PROCESSING) return; /* @@ -1305,7 +1417,8 @@ cupsdSetJobPriority( job->priority = priority; - if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(job->attrs, "job-priority", + IPP_TAG_INTEGER)) != NULL) attr->values[0].integer = priority; else ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority", @@ -1338,37 +1451,41 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ int backroot; /* Run backend as root? */ int pid; /* Process ID of new filter process */ int banner_page; /* 1 if banner page, 0 otherwise */ - int statusfds[2], /* Pipes used between the filters and scheduler */ - filterfds[2][2];/* Pipes used between the filters */ + int statusfds[2], /* Pipes used with the scheduler */ + filterfds[2][2];/* Pipes used between filters */ int envc; /* Number of environment variables */ - char *argv[8], /* Filter command-line arguments */ + char **argv, /* Filter command-line arguments */ sani_uri[1024], /* Sanitized DEVICE_URI env var */ filename[1024], /* Job filename */ - command[1024], /* Full path to filter/backend command */ + command[1024], /* Full path to command */ jobid[255], /* Job ID string */ title[IPP_MAX_NAME], /* Job title string */ copies[255], /* # copies string */ - *envp[MAX_ENV], /* Environment variables */ - charset[255], /* CHARSET environment variable */ - class_name[255],/* CLASS environment variable */ + *envp[MAX_ENV + 11], + /* Environment variables */ + charset[255], /* CHARSET env variable */ + class_name[255],/* CLASS env variable */ classification[1024], - /* CLASSIFICATION environment variable */ + /* CLASSIFICATION env variable */ content_type[1024], - /* CONTENT_TYPE environment variable */ + /* CONTENT_TYPE env variable */ device_uri[1024], - /* DEVICE_URI environment variable */ - lang[255], /* LANG environment variable */ - ppd[1024], /* PPD environment variable */ + /* DEVICE_URI env variable */ + final_content_type[1024], + /* FINAL_CONTENT_TYPE env variable */ + lang[255], /* LANG env variable */ + ppd[1024], /* PPD env variable */ printer_name[255], - /* PRINTER environment variable */ + /* PRINTER env variable */ rip_max_cache[255]; - /* RIP_MAX_CACHE environment variable */ + /* 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_DEBUG, "cupsdStartJob() id = %d, file = %d/%d", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: id = %d, file = %d/%d", job->id, job->current_file, job->num_files); if (job->num_files == 0) @@ -1399,7 +1516,7 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ */ cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdStartJob: Sending job to queue tagged as raw..."); + "[Job %d] Sending job to queue tagged as raw...", job->id); filters = NULL; } @@ -1410,12 +1527,13 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ */ filters = mimeFilter(MimeDatabase, job->filetypes[job->current_file], - printer->filetype, &(job->cost), MAX_FILTERS - 1); + printer->filetype, &(job->cost)); if (!filters) { cupsdLogMessage(CUPSD_LOG_ERROR, - "Unable to convert file %d to printable format for job %d!", + "Unable to convert file %d to printable format for " + "job %d!", job->current_file, job->id); cupsdLogMessage(CUPSD_LOG_INFO, "Hint: Do you have ESP Ghostscript installed?"); @@ -1429,7 +1547,8 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ 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."); + "Job canceled because it has no files that can be " + "printed."); cupsdCancelJob(job, 0); } @@ -1470,8 +1589,9 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdLogMessage(CUPSD_LOG_INFO, "Holding job %d because filter limit has been reached.", job->id); - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdStartJob: id=%d, file=%d, cost=%d, level=%d, limit=%d", + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: id=%d, file=%d, cost=%d, level=%d, " + "limit=%d", job->id, job->current_file, job->cost, FilterLevel, FilterLimit); return; @@ -1480,10 +1600,17 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ 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... */ - if (job->compressions[job->current_file]) + if (!remote_job && job->compressions[job->current_file]) { /* * Add gziptoany filter to the front of the list... @@ -1491,11 +1618,11 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ if (!cupsArrayInsert(filters, &gziptoany_filter)) { - cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add decompression filter - %s", - strerror(errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to add decompression filter - %s", + strerror(errno)); - if (filters != NULL) - free(filters); + cupsArrayDelete(filters); job->current_file ++; @@ -1527,8 +1654,7 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add port monitor - %s", strerror(errno)); - if (filters != NULL) - free(filters); + cupsArrayDelete(filters); job->current_file ++; @@ -1553,6 +1679,7 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ */ job->state->values[0].integer = IPP_JOB_PROCESSING; + job->state_value = IPP_JOB_PROCESSING; job->status = 0; job->printer = printer; printer->job = job; @@ -1620,11 +1747,10 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ if (optptr == NULL) { cupsdLogMessage(CUPSD_LOG_CRIT, - "cupsdStartJob: Unable to allocate %d bytes for option buffer for job %d!", - i, job->id); + "Unable to allocate %d bytes for option buffer for " + "job %d!", i, job->id); - if (filters != NULL) - free(filters); + cupsArrayDelete(filters); FilterLevel -= job->cost; @@ -1652,7 +1778,7 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ for (attr = job->attrs->attrs; attr != NULL; attr = attr->next) { - if (strcmp(attr->name, "copies") == 0 && + if (!strcmp(attr->name, "copies") && attr->value_tag == IPP_TAG_INTEGER) { /* @@ -1662,7 +1788,7 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ if (!banner_page) sprintf(copies, "%d", attr->values[0].integer); } - else if (strcmp(attr->name, "job-name") == 0 && + else if (!strcmp(attr->name, "job-name") && (attr->value_tag == IPP_TAG_NAME || attr->value_tag == IPP_TAG_NAMELANG)) strlcpy(title, attr->values[0].string.text, sizeof(title)); @@ -1675,29 +1801,32 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ if (attr->value_tag == IPP_TAG_MIMETYPE || attr->value_tag == IPP_TAG_NAMELANG || attr->value_tag == IPP_TAG_TEXTLANG || - attr->value_tag == IPP_TAG_URI || + (attr->value_tag == IPP_TAG_URI && strcmp(attr->name, "job-uuid")) || attr->value_tag == IPP_TAG_URISCHEME || attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */ continue; - if (strncmp(attr->name, "time-", 5) == 0) + if (!strncmp(attr->name, "time-", 5)) continue; - if (strncmp(attr->name, "job-", 4) == 0 && + if (!strncmp(attr->name, "job-", 4) && strcmp(attr->name, "job-uuid") && !(printer->type & CUPS_PRINTER_REMOTE)) continue; - if (strncmp(attr->name, "job-", 4) == 0 && - strcmp(attr->name, "job-billing") != 0 && - strcmp(attr->name, "job-sheets") != 0 && - strcmp(attr->name, "job-hold-until") != 0 && - strcmp(attr->name, "job-priority") != 0) + if (!strncmp(attr->name, "job-", 4) && + strcmp(attr->name, "job-uuid") && + strcmp(attr->name, "job-billing") && + strcmp(attr->name, "job-sheets") && + strcmp(attr->name, "job-hold-until") && + strcmp(attr->name, "job-priority")) continue; - if ((strcmp(attr->name, "page-label") == 0 || - strcmp(attr->name, "page-border") == 0 || - strncmp(attr->name, "number-up", 9) == 0 || - strcmp(attr->name, "page-set") == 0) && + if ((!strcmp(attr->name, "page-label") || + !strcmp(attr->name, "page-border") || + !strncmp(attr->name, "number-up", 9) || + !strcmp(attr->name, "page-set") || + !strcasecmp(attr->name, "AP_FIRSTPAGE_InputSlot") || + !strcasecmp(attr->name, "AP_FIRSTPAGE_ManualFeed")) && banner_page) continue; @@ -1762,6 +1891,7 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : + case IPP_TAG_URI : for (valptr = attr->values[i].string.text; *valptr;) { if (strchr(" \t\n\\\'\"", *valptr)) @@ -1795,11 +1925,16 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ * * This allows legacy printer drivers that use the old System V * printing interface to be used by CUPS. + * + * For remote jobs, we send all of the files in the argument list. */ + if (remote_job) + argv = calloc(7 + job->num_files, sizeof(char *)); + else + argv = calloc(8, sizeof(char *)); + sprintf(jobid, "%d", job->id); - snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, - job->id, job->current_file + 1); argv[0] = printer->name; argv[1] = jobid; @@ -1807,12 +1942,26 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ argv[3] = title; argv[4] = copies; argv[5] = options; - argv[6] = filename; - argv[7] = NULL; - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdStartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"", - argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + { + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, + job->id, i + 1); + argv[6 + i] = strdup(filename); + } + } + else + { + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, + job->id, job->current_file + 1); + argv[6] = filename; + } + + for (i = 0; argv[i]; i ++) + cupsdLogMessage(CUPSD_LOG_DEBUG, + "[Job %d] argv[%d]=\"%s\"", job->id, i, argv[i]); /* * Create environment variable strings for the filters... @@ -1870,7 +2019,8 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s", job->filetypes[job->current_file]->super, job->filetypes[job->current_file]->type); - snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", printer->device_uri); + snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", + printer->device_uri); cupsdSanitizeURI(printer->device_uri, sani_uri, sizeof(sani_uri)); snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot, printer->name); snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name); @@ -1886,6 +2036,14 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ envp[envc ++] = device_uri; envp[envc ++] = printer_name; + if ((filter = (mime_filter_t *)cupsArrayLast(filters)) != NULL) + { + 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) { if ((attr = ippFindAttribute(job->attrs, "job-sheets", @@ -1913,13 +2071,16 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ for (i = 0; i < envc; i ++) if (strncmp(envp[i], "DEVICE_URI=", 11)) - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: envp[%d]=\"%s\"", - i, envp[i]); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"%s\"", + job->id, i, envp[i]); else - cupsdLogMessage(CUPSD_LOG_DEBUG, - "cupsdStartJob: envp[%d]=\"DEVICE_URI=%s\"", i, sani_uri); + cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] envp[%d]=\"DEVICE_URI=%s\"", + job->id, i, sani_uri); - job->current_file ++; + if (remote_job) + job->current_file = job->num_files; + else + job->current_file ++; /* * Now create processes for all of the filters... @@ -1934,17 +2095,25 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdAddPrinterHistory(printer); - if (filters != NULL) - free(filters); + cupsArrayDelete(filters); cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled because the server could not create the job status pipes."); + "Job canceled because the server could not create the job " + "status pipes."); + + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); cupsdCancelJob(job, 0); return; } - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: statusfds = [ %d %d ]", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: statusfds = [ %d %d ]", statusfds[0], statusfds[1]); #ifdef FD_CLOEXEC @@ -1969,17 +2138,25 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdAddPrinterHistory(printer); - if (filters != NULL) - free(filters); + cupsArrayDelete(filters); cupsdClosePipe(statusfds); + + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); + cupsdCancelJob(job, 0); return; } fcntl(filterfds[1][0], F_SETFD, fcntl(filterfds[1][0], F_GETFD) | FD_CLOEXEC); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: filterfds[%d] = [ %d %d ]", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: filterfds[%d] = [ %d %d ]", 1, filterfds[1][0], filterfds[1][1]); for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters); @@ -2009,7 +2186,16 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdClosePipe(filterfds[!slot]); cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled because the server could not create the filter pipes."); + "Job canceled because the server could not create the " + "filter pipes."); + + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); cupsdCancelJob(job, 0); return; @@ -2036,7 +2222,16 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdClosePipe(filterfds[!slot]); cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled because the server could not create the backend pipes."); + "Job canceled because the server could not create " + "the backend pipes."); + + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); cupsdCancelJob(job, 0); return; @@ -2074,7 +2269,16 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdClosePipe(filterfds[!slot]); cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled because the server could not open the output file."); + "Job canceled because the server could not open the " + "output file."); + + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); cupsdCancelJob(job, 0); return; @@ -2084,16 +2288,19 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ fcntl(job->print_pipes[1], F_GETFD) | FD_CLOEXEC); } - cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: print_pipes = [ %d %d ]", - job->print_pipes[0], job->print_pipes[1]); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: 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_DEBUG, "cupsdStartJob: filter = \"%s\"", command); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: filterfds[%d] = [ %d %d ]", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: filter=\"%s\"", + command); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: filterfds[%d]=[ %d %d ]", slot, filterfds[slot][0], filterfds[slot][1]); pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0], @@ -2101,7 +2308,8 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ job->back_pipes[0], 0, job->filters + i); cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStartJob: Closing filter pipes for slot %d [ %d %d ]...", + "cupsdStartJob: Closing filter pipes for slot %d " + "[ %d %d ]...", !slot, filterfds[!slot][0], filterfds[!slot][1]); cupsdClosePipe(filterfds[!slot]); @@ -2121,7 +2329,16 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdAddPrinterHistory(printer); cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled because the server could not execute a filter."); + "Job canceled because the server could not execute a " + "filter."); + + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); cupsdCancelJob(job, 0); return; @@ -2177,6 +2394,14 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, "Job canceled because the server could not open a file."); + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); + cupsdCancelJob(job, 0); return; } @@ -2184,9 +2409,9 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ fcntl(filterfds[slot][1], F_SETFD, fcntl(filterfds[slot][1], F_GETFD) | FD_CLOEXEC); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: backend = \"%s\"", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: backend=\"%s\"", command); - cupsdLogMessage(CUPSD_LOG_DEBUG, + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: filterfds[%d] = [ %d %d ]", slot, filterfds[slot][0], filterfds[slot][1]); @@ -2200,7 +2425,8 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdLogMessage(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)); + "Unable to start backend \"%s\" - %s.", method, + strerror(errno)); cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: Closing print pipes [ %d %d ]...", @@ -2215,7 +2441,16 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ cupsdClosePipe(job->back_pipes); cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, - "Job canceled because the server could not execute the backend."); + "Job canceled because the server could not execute " + "the backend."); + + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); cupsdCancelJob(job, 0); return; @@ -2258,8 +2493,17 @@ cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ } } + if (remote_job) + { + for (i = 0; i < job->num_files; i ++) + free(argv[i + 6]); + } + + free(argv); + cupsdLogMessage(CUPSD_LOG_DEBUG2, - "cupsdStartJob: Closing filter pipes for slot %d [ %d %d ]...", + "cupsdStartJob: Closing filter pipes for slot %d " + "[ %d %d ]...", slot, filterfds[slot][0], filterfds[slot][1]); cupsdClosePipe(filterfds[slot]); @@ -2296,10 +2540,11 @@ cupsdStopAllJobs(void) for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); job; job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) - if (job->state->values[0].integer == IPP_JOB_PROCESSING) + if (job->state_value == IPP_JOB_PROCESSING) { cupsdStopJob(job, 1); job->state->values[0].integer = IPP_JOB_PENDING; + job->state_value = IPP_JOB_PENDING; } } @@ -2315,10 +2560,10 @@ cupsdStopJob(cupsd_job_t *job, /* I - Job */ int i; /* Looping var */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStopJob: id = %d, force = %d", + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStopJob: id = %d, force = %d", job->id, force); - if (job->state->values[0].integer != IPP_JOB_PROCESSING) + if (job->state_value != IPP_JOB_PROCESSING) return; FilterLevel -= job->cost; @@ -2331,10 +2576,11 @@ cupsdStopJob(cupsd_job_t *job, /* I - Job */ else if (job->printer->state != IPP_PRINTER_STOPPED) cupsdSetPrinterState(job->printer, IPP_PRINTER_IDLE, 0); - cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStopJob: printer state is %d", + 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->printer = NULL; @@ -2389,6 +2635,49 @@ cupsdStopJob(cupsd_job_t *job, /* I - Job */ /* + * 'cupsdUnloadCompletedJobs()' - Flush completed job history from memory. + */ + +void +cupsdUnloadCompletedJobs(void) +{ + cupsd_job_t *job; /* Current job */ + time_t expire; /* Expiration time */ + + + expire = time(NULL) - 60; + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + if (job->attrs && job->state_value >= IPP_JOB_STOPPED && + job->access_time < expire) + cupsdUnloadJob(job); +} + + +/* + * 'cupsdUnloadJob()' - Unload a job from memory. + */ + +void +cupsdUnloadJob(cupsd_job_t *job) /* I - Job */ +{ + if (!job->attrs) + return; + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Unloading job %d...", job->id); + + ippDelete(job->attrs); + + job->attrs = NULL; + job->state = NULL; + job->sheets = NULL; + job->job_sheets = NULL; +} + + +/* * 'cupsdUpdateJob()' - Read a status update from a job's filters. */ @@ -2480,7 +2769,7 @@ cupsdUpdateJob(cupsd_job_t *job) /* I - Job to check */ cupsdAddPrinterHistory(job->printer); } #endif /* __APPLE__ */ - else + else if (loglevel <= CUPSD_LOG_INFO) { /* * Some message to show in the printer-state-message attribute... @@ -2531,7 +2820,8 @@ compare_active_jobs(void *first, /* I - First job */ int diff; /* Difference */ - if ((diff = ((cupsd_job_t *)first)->priority - ((cupsd_job_t *)second)->priority) != 0) + if ((diff = ((cupsd_job_t *)first)->priority - + ((cupsd_job_t *)second)->priority) != 0) return (diff); else return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id); @@ -2552,11 +2842,33 @@ compare_jobs(void *first, /* I - First job */ /* + * '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. */ -int /* O - Size of buffer to hold IPP attributes */ +int /* O - Size of attribute buffer */ ipp_length(ipp_t *ipp) /* I - IPP request */ { int bytes; /* Number of bytes */ @@ -2654,6 +2966,7 @@ ipp_length(ipp_t *ipp) /* I - IPP request */ case IPP_TAG_KEYWORD : case IPP_TAG_CHARSET : case IPP_TAG_LANGUAGE : + case IPP_TAG_URI : /* * Strings can contain characters that need quoting. We need * at least 2 * len + 2 characters to cover the quotes and @@ -2674,6 +2987,373 @@ ipp_length(ipp_t *ipp) /* I - IPP request */ /* + * 'load_job_cache()' - Load jobs from the job.cache file. + */ + +static void +load_job_cache(const char *filename) /* I - job.cache filename */ +{ + cups_file_t *fp; /* job.cache file */ + char line[1024], /* Line buffer */ + *value; /* Value on line */ + int linenum; /* Line number in file */ + cupsd_job_t *job; /* Current job */ + int jobid; /* Job ID */ + char jobfile[1024]; /* Job filename */ + + + /* + * Open the job.cache file... + */ + + if ((fp = cupsFileOpen(filename, "r")) == NULL) + { + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to open job cache file \"%s\": %s", + filename, strerror(errno)); + + load_request_root(); + + return; + } + + /* + * Read entries from the job cache file and create jobs as needed. + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Loading job cache file \"%s\"...", + filename); + + linenum = 0; + job = NULL; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + if (!strcasecmp(line, "NextJobId")) + { + if (value) + NextJobId = atoi(value); + } + else if (!strcasecmp(line, "<Job")) + { + if (job) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing </Job> directive on line %d!", + linenum); + continue; + } + + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing job ID on line %d!", linenum); + continue; + } + + jobid = atoi(value); + + if (jobid < 1) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad job ID %d on line %d!", jobid, + linenum); + continue; + } + + snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, jobid); + if (access(jobfile, 0)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Job %d files have gone away!", jobid); + continue; + } + + job = calloc(1, sizeof(cupsd_job_t)); + if (!job) + { + cupsdLogMessage(CUPSD_LOG_EMERG, + "Unable to allocate memory for job %d!", jobid); + break; + } + + job->id = jobid; + job->back_pipes[0] = -1; + job->back_pipes[1] = -1; + job->print_pipes[0] = -1; + job->print_pipes[1] = -1; + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Loading job %d from cache...", job->id); + } + else if (!job) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing <Job #> directive on line %d!", linenum); + continue; + } + else if (!strcasecmp(line, "</Job>")) + { + cupsArrayAdd(Jobs, job); + + if (job->state_value < IPP_JOB_STOPPED) + { + cupsArrayAdd(ActiveJobs, job); + cupsdLoadJob(job); + } + + job = NULL; + } + else if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d!", linenum); + continue; + } + else if (!strcasecmp(line, "State")) + { + job->state_value = atoi(value); + + if (job->state_value < IPP_JOB_PENDING) + job->state_value = IPP_JOB_PENDING; + else if (job->state_value > IPP_JOB_COMPLETED) + job->state_value = IPP_JOB_COMPLETED; + } + else if (!strcasecmp(line, "Priority")) + { + job->priority = atoi(value); + } + else if (!strcasecmp(line, "Username")) + { + cupsdSetString(&job->username, value); + } + else if (!strcasecmp(line, "Destination")) + { + cupsdSetString(&job->dest, value); + } + else if (!strcasecmp(line, "DestType")) + { + job->dtype = (cups_ptype_t)atoi(value); + } + else if (!strcasecmp(line, "NumFiles")) + { + job->num_files = atoi(value); + + if (job->num_files < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad NumFiles value %d on line %d!", + job->num_files, linenum); + job->num_files = 0; + continue; + } + + if (job->num_files > 0) + { + snprintf(jobfile, sizeof(jobfile), "%s/d%05d-001", RequestRoot, + job->id); + if (access(jobfile, 0)) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Data files for job %d have gone away!", job->id); + job->num_files = 0; + continue; + } + + job->filetypes = calloc(job->num_files, sizeof(mime_type_t *)); + job->compressions = calloc(job->num_files, sizeof(int)); + + if (!job->filetypes || !job->compressions) + { + cupsdLogMessage(CUPSD_LOG_EMERG, + "Unable to allocate memory for %d files!", + job->num_files); + break; + } + } + } + else if (!strcasecmp(line, "File")) + { + int number, /* File number */ + compression; /* Compression value */ + char super[MIME_MAX_SUPER], /* MIME super type */ + type[MIME_MAX_TYPE]; /* MIME type */ + + + if (sscanf(value, "%d%*[ \t]%15[^/]/%255s%d", &number, super, type, + &compression) != 4) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File on line %d!", linenum); + continue; + } + + if (number < 1 || number > job->num_files) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File number %d on line %d!", + number, linenum); + continue; + } + + number --; + + job->compressions[number] = compression; + job->filetypes[number] = mimeType(MimeDatabase, super, type); + + if (!job->filetypes[number]) + { + /* + * 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); + + snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot, + job->id, number + 1); + job->filetypes[number] = mimeFileType(MimeDatabase, jobfile, NULL, + job->compressions + number); + + /* + * If that didn't work, assume it is raw... + */ + + if (!job->filetypes[number]) + job->filetypes[number] = mimeType(MimeDatabase, "application", + "vnd.cups-raw"); + } + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown %s directive on line %d!", + line, linenum); + } + + cupsFileClose(fp); +} + + +/* + * 'load_next_job_id()' - Load the NextJobId value from the job.cache file. + */ + +static void +load_next_job_id(const char *filename) /* I - job.cache filename */ +{ + cups_file_t *fp; /* job.cache file */ + char line[1024], /* Line buffer */ + *value; /* Value on line */ + int linenum; /* Line number in file */ + + + /* + * Read the NextJobId directive from the job.cache file and use + * the value (if any). + */ + + if ((fp = cupsFileOpen(filename, "r")) == NULL) + { + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to open job cache file \"%s\": %s", + filename, strerror(errno)); + + return; + } + + cupsdLogMessage(CUPSD_LOG_INFO, + "Loading NextJobId from job cache file \"%s\"...", filename); + + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + if (!strcasecmp(line, "NextJobId")) + { + if (value) + NextJobId = atoi(value); + + break; + } + } + + cupsFileClose(fp); +} + + +/* + * 'load_request_root()' - Load jobs from the RequestRoot directory. + */ + +static void +load_request_root(void) +{ + cups_dir_t *dir; /* Directory */ + cups_dentry_t *dent; /* Directory entry */ + cupsd_job_t *job; /* New job */ + + + /* + * Open the requests directory... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Scanning %s for jobs...", RequestRoot); + + if ((dir = cupsDirOpen(RequestRoot)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to open spool directory \"%s\": %s", + RequestRoot, strerror(errno)); + return; + } + + /* + * Read all the c##### files... + */ + + while ((dent = cupsDirRead(dir)) != NULL) + if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c') + { + /* + * Allocate memory for the job... + */ + + if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Ran out of memory for jobs!"); + cupsDirClose(dir); + return; + } + + /* + * Assign the job ID... + */ + + job->id = atoi(dent->filename + 1); + job->back_pipes[0] = -1; + job->back_pipes[1] = -1; + job->print_pipes[0] = -1; + job->print_pipes[1] = -1; + + if (job->id >= NextJobId) + NextJobId = job->id + 1; + + /* + * Load the job... + */ + + cupsdLoadJob(job); + + /* + * Insert the job into the array, sorting by job priority and ID... + */ + + cupsArrayAdd(Jobs, job); + + if (job->state_value < IPP_JOB_STOPPED) + cupsArrayAdd(ActiveJobs,job); + else + cupsdUnloadJob(job); + } + + cupsDirClose(dir); +} + + +/* * 'set_time()' - Set one of the "time-at-xyz" attributes... */ @@ -2709,9 +3389,11 @@ set_hold_until(cupsd_job_t *job, /* I - Job to update */ * Set the hold_until value and hold the job... */ - cupsdLogMessage(CUPSD_LOG_DEBUG, "set_hold_until: hold_until = %d", (int)holdtime); + cupsdLogMessage(CUPSD_LOG_DEBUG, "set_hold_until: hold_until = %d", + (int)holdtime); job->state->values[0].integer = IPP_JOB_HELD; + job->state_value = IPP_JOB_HELD; job->hold_until = holdtime; /* @@ -2723,7 +3405,8 @@ set_hold_until(cupsd_job_t *job, /* I - Job to update */ snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour, holddate->tm_min, holddate->tm_sec); - if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL) + if ((attr = ippFindAttribute(job->attrs, "job-hold-until", + IPP_TAG_KEYWORD)) == NULL) attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); /* @@ -2741,5 +3424,5 @@ set_hold_until(cupsd_job_t *job, /* I - Job to update */ /* - * End of "$Id: job.c 5051 2006-02-02 16:13:16Z mike $". + * End of "$Id: job.c 5131 2006-02-18 05:31:36Z mike $". */ |