]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/job.c
Change new keyword to "cups-waiting-for-job-completed" (<rdar://problem/14323704>)
[thirdparty/cups.git] / scheduler / job.c
index a2ef65f71948f3344a50f829ef306b74155c4ec9..626d8bdbb7ba8c326abf060100b6fe6b97bfb7f2 100644 (file)
@@ -1,71 +1,16 @@
 /*
- * "$Id: job.c 7902 2008-09-03 14:20:17Z mike $"
+ * "$Id$"
  *
- *   Job management routines for the CUPS scheduler.
+ * Job management routines for the CUPS scheduler.
  *
- *   Copyright 2007-2012 by Apple Inc.
- *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2013 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/".
- *
- * Contents:
- *
- *   cupsdAddJob()             - Add a new job to the job queue.
- *   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.
- *   cupsdContinueJob()        - Continue printing with the next file in a
- *                               job.
- *   cupsdDeleteJob()          - Free all memory used by 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.
- *   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.
- *   cupsdSetJobState()        - Set the state of the specified print job.
- *   cupsdStopAllJobs()        - Stop all print jobs.
- *   cupsdUnloadCompletedJobs() - Flush completed job history from memory.
- *   cupsdUpdateJobs()          - Update the history/file files for all jobs.
- *   compare_active_jobs()     - Compare the job IDs and priorities of two
- *                               jobs.
- *   compare_jobs()            - Compare the job IDs of two jobs.
- *   dump_job_history()        - Dump any debug messages for a job.
- *   free_job_history()        - Free any log history.
- *   finalize_job()            - Cleanup after job filter processes and
- *                               support data.
- *   get_options()             - Get a string containing the job options.
- *   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.
- *   remove_job_files()        - Remove the document files for a job.
- *   remove_job_history()      - Remove the control file for a job.
- *   set_time()                - Set one of the "time-at-xyz" attributes.
- *   start_job()               - Start a print job.
- *   stop_job()                - Stop a print job.
- *   unload_job()              - Unload a job from memory.
- *   update_job()              - Read a status update from a job's filters.
- *   update_job_attrs()        - Update the job-printer-* attributes.
+ * 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/".
  */
 
 /*
@@ -312,8 +257,8 @@ cupsdCheckJobs(void)
 
     if (job->kill_time && job->kill_time <= curtime)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Stopping unresponsive job.",
-                     job->id);
+      if (!job->completed)
+        cupsdLogJob(job, CUPSD_LOG_ERROR, "Stopping unresponsive job.");
 
       stop_job(job, CUPSD_JOB_FORCE);
       continue;
@@ -325,8 +270,12 @@ cupsdCheckJobs(void)
 
     if (job->cancel_time && job->cancel_time <= curtime)
     {
-      cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
-                       "Canceling stuck job after %d seconds.", MaxJobTime);
+      if (job->completed)
+       cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_FORCE,
+                        "Marking stuck job as completed after %d seconds.", MaxJobTime);
+      else
+       cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
+                        "Canceling stuck job after %d seconds.", MaxJobTime);
       continue;
     }
 
@@ -379,10 +328,7 @@ cupsdCheckJobs(void)
     */
 
     if (job->state_value == IPP_JOB_PENDING && !NeedReload &&
-#ifndef kIOPMAssertionTypeDenySystemSleep
-        !Sleeping &&
-#endif /* !kIOPMAssertionTypeDenySystemSleep */
-        !DoingShutdown && !job->printer)
+        !Sleeping && !DoingShutdown && !job->printer)
     {
       printer = cupsdFindDest(job->dest);
       pclass  = NULL;
@@ -671,6 +617,9 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
                   "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super,
                   filter->dst->type);
       }
+      else
+        snprintf(final_content_type, sizeof(final_content_type),
+                 "FINAL_CONTENT_TYPE=printer/%s", job->printer->name);
     }
 
    /*
@@ -756,9 +705,8 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
   * Add decompression/raw filter as needed...
   */
 
