]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/job.c
Fix an issue with and time values (Issue #5538)
[thirdparty/cups.git] / scheduler / job.c
index 11412face92b626ee36049640211bbd706eaf08c..4f041388c47c9949b2dc5f26627984d4d5a68dd4 100644 (file)
@@ -1,14 +1,14 @@
 /*
  * Job management routines for the CUPS scheduler.
  *
- * Copyright 2007-2016 by Apple Inc.
+ * Copyright 2007-2019 by Apple Inc.
  * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  * These coded instructions, statements, and computer programs are the
  * property of Apple Inc. and are protected by Federal copyright
  * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
  * which should have been included with this file.  If this file is
- * file is missing or damaged, see the license at "http://www.cups.org/".
+ * missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
@@ -437,10 +437,20 @@ cupsdCleanJobs(void)
   curtime          = time(NULL);
   JobHistoryUpdate = 0;
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: curtime=%d", (int)curtime);
+
   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
        job;
        job = (cupsd_job_t *)cupsArrayNext(Jobs))
   {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: Job %d, state=%d, printer=%p, history_time=%d, file_time=%d", job->id, (int)job->state_value, (void *)job->printer, (int)job->history_time, (int)job->file_time);
+
+    if ((job->history_time && job->history_time) < JobHistoryUpdate || !JobHistoryUpdate)
+      JobHistoryUpdate = job->history_time;
+
+    if ((job->file_time && job->file_time < JobHistoryUpdate) || !JobHistoryUpdate)
+      JobHistoryUpdate = job->file_time;
+
     if (job->state_value >= IPP_JOB_CANCELED && !job->printer)
     {
      /*
@@ -459,17 +469,6 @@ cupsdCleanJobs(void)
         remove_job_files(job);
 
         cupsdMarkDirty(CUPSD_DIRTY_JOBS);
-
-        if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
-         JobHistoryUpdate = job->history_time;
-      }
-      else
-      {
-        if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
-         JobHistoryUpdate = job->history_time;
-
-       if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
-         JobHistoryUpdate = job->file_time;
       }
     }
   }
@@ -1728,7 +1727,7 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
     job->completed_time = attr->values[0].integer;
 
     if (JobHistory < INT_MAX)
-      job->history_time = attr->values[0].integer + JobHistory;
+      job->history_time = job->completed_time + JobHistory;
     else
       job->history_time = INT_MAX;
 
@@ -1739,10 +1738,12 @@ cupsdLoadJob(cupsd_job_t *job)          /* I - Job */
       JobHistoryUpdate = job->history_time;
 
     if (JobFiles < INT_MAX)
-      job->file_time = attr->values[0].integer + JobFiles;
+      job->file_time = job->completed_time + JobFiles;
     else
       job->file_time = INT_MAX;
 
+    cupsdLogJob(job, CUPSD_LOG_DEBUG2, "cupsdLoadJob: job->file_time=%ld, time-at-completed=%ld, JobFiles=%d", (long)job->file_time, (long)attr->values[0].integer, JobFiles);
+
     if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
       JobHistoryUpdate = job->file_time;
 
@@ -1847,6 +1848,8 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
 
   if (!job->impressions)
     job->impressions = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", 0);
+  if (!job->sheets)
+    job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-media-sheets-completed", 0);
 
   if (!job->priority)
   {
@@ -2765,7 +2768,7 @@ cupsdSetJobState(
   * Update the server "busy" state...
   */
 
-  cupsdSetBusyState();
+  cupsdSetBusyState(0);
 }
 
 
@@ -2857,8 +2860,10 @@ cupsdUpdateJobs(void)
       * Update history/file expiration times...
       */
 
+      job->completed_time = attr->values[0].integer;
+
       if (JobHistory < INT_MAX)
-       job->history_time = attr->values[0].integer + JobHistory;
+       job->history_time = job->completed_time + JobHistory;
       else
        job->history_time = INT_MAX;
 
@@ -2872,16 +2877,18 @@ cupsdUpdateJobs(void)
        JobHistoryUpdate = job->history_time;
 
       if (JobFiles < INT_MAX)
-       job->file_time = attr->values[0].integer + JobFiles;
+       job->file_time = job->completed_time + JobFiles;
       else
        job->file_time = INT_MAX;
 
+      cupsdLogJob(job, CUPSD_LOG_DEBUG2, "cupsdUpdateJobs: job->file_time=%ld, time-at-completed=%ld, JobFiles=%d", (long)job->file_time, (long)attr->values[0].integer, JobFiles);
+
       if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
        JobHistoryUpdate = job->file_time;
     }
   }
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdUpdateAllJobs: JobHistoryUpdate=%ld",
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdUpdateJobs: JobHistoryUpdate=%ld",
                   (long)JobHistoryUpdate);
 }
 
