diff -up cups-1.7.5/scheduler/ipp.c.str2913 cups-1.7.5/scheduler/ipp.c --- cups-1.7.5/scheduler/ipp.c.str2913 2014-08-20 17:19:25.216908923 +0100 +++ cups-1.7.5/scheduler/ipp.c 2014-08-20 17:21:45.641812985 +0100 @@ -1531,8 +1531,7 @@ add_job(cupsd_client_t *con, /* I - Cl } if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_ZERO)) == NULL) - ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, - "Untitled"); + ippAddString(con->request, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, "Untitled"); else if ((attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_NAMELANG) || attr->num_values != 1) @@ -1612,6 +1611,9 @@ add_job(cupsd_client_t *con, /* I - Cl ippDeleteAttribute(job->attrs, auth_info); } + if ((attr = ippFindAttribute(con->request, "job-name", IPP_TAG_NAME)) != NULL) + cupsdSetString(&(job->name), attr->values[0].string.text); + if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name", IPP_TAG_ZERO)) != NULL) { @@ -1706,8 +1708,7 @@ add_job(cupsd_client_t *con, /* I - Cl ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri", NULL, printer->uri); - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer = 0; else ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", 0); @@ -4357,8 +4358,9 @@ copy_banner(cupsd_client_t *con, /* I - kbytes = (cupsFileTell(out) + 1023) / 1024; - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + job->koctets += kbytes; + + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer += kbytes; cupsFileClose(out); @@ -4780,7 +4782,55 @@ copy_job_attrs(cupsd_client_t *con, /* I "job-uri", NULL, job_uri); } - copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude); + if (job->attrs) + { + copy_attrs(con->response, job->attrs, ra, IPP_TAG_JOB, 0, exclude); + } + else + { + /* + * Generate attributes from the job structure... + */ + + if (!ra || cupsArrayFind(ra, "job-id")) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-id", job->id); + + if (!ra || cupsArrayFind(ra, "job-k-octets")) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-k-octets", job->koctets); + + if (job->name && (!ra || cupsArrayFind(ra, "job-name"))) + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-name", NULL, job->name); + + if (job->username && (!ra || cupsArrayFind(ra, "job-originating-user-name"))) + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_NAME, "job-originating-user-name", NULL, job->username); + + if (!ra || cupsArrayFind(ra, "job-state")) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", (int)job->state_value); + + if (!ra || cupsArrayFind(ra, "job-state-reasons")) + { + switch (job->state_value) + { + default : /* Should never get here for processing, pending, held, or stopped jobs since they don't get unloaded... */ + break; + case IPP_JSTATE_ABORTED : + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-aborted-by-system"); + break; + case IPP_JSTATE_CANCELED : + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-canceled-by-user"); + break; + case IPP_JSTATE_COMPLETED : + ippAddString(con->response, IPP_TAG_JOB, IPP_TAG_KEYWORD, "job-state-reasons", NULL, "job-completed-successfully"); + break; + } + } + + if (job->completed_time && (!ra || cupsArrayFind(ra, "time-at-completed"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-completed", (int)job->completed_time); + + if (job->completed_time && (!ra || cupsArrayFind(ra, "time-at-creation"))) + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_INTEGER, "time-at-creation", (int)job->creation_time); + } } @@ -6133,9 +6183,13 @@ get_jobs(cupsd_client_t *con, /* I - C int port; /* Port portion of URI */ int job_comparison; /* Job comparison */ ipp_jstate_t job_state; /* job-state value */ - int first_job_id; /* First job ID */ - int limit; /* Maximum number of jobs to return */ + int first_job_id = 1, /* First job ID */ + first_index = 1, /* First index */ + current_index = 0; /* Current index */ + int limit = 0; /* Maximum number of jobs to return */ int count; /* Number of jobs that match */ + int need_load_job = 0; /* Do we need to load the job? */ + const char *job_attr; /* Job attribute requested */ ipp_attribute_t *job_ids; /* job-ids attribute */ cupsd_job_t *job; /* Current job pointer */ cupsd_printer_t *printer; /* Printer */ @@ -6301,8 +6355,7 @@ get_jobs(cupsd_client_t *con, /* I - C * See if they want to limit the number of jobs reported... */ - if ((attr = ippFindAttribute(con->request, "limit", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL) { if (job_ids) { @@ -6314,11 +6367,20 @@ get_jobs(cupsd_client_t *con, /* I - C limit = attr->values[0].integer; } - else - limit = 0; - if ((attr = ippFindAttribute(con->request, "first-job-id", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(con->request, "first-index", IPP_TAG_INTEGER)) != NULL) + { + if (job_ids) + { + send_ipp_status(con, IPP_CONFLICT, + _("The %s attribute cannot be provided with job-ids."), + "first-index"); + return; + } + + first_index = attr->values[0].integer; + } + else if ((attr = ippFindAttribute(con->request, "first-job-id", IPP_TAG_INTEGER)) != NULL) { if (job_ids) { @@ -6330,15 +6392,12 @@ get_jobs(cupsd_client_t *con, /* I - C first_job_id = attr->values[0].integer; } - else - first_job_id = 1; /* * See if we only want to see jobs for a specific user... */ - if ((attr = ippFindAttribute(con->request, "my-jobs", - IPP_TAG_BOOLEAN)) != NULL && job_ids) + if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && job_ids) { send_ipp_status(con, IPP_CONFLICT, _("The %s attribute cannot be provided with job-ids."), @@ -6351,6 +6410,43 @@ get_jobs(cupsd_client_t *con, /* I - C username[0] = '\0'; ra = create_requested_array(con->request); + for (job_attr = (char *)cupsArrayFirst(ra); job_attr; job_attr = (char *)cupsArrayNext(ra)) + if (strcmp(job_attr, "job-id") && + strcmp(job_attr, "job-k-octets") && + strcmp(job_attr, "job-media-progress") && + strcmp(job_attr, "job-more-info") && + strcmp(job_attr, "job-name") && + strcmp(job_attr, "job-originating-user-name") && + strcmp(job_attr, "job-preserved") && + strcmp(job_attr, "job-printer-up-time") && + strcmp(job_attr, "job-printer-uri") && + strcmp(job_attr, "job-state") && + strcmp(job_attr, "job-state-reasons") && + strcmp(job_attr, "job-uri") && + strcmp(job_attr, "time-at-completed") && + strcmp(job_attr, "time-at-creation") && + strcmp(job_attr, "number-of-documents")) + { + need_load_job = 1; + break; + } + + if (need_load_job && (limit == 0 || limit > 500) && (list == Jobs || delete_list)) + { + /* + * Limit expensive Get-Jobs for job history to 500 jobs... + */ + + ippAddInteger(con->response, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "limit", 500); + + if (limit) + ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, "limit", limit); + + limit = 500; + + cupsdLogMessage(CUPSD_LOG_INFO, + "Limiting Get-Jobs response to %d jobs.", limit); + } /* * OK, build a list of jobs for this printer... @@ -6377,13 +6473,15 @@ get_jobs(cupsd_client_t *con, /* I - C { job = cupsdFindJob(job_ids->values[i].integer); - cupsdLoadJob(job); - - if (!job->attrs) + if (need_load_job && !job->attrs) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", - job->id); - continue; + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } } if (i > 0) @@ -6433,13 +6531,19 @@ get_jobs(cupsd_client_t *con, /* I - C if (job->id < first_job_id) continue; - cupsdLoadJob(job); + current_index ++; + if (current_index < first_index) + continue; - if (!job->attrs) + if (need_load_job && !job->attrs) { - cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", - job->id); - continue; + cupsdLoadJob(job); + + if (!job->attrs) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs: No attributes for job %d", job->id); + continue; + } } if (username[0] && _cups_strcasecmp(username, job->username)) @@ -8173,8 +8277,9 @@ print_job(cupsd_client_t *con, /* I - cupsdUpdateQuota(printer, job->username, 0, kbytes); - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + job->koctets += kbytes; + + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer += kbytes; /* @@ -9410,8 +9515,9 @@ send_document(cupsd_client_t *con, /* I cupsdUpdateQuota(printer, job->username, 0, kbytes); - if ((attr = ippFindAttribute(job->attrs, "job-k-octets", - IPP_TAG_INTEGER)) != NULL) + job->koctets += kbytes; + + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) attr->values[0].integer += kbytes; snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, diff -up cups-1.7.5/scheduler/job.c.str2913 cups-1.7.5/scheduler/job.c --- cups-1.7.5/scheduler/job.c.str2913 2014-08-20 17:19:25.261909213 +0100 +++ cups-1.7.5/scheduler/job.c 2014-08-20 17:19:25.272909284 +0100 @@ -1707,9 +1707,10 @@ cupsdLoadJob(cupsd_job_t *job) /* I - J job->file_time = 0; job->history_time = 0; - if (job->state_value >= IPP_JOB_CANCELED && - (attr = ippFindAttribute(job->attrs, "time-at-completed", - IPP_TAG_INTEGER)) != NULL) + if ((attr = ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER)) != NULL) + job->creation_time = attr->values[0].integer; + + if (job->state_value >= IPP_JOB_CANCELED && (attr = ippFindAttribute(job->attrs, "time-at-completed", IPP_TAG_INTEGER)) != NULL) { job->completed_time = attr->values[0].integer; @@ -1858,6 +1859,12 @@ cupsdLoadJob(cupsd_job_t *job) /* I - J cupsdSetString(&job->username, attr->values[0].string.text); } + if (!job->name) + { + if ((attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL) + cupsdSetString(&job->name, attr->values[0].string.text); + } + /* * Set the job hold-until time and state... */ @@ -1882,6 +1889,9 @@ cupsdLoadJob(cupsd_job_t *job) /* I - J job->state_value = IPP_JOB_PENDING; } + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) + job->koctets = attr->values[0].integer; + if (!job->num_files) { /* @@ -2190,14 +2200,18 @@ cupsdSaveAllJobs(void) { cupsFilePrintf(fp, "\n", job->id); cupsFilePrintf(fp, "State %d\n", job->state_value); + cupsFilePrintf(fp, "Created %ld\n", (long)job->creation_time); if (job->completed_time) cupsFilePrintf(fp, "Completed %ld\n", (long)job->completed_time); cupsFilePrintf(fp, "Priority %d\n", job->priority); if (job->hold_until) cupsFilePrintf(fp, "HoldUntil %ld\n", (long)job->hold_until); cupsFilePrintf(fp, "Username %s\n", job->username); + if (job->name) + cupsFilePutConf(fp, "Name", job->name); cupsFilePrintf(fp, "Destination %s\n", job->dest); cupsFilePrintf(fp, "DestType %d\n", job->dtype); + cupsFilePrintf(fp, "KOctets %d\n", job->koctets); 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, @@ -4138,7 +4152,7 @@ load_job_cache(const char *filename) /* cupsArrayAdd(ActiveJobs, job); else if (job->state_value > IPP_JOB_STOPPED) { - if (!job->completed_time) + if (!job->completed_time || !job->creation_time || !job->name || !job->koctets) { cupsdLoadJob(job); unload_job(job); @@ -4161,6 +4175,14 @@ 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, "Name")) + { + cupsdSetString(&(job->name), value); + } + else if (!_cups_strcasecmp(line, "Created")) + { + job->creation_time = strtol(value, NULL, 10); + } else if (!_cups_strcasecmp(line, "Completed")) { job->completed_time = strtol(value, NULL, 10); @@ -4185,6 +4207,10 @@ load_job_cache(const char *filename) /* { job->dtype = (cups_ptype_t)atoi(value); } + else if (!_cups_strcasecmp(line, "KOctets")) + { + job->koctets = atoi(value); + } else if (!_cups_strcasecmp(line, "NumFiles")) { job->num_files = atoi(value); diff -up cups-1.7.5/scheduler/job.h.str2913 cups-1.7.5/scheduler/job.h --- cups-1.7.5/scheduler/job.h.str2913 2014-08-20 17:19:25.196908795 +0100 +++ cups-1.7.5/scheduler/job.h 2014-08-20 17:19:25.273909291 +0100 @@ -39,6 +39,8 @@ struct cupsd_job_s /**** Job request * * waiting on files */ char *username; /* Printing user */ char *dest; /* Destination printer or class */ + char *name; /* Job name/title */ + int koctets; /* job-k-octets */ cups_ptype_t dtype; /* Destination type */ cupsd_printer_t *printer; /* Printer this job is assigned to */ int num_files; /* Number of files in job */ @@ -47,6 +49,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 */ + creation_time, /* When job was created */ completed_time, /* When job was completed (0 if not) */ file_time, /* Job file retain time */ history_time, /* Job history retain time */