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