diff -up cups-1.7.5/CHANGES.txt.str4396 cups-1.7.5/CHANGES.txt diff -up cups-1.7.5/scheduler/ipp.c.str4396 cups-1.7.5/scheduler/ipp.c --- cups-1.7.5/scheduler/ipp.c.str4396 2014-08-20 16:56:29.012022421 +0100 +++ cups-1.7.5/scheduler/ipp.c 2014-08-20 16:56:38.535084011 +0100 @@ -6595,6 +6595,7 @@ get_jobs(cupsd_client_t *con, /* I - C cupsd_job_t *job; /* Current job pointer */ cupsd_printer_t *printer; /* Printer */ cups_array_t *list; /* Which job list... */ + int delete_list = 0; /* Delete the list afterwards? */ cups_array_t *ra, /* Requested attributes array */ *exclude; /* Private attributes array */ cupsd_policy_t *policy; /* Current policy */ @@ -6694,13 +6695,15 @@ get_jobs(cupsd_client_t *con, /* I - C { job_comparison = 1; job_state = IPP_JOB_CANCELED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "aborted")) { job_comparison = 0; job_state = IPP_JOB_ABORTED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "all")) { @@ -6712,7 +6715,8 @@ get_jobs(cupsd_client_t *con, /* I - C { job_comparison = 0; job_state = IPP_JOB_CANCELED; - list = Jobs; + list = cupsdGetCompletedJobs(printer); + delete_list = 1; } else if (!strcmp(attr->values[0].string.text, "pending")) { @@ -6919,6 +6923,9 @@ get_jobs(cupsd_client_t *con, /* I - C cupsArrayDelete(ra); + if (delete_list) + cupsArrayDelete(list); + con->response->request.status.status_code = IPP_OK; } diff -up cups-1.7.5/scheduler/job.c.str4396 cups-1.7.5/scheduler/job.c --- cups-1.7.5/scheduler/job.c.str4396 2014-08-20 16:56:29.013022427 +0100 +++ cups-1.7.5/scheduler/job.c 2014-08-20 16:56:38.537084024 +0100 @@ -130,6 +130,7 @@ static mime_filter_t gziptoany_filter = */ static int compare_active_jobs(void *first, void *second, void *data); +static int compare_completed_jobs(void *first, void *second, void *data); static int compare_jobs(void *first, void *second, void *data); static void dump_job_history(cupsd_job_t *job); static void finalize_job(cupsd_job_t *job, int set_job_state); @@ -1568,6 +1569,30 @@ cupsdFindJob(int id) /* I - Job ID */ /* + * 'cupsdGetCompletedJobs()'- Generate a completed jobs list. + */ + +cups_array_t * /* O - Array of jobs */ +cupsdGetCompletedJobs( + cupsd_printer_t *p) /* I - Printer */ +{ + cups_array_t *list; /* Array of jobs */ + cupsd_job_t *job; /* Current job */ + + + list = cupsArrayNew(compare_completed_jobs, NULL); + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + if ((!p || !_cups_strcasecmp(p->name, job->dest)) && job->state_value >= IPP_JOB_STOPPED && job->completed_time) + cupsArrayAdd(list, job); + + return (list); +} + + +/* * 'cupsdGetPrinterJobCount()' - Get the number of pending, processing, * or held jobs in a printer or class. */ @@ -1766,6 +1791,8 @@ cupsdLoadJob(cupsd_job_t *job) /* I - J (attr = ippFindAttribute(job->attrs, "time-at-completed", IPP_TAG_INTEGER)) != NULL) { + job->completed_time = attr->values[0].integer; + if (JobHistory < INT_MAX) job->history_time = attr->values[0].integer + JobHistory; else @@ -2257,8 +2284,11 @@ cupsdSaveAllJobs(void) { cupsFilePrintf(fp, "\n", job->id); cupsFilePrintf(fp, "State %d\n", job->state_value); + if (job->completed_time) + cupsFilePrintf(fp, "Completed %ld\n", (long)job->completed_time); cupsFilePrintf(fp, "Priority %d\n", job->priority); - cupsFilePrintf(fp, "HoldUntil %d\n", (int)job->hold_until); + if (job->hold_until) + cupsFilePrintf(fp, "HoldUntil %ld\n", (long)job->hold_until); cupsFilePrintf(fp, "Username %s\n", job->username); cupsFilePrintf(fp, "Destination %s\n", job->dest); cupsFilePrintf(fp, "DestType %d\n", job->dtype); @@ -2993,6 +3023,28 @@ compare_active_jobs(void *first, /* I - /* + * 'compare_completed_jobs()' - Compare the job IDs and completion times of two jobs. + */ + +static int /* O - Difference */ +compare_completed_jobs(void *first, /* I - First job */ + void *second, /* I - Second job */ + void *data) /* I - App data (not used) */ +{ + int diff; /* Difference */ + + + (void)data; + + if ((diff = ((cupsd_job_t *)second)->completed_time - + ((cupsd_job_t *)first)->completed_time) != 0) + return (diff); + else + return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id); +} + + +/* * 'compare_jobs()' - Compare the job IDs of two jobs. */ @@ -4268,6 +4320,14 @@ load_job_cache(const char *filename) /* if (job->state_value <= IPP_JOB_STOPPED && cupsdLoadJob(job)) cupsArrayAdd(ActiveJobs, job); + else if (job->state_value > IPP_JOB_STOPPED) + { + if (!job->completed_time) + { + cupsdLoadJob(job); + unload_job(job); + } + } job = NULL; } @@ -4285,9 +4345,13 @@ load_job_cache(const char *filename) /* else if (job->state_value > IPP_JOB_COMPLETED) job->state_value = IPP_JOB_COMPLETED; } + else if (!_cups_strcasecmp(line, "Completed")) + { + job->completed_time = strtol(value, NULL, 10); + } else if (!_cups_strcasecmp(line, "HoldUntil")) { - job->hold_until = atoi(value); + job->hold_until = strtol(value, NULL, 10); } else if (!_cups_strcasecmp(line, "Priority")) { @@ -4625,6 +4689,8 @@ set_time(cupsd_job_t *job, /* I - Job t if (!strcmp(name, "time-at-completed")) { + job->completed_time = curtime; + if (JobHistory < INT_MAX && attr) job->history_time = attr->values[0].integer + JobHistory; else diff -up cups-1.7.5/scheduler/job.h.str4396 cups-1.7.5/scheduler/job.h --- cups-1.7.5/scheduler/job.h.str4396 2014-08-20 16:56:29.013022427 +0100 +++ cups-1.7.5/scheduler/job.h 2014-08-20 16:56:38.538084031 +0100 @@ -54,6 +54,7 @@ struct cupsd_job_s /**** Job request * ipp_attribute_t *sheets; /* job-media-sheets-completed */ time_t access_time, /* Last access time */ cancel_time, /* When to cancel/send SIGTERM */ + completed_time, /* When job was completed (0 if not) */ file_time, /* Job file retain time */ history_time, /* Job history retain time */ hold_until, /* Hold expiration date/time */ @@ -156,6 +157,7 @@ extern void cupsdDeleteJob(cupsd_job_t cupsd_jobaction_t action); extern cupsd_job_t *cupsdFindJob(int id); extern void cupsdFreeAllJobs(void); +extern cups_array_t *cupsdGetCompletedJobs(cupsd_printer_t *p); extern int cupsdGetPrinterJobCount(const char *dest); extern int cupsdGetUserJobCount(const char *username); extern void cupsdLoadAllJobs(void); diff -up cups-1.7.5/systemv/lpstat.c.str4396 cups-1.7.5/systemv/lpstat.c --- cups-1.7.5/systemv/lpstat.c.str4396 2014-05-22 14:59:21.000000000 +0100 +++ cups-1.7.5/systemv/lpstat.c 2014-08-20 16:56:38.539084037 +0100 @@ -1316,7 +1316,8 @@ show_jobs(const char *dests, /* I - Des const char *dest, /* Pointer into job-printer-uri */ *username, /* Pointer to job-originating-user-name */ *title, /* Pointer to job-name */ - *message; /* Pointer to job-printer-state-message */ + *message, /* Pointer to job-printer-state-message */ + *time_at; /* time-at-xxx attribute name to use */ int rank, /* Rank in queue */ jobid, /* job-id */ size; /* job-k-octets */ @@ -1332,7 +1333,8 @@ show_jobs(const char *dests, /* I - Des "job-printer-state-message", "job-printer-uri", "job-state-reasons", - "time-at-creation" + "time-at-creation", + "time-at-completed" }; @@ -1398,6 +1400,13 @@ show_jobs(const char *dests, /* I - Des * Loop through the job list and display them... */ + if (!strcmp(which, "aborted") || + !strcmp(which, "canceled") || + !strcmp(which, "completed")) + time_at = "time-at-completed"; + else + time_at = "time-at-creation"; + rank = -1; for (attr = response->attrs; attr != NULL; attr = attr->next) @@ -1433,8 +1442,7 @@ show_jobs(const char *dests, /* I - Des else if (!strcmp(attr->name, "job-k-octets") && attr->value_tag == IPP_TAG_INTEGER) size = attr->values[0].integer; - else if (!strcmp(attr->name, "time-at-creation") && - attr->value_tag == IPP_TAG_INTEGER) + else if (!strcmp(attr->name, time_at) && attr->value_tag == IPP_TAG_INTEGER) jobtime = attr->values[0].integer; else if (!strcmp(attr->name, "job-printer-state-message") && attr->value_tag == IPP_TAG_TEXT) diff -up cups-1.7.5/test/5.5-lp.sh.str4396 cups-1.7.5/test/5.5-lp.sh --- cups-1.7.5/test/5.5-lp.sh.str4396 2013-11-06 20:09:03.000000000 +0000 +++ cups-1.7.5/test/5.5-lp.sh 2014-08-20 16:56:38.540084044 +0100 @@ -79,6 +79,19 @@ echo "" ./waitjobs.sh +echo "LPSTAT Completed Jobs Order Test" +echo "" +echo " lpstat -W completed -o" +$VALGRIND ../systemv/lpstat -W completed -o | tee $BASE/lpstat-completed.txt +if test "`uniq -d $BASE/lpstat-completed.txt`" != ""; then + echo " FAILED" + exit 1 +else + echo " PASSED" +fi +echo "" + + # # End of "$Id: 5.5-lp.sh 11396 2013-11-06 20:09:03Z msweet $". #