-  if ((!job->printer->raw && job->compressions[job->current_file]) ||
-      (!filters && !job->printer->remote &&
-       (job->num_files > 1 || !strncmp(job->printer->device_uri, "file:", 5))))
+  if (job->compressions[job->current_file] &&
+      (!job->printer->remote || job->num_files == 1))
   {
    /*
     * Add gziptoany filter to the front of the list...
@@ -926,7 +874,7 @@ cupsdContinueJob(cupsd_job_t *job)  /* I - Job */
   {
     snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
              job->id, job->current_file + 1);
-    argv[6] = filename;
+    argv[6] = strdup(filename);
   }
 
   for (i = 0; argv[i]; i ++)
@@ -1311,13 +1259,11 @@ cupsdContinueJob(cupsd_job_t *job)      /* I - Job */
 
   cupsdClosePipe(filterfds[slot]);
 
-  if (job->printer->remote && job->num_files > 1)
-  {
-    for (i = 0; i < job->num_files; i ++)
-      free(argv[i + 6]);
-  }
+  for (i = 0; i < job->num_files; i ++)
+    free(argv[i + 6]);
 
   free(argv);
+
   if (printer_state_reasons)
     free(printer_state_reasons);
 
@@ -1637,7 +1583,7 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
   * Load job attributes...
   */
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Loading attributes...", job->id);
+  cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading attributes...");
 
   snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, job->id);
   if ((fp = cupsdOpenConfFile(jobfile)) == NULL)
@@ -1645,9 +1591,8 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
 
   if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, job->attrs) != IPP_DATA)
   {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                   "[Job %d] Unable to read job control file \"%s\".", job->id,
-                   jobfile);
+    cupsdLogJob(job, CUPSD_LOG_ERROR,
+               "Unable to read job control file \"%s\".", jobfile);
     cupsFileClose(fp);
     goto error;
   }
@@ -1660,18 +1605,16 @@ cupsdLoadJob(cupsd_job_t *job)          /* I - Job */
 
   if (!ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER))
   {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                   "[Job %d] Missing or bad time-at-creation attribute in "
-                   "control file.", job->id);
+    cupsdLogJob(job, CUPSD_LOG_ERROR,
+               "Missing or bad time-at-creation attribute in control file.");
     goto error;
   }
 
   if ((job->state = ippFindAttribute(job->attrs, "job-state",
                                      IPP_TAG_ENUM)) == NULL)
   {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                   "[Job %d] Missing or bad job-state attribute in control "
-                   "file.", job->id);
+    cupsdLogJob(job, CUPSD_LOG_ERROR,
+               "Missing or bad job-state attribute in control file.");
     goto error;
   }
 
@@ -1711,18 +1654,17 @@ cupsdLoadJob(cupsd_job_t *job)          /* I - Job */
     if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
                                  IPP_TAG_URI)) == NULL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "[Job %d] No job-printer-uri attribute in control file.",
-                     job->id);
+      cupsdLogJob(job, CUPSD_LOG_ERROR,
+                 "No job-printer-uri attribute in control file.");
       goto error;
     }
 
     if ((dest = cupsdValidateDest(attr->values[0].string.text, &(job->dtype),
                                   &destptr)) == NULL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "[Job %d] Unable to queue job for destination \"%s\".",
-                     job->id, attr->values[0].string.text);
+      cupsdLogJob(job, CUPSD_LOG_ERROR,
+                 "Unable to queue job for destination \"%s\".",
+                 attr->values[0].string.text);
       goto error;
     }
 
@@ -1730,9 +1672,9 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
   }
   else if ((destptr = cupsdFindDest(job->dest)) == NULL)
   {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                   "[Job %d] Unable to queue job for destination \"%s\".",
-                   job->id, job->dest);
+    cupsdLogJob(job, CUPSD_LOG_ERROR,
+               "Unable to queue job for destination \"%s\".",
+               job->dest);
     goto error;
   }
 