@@ -3149,6 +3156,13 @@ finalize_job(cupsd_job_t *job,           /* I - Job */
   cupsdStatBufDelete(job->status_buffer);
   job->status_buffer = NULL;
 
+ /*
+  * Log the final impression (page) count...
+  */
+
+  snprintf(buffer, sizeof(buffer), "total %d", ippGetInteger(job->impressions, 0));
+  cupsdLogPage(job, buffer);
+
  /*
   * Process the exit status...
   */
@@ -3206,7 +3220,7 @@ finalize_job(cupsd_job_t *job,            /* I - Job */
 
    /*
     * Convert the status to an exit code.  Due to the way the W* macros are
-    * implemented on MacOS X (bug?), we have to store the exit status in a
+    * implemented on macOS (bug?), we have to store the exit status in a
     * variable first and then convert...
     */
 
@@ -3325,8 +3339,14 @@ finalize_job(cupsd_job_t *job,           /* I - Job */
                   job_state == IPP_JOB_COMPLETED)
          {
            job_state = IPP_JOB_ABORTED;
-           message   = "Job aborted due to backend errors; please consult "
-                       "the error_log file for details.";
+
+           if (ErrorLog)
+           {
+             snprintf(buffer, sizeof(buffer), "Job aborted due to backend errors; please consult the %s file for details.", ErrorLog);
+             message = buffer;
+            }
+            else
+             message = "Job aborted due to backend errors.";
 
            ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system");
          }
@@ -3334,8 +3354,14 @@ finalize_job(cupsd_job_t *job,           /* I - Job */
           {
             job_state     = IPP_JOB_PENDING;
            printer_state = IPP_PRINTER_STOPPED;
-           message       = "Printer stopped due to backend errors; please "
-                           "consult the error_log file for details.";
+
+           if (ErrorLog)
+           {
+             snprintf(buffer, sizeof(buffer), "Printer stopped due to backend errors; please consult the %s file for details.", ErrorLog);
+             message = buffer;
+            }
+            else
+             message = "Printer stopped due to backend errors.";
 
            ippSetString(job->attrs, &job->reasons, 0, "none");
          }
@@ -3373,15 +3399,20 @@ finalize_job(cupsd_job_t *job,          /* I - Job */
 
              ippSetString(job->attrs, &job->reasons, 0,
                           "job-hold-until-specified");
-             message = "Job held indefinitely due to backend errors; please "
-                       "consult the error_log file for details.";
+
+             if (ErrorLog)
+             {
+               snprintf(buffer, sizeof(buffer), "Job held indefinitely due to backend errors; please consult the %s file for details.", ErrorLog);
+               message = buffer;
+             }
+             else
+               message = "Job held indefinitely due to backend errors.";
             }
             else if (!strcmp(reason, "account-info-needed"))
             {
              cupsdSetJobHoldUntil(job, "indefinite", 0);
 
-             message = "Job held indefinitely - account information is "
-                       "required.";
+             message = "Job held indefinitely - account information is required.";
             }
             else if (!strcmp(reason, "account-closed"))
             {
@@ -3393,8 +3424,7 @@ finalize_job(cupsd_job_t *job,            /* I - Job */
             {
              cupsdSetJobHoldUntil(job, "indefinite", 0);
 
-             message = "Job held indefinitely - account limit has been "
-                       "reached.";
+             message = "Job held indefinitely - account limit has been reached.";
            }
             else
             {
@@ -3412,16 +3442,27 @@ finalize_job(cupsd_job_t *job,          /* I - Job */
          * Stop the printer...
          */
 
+          if (job_state == IPP_JSTATE_CANCELED || job_state == IPP_JSTATE_ABORTED)
+          {
+            cupsdLogJob(job, CUPSD_LOG_INFO, "Ignored STOP from backend since the job is %s.", job_state == IPP_JSTATE_CANCELED ? "canceled" : "aborted");
+            break;
+         }
+
          printer_state = IPP_PRINTER_STOPPED;
-         message       = "Printer stopped due to backend errors; please "
-                         "consult the error_log file for details.";
+
+         if (ErrorLog)
+         {
+           snprintf(buffer, sizeof(buffer), "Printer stopped due to backend errors; please consult the %s file for details.", ErrorLog);
+           message = buffer;
+         }
+         else
+           message = "Printer stopped due to backend errors.";
 
          if (job_state == IPP_JOB_COMPLETED)
          {
            job_state = IPP_JOB_PENDING;
 
-           ippSetString(job->attrs, &job->reasons, 0,
-                        "resources-are-not-ready");
+           ippSetString(job->attrs, &job->reasons, 0, "resources-are-not-ready");
          }
           break;
 
@@ -3511,8 +3552,14 @@ finalize_job(cupsd_job_t *job,           /* I - Job */
     if (job_state == IPP_JOB_COMPLETED)
     {
       job_state = IPP_JOB_STOPPED;
-      message   = "Job stopped due to filter errors; please consult the "
-                 "error_log file for details.";
+
+      if (ErrorLog)
+      {
+       snprintf(buffer, sizeof(buffer), "Job stopped due to filter errors; please consult the %s file for details.", ErrorLog);
+       message = buffer;
+      }
+      else
+       message = "Job stopped due to filter errors.";
 
       if (WIFSIGNALED(job->status))
        ippSetString(job->attrs, &job->reasons, 0, "cups-filter-crashed");
@@ -3544,6 +3591,13 @@ finalize_job(cupsd_job_t *job,           /* I - Job */
 
   cupsArrayRemove(PrintingJobs, job);
 
+ /*
+  * Clear informational messages...
+  */
+
+  if (job->status_level > CUPSD_LOG_ERROR)
+    job->printer->state_message[0] = '\0';
+
  /*
   * Apply any PPD updates...
   */
@@ -3612,12 +3666,9 @@ get_options(cupsd_job_t *job,            /* I - Job */
   pwgppds     = NULL;
 
   if (pc &&
-      !ippFindAttribute(job->attrs,
-                        "com.apple.print.DocumentTicket.PMSpoolFormat",
-                       IPP_TAG_ZERO) &&
+      !ippFindAttribute(job->attrs, "com.apple.print.DocumentTicket.PMSpoolFormat", IPP_TAG_ZERO) &&
       !ippFindAttribute(job->attrs, "APPrinterPreset", IPP_TAG_ZERO) &&
-      (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) ||
-       ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO)))
+      (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_ZERO)))
   {
    /*
     * Map print-color-mode and print-quality to a preset...
@@ -3630,13 +3681,36 @@ get_options(cupsd_job_t *job,           /* I - Job */
     else
       print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
 
-    if ((attr = ippFindAttribute(job->attrs, "print-quality",
-                                IPP_TAG_ENUM)) != NULL &&
-       attr->values[0].integer >= IPP_QUALITY_DRAFT &&
-       attr->values[0].integer <= IPP_QUALITY_HIGH)
-      print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT;
+    if ((attr = ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM)) != NULL)
+    {
+      ipp_quality_t pq = (ipp_quality_t)ippGetInteger(attr, 0);
+
+      if (pq >= IPP_QUALITY_DRAFT && pq <= IPP_QUALITY_HIGH)
+        print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT;
+      else
+        print_quality = _PWG_PRINT_QUALITY_NORMAL;
+    }
+    else if ((attr = ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_NAME)) != NULL)
+    {
+      const char *pq = ippGetString(attr, 0, NULL);
+
+      if (!_cups_strcasecmp(pq, "draft"))
+        print_quality = _PWG_PRINT_QUALITY_DRAFT;
+      else if (!_cups_strcasecmp(pq, "high"))
+        print_quality = _PWG_PRINT_QUALITY_HIGH;
+      else
+        print_quality = _PWG_PRINT_QUALITY_NORMAL;
+
+      if (!ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM))
+      {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping cupsPrintQuality=%s to print-quality=%d", pq, print_quality + IPP_QUALITY_DRAFT);
+        num_pwgppds = cupsAddIntegerOption("print-quality", print_quality + IPP_QUALITY_DRAFT, num_pwgppds, &pwgppds);
+      }
+    }
     else
+    {
       print_quality = _PWG_PRINT_QUALITY_NORMAL;
+    }
 
     if (pc->num_presets[print_color_mode][print_quality] == 0)
     {
@@ -3669,14 +3743,30 @@ get_options(cupsd_job_t *job,           /* I - Job */
           i --, preset ++)
       {
         if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO))
-         num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds,
-                                     &pwgppds);
+        {
+          cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding preset option %s=%s", preset->name, preset->value);
+
+         num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds, &pwgppds);
+        }
       }
     }
   }
 
   if (pc)
   {
+    if ((attr = ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM)) != NULL)
+    {
+      int pq = ippGetInteger(attr, 0);
+      static const char * const pqs[] = { "Draft", "Normal", "High" };
+
+      if (pq >= IPP_QUALITY_DRAFT && pq <= IPP_QUALITY_HIGH)
+      {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping print-quality=%d to cupsPrintQuality=%s", pq, pqs[pq - IPP_QUALITY_DRAFT]);
+
+        num_pwgppds = cupsAddOption("cupsPrintQuality", pqs[pq - IPP_QUALITY_DRAFT], num_pwgppds, &pwgppds);
+      }
+    }
+
     if (!ippFindAttribute(job->attrs, "InputSlot", IPP_TAG_ZERO) &&
        !ippFindAttribute(job->attrs, "HPPaperSource", IPP_TAG_ZERO))
     {
@@ -3686,16 +3776,26 @@ get_options(cupsd_job_t *job,           /* I - Job */
     }
     if (!ippFindAttribute(job->attrs, "MediaType", IPP_TAG_ZERO) &&
        (ppd = _ppdCacheGetMediaType(pc, job->attrs, NULL)) != NULL)
+    {
+      cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping media to MediaType=%s", ppd);
+
       num_pwgppds = cupsAddOption("MediaType", ppd, num_pwgppds, &pwgppds);
+    }
 
     if (!ippFindAttribute(job->attrs, "PageRegion", IPP_TAG_ZERO) &&
        !ippFindAttribute(job->attrs, "PageSize", IPP_TAG_ZERO) &&
        (ppd = _ppdCacheGetPageSize(pc, job->attrs, NULL, &exact)) != NULL)
     {
+      cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping media to Pagesize=%s", ppd);
+
       num_pwgppds = cupsAddOption("PageSize", ppd, num_pwgppds, &pwgppds);
 
       if (!ippFindAttribute(job->attrs, "media", IPP_TAG_ZERO))
+      {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding media=%s", ppd);
+
         num_pwgppds = cupsAddOption("media", ppd, num_pwgppds, &pwgppds);
+      }
     }
 
     if (!ippFindAttribute(job->attrs, "OutputBin", IPP_TAG_ZERO) &&
@@ -3709,6 +3809,8 @@ get_options(cupsd_job_t *job,             /* I - Job */
       * Map output-bin to OutputBin option...
       */
 
+      cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping output-bin to OutputBin=%s", ppd);
+
       num_pwgppds = cupsAddOption("OutputBin", ppd, num_pwgppds, &pwgppds);
     }
 
@@ -3721,23 +3823,33 @@ get_options(cupsd_job_t *job,           /* I - Job */
       */
 
       if (!strcmp(attr->values[0].string.text, "one-sided"))
-        num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_1sided,
-                                   num_pwgppds, &pwgppds);
+      {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_1sided);
+
+        num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_1sided, num_pwgppds, &pwgppds);
+      }
       else if (!strcmp(attr->values[0].string.text, "two-sided-long-edge"))