@@ -1741,9 +1683,8 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
   {
     const char *reason;                /* job-state-reason keyword */
 
-    cupsdLogMessage(CUPSD_LOG_DEBUG,
-                   "[Job %d] Adding missing job-state-reasons attribute to "
-                   " control file.", job->id);
+    cupsdLogJob(job, CUPSD_LOG_DEBUG,
+               "Adding missing job-state-reasons attribute to  control file.");
 
     switch (job->state_value)
     {
@@ -1808,9 +1749,8 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
     if ((attr = ippFindAttribute(job->attrs, "job-priority",
                                 IPP_TAG_INTEGER)) == NULL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "[Job %d] Missing or bad job-priority attribute in "
-                     "control file.", job->id);
+      cupsdLogJob(job, CUPSD_LOG_ERROR,
+                 "Missing or bad job-priority attribute in control file.");
       goto error;
     }
 
@@ -1822,9 +1762,9 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
     if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name",
                                 IPP_TAG_NAME)) == NULL)
     {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "[Job %d] Missing or bad job-originating-user-name "
-                     "attribute in control file.", job->id);
+      cupsdLogJob(job, CUPSD_LOG_ERROR,
+                 "Missing or bad job-originating-user-name "
+                 "attribute in control file.");
       goto error;
     }
 
@@ -1869,9 +1809,8 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
       if (access(jobfile, 0))
         break;
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG,
-                     "[Job %d] Auto-typing document file \"%s\"...", job->id,
-                     jobfile);
+      cupsdLogJob(job, CUPSD_LOG_DEBUG,
+                 "Auto-typing document file \"%s\"...", jobfile);
 
       if (fileid > job->num_files)
       {
@@ -1897,9 +1836,8 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
 
         if (!compressions || !filetypes)
        {
-          cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "[Job %d] Ran out of memory for job file types.",
-                         job->id);
+          cupsdLogJob(job, CUPSD_LOG_ERROR,
+                     "Ran out of memory for job file types.");
 
          ippDelete(job->attrs);
          job->attrs = NULL;
@@ -1956,7 +1894,7 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
 
 
       if (cupsFileGets(fp, line, sizeof(line)) &&
-          !strcmp(line, "CUPSD-AUTH-V2"))
+          !strcmp(line, "CUPSD-AUTH-V3"))
       {
         i = 0;
         while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
@@ -1965,8 +1903,11 @@ cupsdLoadJob(cupsd_job_t *job)           /* I - Job */
           * Decode value...
           */
 
-         bytes = sizeof(data);
-         httpDecode64_2(data, &bytes, value);
+          if (strcmp(line, "negotiate") && strcmp(line, "uid"))
+          {
+           bytes = sizeof(data);
+           httpDecode64_2(data, &bytes, value);
+         }
 
          /*
           * Assign environment variables...
@@ -1987,7 +1928,7 @@ cupsdLoadJob(cupsd_job_t *job)            /* I - Job */
          else if (!strcmp(line, "password"))
            cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s", data);
          else if (!strcmp(line, "negotiate"))
-           cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", data);
+           cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", value);
          else
            continue;
 
@@ -2204,8 +2145,7 @@ cupsdSaveJob(cupsd_job_t *job)            /* I - Job */
   if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
                  job->attrs) != IPP_DATA)
   {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "[Job %d] Unable to write job control file.", job->id);
+    cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to write job control file.");
     cupsFileClose(fp);
     return;
   }
@@ -2707,10 +2647,17 @@ cupsdStopAllJobs(
        job;
        job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
   {
-    if (kill_delay)
-      job->kill_time = time(NULL) + kill_delay;
+    if (job->completed)
+    {
+      cupsdSetJobState(job, IPP_JOB_COMPLETED, CUPSD_JOB_FORCE, NULL);
+    }
+    else
+    {
+      if (kill_delay)
+        job->kill_time = time(NULL) + kill_delay;
 
-    cupsdSetJobState(job, IPP_JOB_PENDING, action, NULL);
+      cupsdSetJobState(job, IPP_JOB_PENDING, action, NULL);
+    }
   }
 }
 