-        num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_long,
-                                   num_pwgppds, &pwgppds);
+      {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_2sided_long);
+
+        num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_long, num_pwgppds, &pwgppds);
+      }
       else if (!strcmp(attr->values[0].string.text, "two-sided-short-edge"))
-        num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_short,
-                                   num_pwgppds, &pwgppds);
+      {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_2sided_short);
+
+        num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_short, num_pwgppds, &pwgppds);
+      }
     }
 
    /*
     * Map finishings values...
     */
 
-    num_pwgppds = _ppdCacheGetFinishingOptions(pc, job->attrs,
-                                               IPP_FINISHINGS_NONE, num_pwgppds,
-                                               &pwgppds);
+    num_pwgppds = _ppdCacheGetFinishingOptions(pc, job->attrs, IPP_FINISHINGS_NONE, num_pwgppds, &pwgppds);
+
+    for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
+      cupsdLogJob(job, CUPSD_LOG_DEBUG2, "After mapping finishings %s=%s", pwgppd->name, pwgppd->value);
   }
 
  /*
@@ -4586,7 +4698,7 @@ set_time(cupsd_job_t *job,                /* I - Job to update */
     job->completed_time = curtime;
 
     if (JobHistory < INT_MAX && attr)
-      job->history_time = attr->values[0].integer + JobHistory;
+      job->history_time = job->completed_time + JobHistory;
     else
       job->history_time = INT_MAX;
 