@@ -2986,11 +2933,13 @@ finalize_job(cupsd_job_t *job,          /* I - Job */
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "finalize_job(job=%p(%d))", job, job->id);
 
  /*
-  * Clear the "connecting-to-device" reason, which is only valid when a printer
-  * is processing, along with any remote printing job state...
+  * Clear the "connecting-to-device" and "cups-waiting-for-job-completed"
+  * reasons, which are only valid when a printer is processing, along with any
+  * remote printing job state...
   */
 
   cupsdSetPrinterReasons(job->printer, "-connecting-to-device,"
+                                       "cups-waiting-for-job-completed,"
                                       "cups-remote-pending,"
                                       "cups-remote-pending-held,"
                                       "cups-remote-processing,"
@@ -4070,8 +4019,7 @@ load_job_cache(const char *filename)      /* I - job.cache filename */
       job->status_pipes[0] = -1;
       job->status_pipes[1] = -1;
 
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Loading from cache...",
-                      job->id);
+      cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading from cache...");
     }
     else if (!job)
     {
@@ -4140,8 +4088,7 @@ load_job_cache(const char *filename)      /* I - job.cache filename */
                 job->id);
         if (access(jobfile, 0))
        {
-         cupsdLogMessage(CUPSD_LOG_INFO, "[Job %d] Data files have gone away.",
-                         job->id);
+         cupsdLogJob(job, CUPSD_LOG_INFO, "Data files have gone away.");
           job->num_files = 0;
          continue;
        }
@@ -4151,9 +4098,9 @@ load_job_cache(const char *filename)      /* I - job.cache filename */
 
         if (!job->filetypes || !job->compressions)
        {
-         cupsdLogMessage(CUPSD_LOG_EMERG,
-                         "[Job %d] Unable to allocate memory for %d files.",
-                         job->id, job->num_files);
+         cupsdLogJob(job, CUPSD_LOG_EMERG,
+                     "Unable to allocate memory for %d files.",
+                     job->num_files);
           break;
        }
       }
@@ -4191,9 +4138,9 @@ load_job_cache(const char *filename)      /* I - job.cache filename */
         * If the original MIME type is unknown, auto-type it!
        */
 
-        cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "[Job %d] Unknown MIME type %s/%s for file %d.",
-                       job->id, super, type, number + 1);
+        cupsdLogJob(job, CUPSD_LOG_ERROR,
+                   "Unknown MIME type %s/%s for file %d.",
+                   super, type, number + 1);
 
         snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot,
                 job->id, number + 1);
@@ -4474,6 +4421,10 @@ start_job(cupsd_job_t     *job,          /* I - Job ID */
           cupsd_printer_t *printer)    /* I - Printer to print job */
 {
   const char   *filename;              /* Support filename */
+  ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
+                                                  "job-cancel-after",
+                                                  IPP_TAG_INTEGER);
+                                       /* job-cancel-after attribute */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job(job=%p(%d), printer=%p(%s))",
@@ -4524,7 +4475,9 @@ start_job(cupsd_job_t     *job,           /* I - Job ID */
   job->printer      = printer;
   printer->job      = job;
 
-  if (MaxJobTime > 0)
+  if (cancel_after)
+    job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
+  else if (MaxJobTime > 0)
     job->cancel_time = time(NULL) + MaxJobTime;
   else
     job->cancel_time = 0;
@@ -4705,7 +4658,7 @@ unload_job(cupsd_job_t *job)              /* I - Job */
   if (!job->attrs)
     return;
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG, "[Job %d] Unloading...", job->id);
+  cupsdLogJob(job, CUPSD_LOG_DEBUG, "Unloading...");
 
   ippDelete(job->attrs);
 
@@ -4820,7 +4773,7 @@ update_job(cupsd_job_t *job)              /* I - Job to check */
       {
        event |= CUPSD_EVENT_PRINTER_STATE;
 
-        if (MaxJobTime > 0 && strstr(message, "connecting-to-device") != NULL)
+        if (MaxJobTime > 0)
         {
          /*
           * Reset cancel time after connecting to the device...
@@ -4831,7 +4784,17 @@ update_job(cupsd_job_t *job)             /* I - Job to check */
               break;
 
           if (i >= job->printer->num_reasons)
-           job->cancel_time = time(NULL) + MaxJobTime;
+          {
+           ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
+                                                            "job-cancel-after",
+                                                            IPP_TAG_INTEGER);
+                                       /* job-cancel-after attribute */
+
+            if (cancel_after)
+             job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
+           else
+             job->cancel_time = time(NULL) + MaxJobTime;
+         }
         }
       }
 
@@ -5197,5 +5160,5 @@ update_job_attrs(cupsd_job_t *job,        /* I - Job to update */
 
 
 /*
- * End of "$Id: job.c 7902 2008-09-03 14:20:17Z mike $".
+ * End of "$Id$".
  */