@@ -4594,7 +4706,7 @@ set_time(cupsd_job_t *job,                /* I - Job to update */
       JobHistoryUpdate = job->history_time;
 
     if (JobFiles < INT_MAX && attr)
-      job->file_time = attr->values[0].integer + JobFiles;
+      job->file_time = job->completed_time + JobFiles;
     else
       job->file_time = INT_MAX;
 
@@ -4704,6 +4816,18 @@ start_job(cupsd_job_t     *job,          /* I - Job ID */
   job->profile  = cupsdCreateProfile(job->id, 0);
   job->bprofile = cupsdCreateProfile(job->id, 1);
 
+#ifdef HAVE_SANDBOX_H
+  if ((!job->profile || !job->bprofile) && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF)
+  {
+   /*
+    * Failure to create the sandbox profile means something really bad has
+    * happened and we need to shutdown immediately.
+    */
+
+    return;
+  }
+#endif /* HAVE_SANDBOX_H */
+
  /*
   * Create the status pipes and buffer...
   */
@@ -4883,7 +5007,6 @@ void
 update_job(cupsd_job_t *job)           /* I - Job to check */
 {
   int          i;                      /* Looping var */
-  int          copies;                 /* Number of copies printed */
   char         message[CUPSD_SB_BUFFER_SIZE],
                                        /* Message text */
                *ptr;                   /* Pointer update... */
@@ -4921,6 +5044,10 @@ update_job(cupsd_job_t *job)             /* I - Job to check */
 
     if (loglevel == CUPSD_LOG_PAGE)
     {
+      int      impressions = ippGetInteger(job->impressions, 0);
+                               /* Number of impressions printed */
+      int      delta;          /* Number of impressions added */
+
      /*
       * Page message; send the message to the page_log file and update the
       * job sheet count...
@@ -4928,51 +5055,57 @@ update_job(cupsd_job_t *job)            /* I - Job to check */
 
       cupsdLogJob(job, CUPSD_LOG_DEBUG, "PAGE: %s", message);
 
-      if (job->impressions)
+      if (!_cups_strncasecmp(message, "total ", 6))
       {
-        if (!_cups_strncasecmp(message, "total ", 6))
-       {
-        /*
-         * Got a total count of pages from a backend or filter...
-         */
+       /*
+       * Got a total count of pages from a backend or filter...
+       */
 
-         copies = atoi(message + 6);
-         copies -= ippGetInteger(job->impressions, 0); /* Just track the delta */
+       int total = atoi(message + 6);  /* Total impressions */
+
+       if (total > impressions)
+       {
+         delta       = total - impressions;
+         impressions = total;
        }
-       else if (!sscanf(message, "%*d%d", &copies))
+       else
+         delta = 0;
+      }
+      else
+      {
+       /*
+        * Add the number of copies to the impression count...
+        */
+
+       int copies;                     /* Number of copies */
+
+       if (!sscanf(message, "%*d%d", &copies) || copies <= 0)
          copies = 1;
 
-        ippSetInteger(job->attrs, &job->impressions, 0, ippGetInteger(job->impressions, 0) + copies);
-        job->dirty = 1;
-       cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+        delta = copies;
+       impressions += copies;
       }
 
+      if (job->impressions)
+        ippSetInteger(job->attrs, &job->impressions, 0, impressions);
+
       if (job->sheets)
       {
-        if (!_cups_strncasecmp(message, "total ", 6))
-       {
-        /*
-         * Got a total count of pages from a backend or filter...
-         */
+       const char *sides = ippGetString(ippFindAttribute(job->attrs, "sides", IPP_TAG_KEYWORD), 0, NULL);
 
-         copies = atoi(message + 6);
-         copies -= ippGetInteger(job->sheets, 0); /* Just track the delta */
-       }
-       else if (!sscanf(message, "%*d%d", &copies))
-         copies = 1;
-
-        ippSetInteger(job->attrs, &job->sheets, 0, ippGetInteger(job->sheets, 0) + copies);
-        job->dirty = 1;
-       cupsdMarkDirty(CUPSD_DIRTY_JOBS);
+        if (sides && strcmp(sides, "one-sided"))
+          ippSetInteger(job->attrs, &job->sheets, 0, impressions / 2);
+       else
+          ippSetInteger(job->attrs, &job->sheets, 0, impressions);
 
-       if (job->printer->page_limit)
-         cupsdUpdateQuota(job->printer, job->username, copies, 0);
+       cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, "Printed %d page(s).", ippGetInteger(job->sheets, 0));
       }
 
-      cupsdLogPage(job, message);
+      job->dirty = 1;
+      cupsdMarkDirty(CUPSD_DIRTY_JOBS);
 
-      if (job->sheets)
-       cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, "Printed %d page(s).", ippGetInteger(job->sheets, 0));
+      if (job->printer->page_limit)
+       cupsdUpdateQuota(job->printer, job->username, delta, 0);
     }
     else if (loglevel == CUPSD_LOG_JOBSTATE)
     {
@@ -5020,8 +5153,10 @@ update_job(cupsd_job_t *job)             /* I - Job to check */
 
             if (cancel_after)
              job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
-           else
+           else if (MaxJobTime > 0)
              job->cancel_time = time(NULL) + MaxJobTime;
+           else
+             job->cancel_time = 0;
          }
         }
       }