xref: /aosp_15_r20/external/libcups/scheduler/job.c (revision 5e7646d21f1134fb0638875d812ef646c12ab91e)
1*5e7646d2SAndroid Build Coastguard Worker /*
2*5e7646d2SAndroid Build Coastguard Worker  * Job management routines for the CUPS scheduler.
3*5e7646d2SAndroid Build Coastguard Worker  *
4*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 2007-2019 by Apple Inc.
5*5e7646d2SAndroid Build Coastguard Worker  * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6*5e7646d2SAndroid Build Coastguard Worker  *
7*5e7646d2SAndroid Build Coastguard Worker  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8*5e7646d2SAndroid Build Coastguard Worker  * information.
9*5e7646d2SAndroid Build Coastguard Worker  */
10*5e7646d2SAndroid Build Coastguard Worker 
11*5e7646d2SAndroid Build Coastguard Worker /*
12*5e7646d2SAndroid Build Coastguard Worker  * Include necessary headers...
13*5e7646d2SAndroid Build Coastguard Worker  */
14*5e7646d2SAndroid Build Coastguard Worker 
15*5e7646d2SAndroid Build Coastguard Worker #include "cupsd.h"
16*5e7646d2SAndroid Build Coastguard Worker #include <grp.h>
17*5e7646d2SAndroid Build Coastguard Worker #include <cups/backend.h>
18*5e7646d2SAndroid Build Coastguard Worker #include <cups/dir.h>
19*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
20*5e7646d2SAndroid Build Coastguard Worker #  include <IOKit/pwr_mgt/IOPMLib.h>
21*5e7646d2SAndroid Build Coastguard Worker #  ifdef HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H
22*5e7646d2SAndroid Build Coastguard Worker #    include <IOKit/pwr_mgt/IOPMLibPrivate.h>
23*5e7646d2SAndroid Build Coastguard Worker #  endif /* HAVE_IOKIT_PWR_MGT_IOPMLIBPRIVATE_H */
24*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
25*5e7646d2SAndroid Build Coastguard Worker 
26*5e7646d2SAndroid Build Coastguard Worker 
27*5e7646d2SAndroid Build Coastguard Worker /*
28*5e7646d2SAndroid Build Coastguard Worker  * Design Notes for Job Management
29*5e7646d2SAndroid Build Coastguard Worker  * -------------------------------
30*5e7646d2SAndroid Build Coastguard Worker  *
31*5e7646d2SAndroid Build Coastguard Worker  * STATE CHANGES
32*5e7646d2SAndroid Build Coastguard Worker  *
33*5e7646d2SAndroid Build Coastguard Worker  *     pending       Do nothing/check jobs
34*5e7646d2SAndroid Build Coastguard Worker  *     pending-held  Send SIGTERM to filters and backend
35*5e7646d2SAndroid Build Coastguard Worker  *     processing    Do nothing/start job
36*5e7646d2SAndroid Build Coastguard Worker  *     stopped       Send SIGKILL to filters and backend
37*5e7646d2SAndroid Build Coastguard Worker  *     canceled      Send SIGTERM to filters and backend
38*5e7646d2SAndroid Build Coastguard Worker  *     aborted       Finalize
39*5e7646d2SAndroid Build Coastguard Worker  *     completed     Finalize
40*5e7646d2SAndroid Build Coastguard Worker  *
41*5e7646d2SAndroid Build Coastguard Worker  *     Finalize clears the printer <-> job association, deletes the status
42*5e7646d2SAndroid Build Coastguard Worker  *     buffer, closes all of the pipes, etc. and doesn't get run until all of
43*5e7646d2SAndroid Build Coastguard Worker  *     the print processes are finished.
44*5e7646d2SAndroid Build Coastguard Worker  *
45*5e7646d2SAndroid Build Coastguard Worker  * UNLOADING OF JOBS (cupsdUnloadCompletedJobs)
46*5e7646d2SAndroid Build Coastguard Worker  *
47*5e7646d2SAndroid Build Coastguard Worker  *     We unload the job attributes when they are not needed to reduce overall
48*5e7646d2SAndroid Build Coastguard Worker  *     memory consumption.  We don't unload jobs where job->state_value <
49*5e7646d2SAndroid Build Coastguard Worker  *     IPP_JOB_STOPPED, job->printer != NULL, or job->access_time is recent.
50*5e7646d2SAndroid Build Coastguard Worker  *
51*5e7646d2SAndroid Build Coastguard Worker  * STARTING OF JOBS (start_job)
52*5e7646d2SAndroid Build Coastguard Worker  *
53*5e7646d2SAndroid Build Coastguard Worker  *     When a job is started, a status buffer, several pipes, a security
54*5e7646d2SAndroid Build Coastguard Worker  *     profile, and a backend process are created for the life of that job.
55*5e7646d2SAndroid Build Coastguard Worker  *     These are shared for every file in a job.  For remote print jobs, the
56*5e7646d2SAndroid Build Coastguard Worker  *     IPP backend is provided with every file in the job and no filters are
57*5e7646d2SAndroid Build Coastguard Worker  *     run.
58*5e7646d2SAndroid Build Coastguard Worker  *
59*5e7646d2SAndroid Build Coastguard Worker  *     The job->printer member tracks which printer is printing a job, which
60*5e7646d2SAndroid Build Coastguard Worker  *     can be different than the destination in job->dest for classes.  The
61*5e7646d2SAndroid Build Coastguard Worker  *     printer object also has a job pointer to track which job is being
62*5e7646d2SAndroid Build Coastguard Worker  *     printed.
63*5e7646d2SAndroid Build Coastguard Worker  *
64*5e7646d2SAndroid Build Coastguard Worker  * PRINTING OF JOB FILES (cupsdContinueJob)
65*5e7646d2SAndroid Build Coastguard Worker  *
66*5e7646d2SAndroid Build Coastguard Worker  *     Each file in a job is filtered by 0 or more programs.  After getting the
67*5e7646d2SAndroid Build Coastguard Worker  *     list of filters needed and the total cost, the job is either passed or
68*5e7646d2SAndroid Build Coastguard Worker  *     put back to the processing state until the current FilterLevel comes down
69*5e7646d2SAndroid Build Coastguard Worker  *     enough to allow printing.
70*5e7646d2SAndroid Build Coastguard Worker  *
71*5e7646d2SAndroid Build Coastguard Worker  *     If we can print, we build a string for the print options and run each of
72*5e7646d2SAndroid Build Coastguard Worker  *     the filters, piping the output from one into the next.
73*5e7646d2SAndroid Build Coastguard Worker  *
74*5e7646d2SAndroid Build Coastguard Worker  * JOB STATUS UPDATES (update_job)
75*5e7646d2SAndroid Build Coastguard Worker  *
76*5e7646d2SAndroid Build Coastguard Worker  *     The update_job function gets called whenever there are pending messages
77*5e7646d2SAndroid Build Coastguard Worker  *     on the status pipe.  These generally are updates to the marker-*,
78*5e7646d2SAndroid Build Coastguard Worker  *     printer-state-message, or printer-state-reasons attributes.  On EOF,
79*5e7646d2SAndroid Build Coastguard Worker  *     finalize_job is called to clean up.
80*5e7646d2SAndroid Build Coastguard Worker  *
81*5e7646d2SAndroid Build Coastguard Worker  * FINALIZING JOBS (finalize_job)
82*5e7646d2SAndroid Build Coastguard Worker  *
83*5e7646d2SAndroid Build Coastguard Worker  *     When all filters and the backend are done, we set the job state to
84*5e7646d2SAndroid Build Coastguard Worker  *     completed (no errors), aborted (filter errors or abort-job policy),
85*5e7646d2SAndroid Build Coastguard Worker  *     pending-held (auth required or retry-job policy), or pending
86*5e7646d2SAndroid Build Coastguard Worker  *     (retry-current-job or stop-printer policies) as appropriate.
87*5e7646d2SAndroid Build Coastguard Worker  *
88*5e7646d2SAndroid Build Coastguard Worker  *     Then we close the pipes and free the status buffers and profiles.
89*5e7646d2SAndroid Build Coastguard Worker  *
90*5e7646d2SAndroid Build Coastguard Worker  * JOB FILE COMPLETION (process_children in main.c)
91*5e7646d2SAndroid Build Coastguard Worker  *
92*5e7646d2SAndroid Build Coastguard Worker  *     For multiple-file jobs, process_children (in main.c) sees that all
93*5e7646d2SAndroid Build Coastguard Worker  *     filters have exited and calls in to print the next file if there are
94*5e7646d2SAndroid Build Coastguard Worker  *     more files in the job, otherwise it waits for the backend to exit and
95*5e7646d2SAndroid Build Coastguard Worker  *     update_job to do the cleanup.
96*5e7646d2SAndroid Build Coastguard Worker  */
97*5e7646d2SAndroid Build Coastguard Worker 
98*5e7646d2SAndroid Build Coastguard Worker 
99*5e7646d2SAndroid Build Coastguard Worker /*
100*5e7646d2SAndroid Build Coastguard Worker  * Local globals...
101*5e7646d2SAndroid Build Coastguard Worker  */
102*5e7646d2SAndroid Build Coastguard Worker 
103*5e7646d2SAndroid Build Coastguard Worker static mime_filter_t	gziptoany_filter =
104*5e7646d2SAndroid Build Coastguard Worker 			{
105*5e7646d2SAndroid Build Coastguard Worker 			  NULL,		/* Source type */
106*5e7646d2SAndroid Build Coastguard Worker 			  NULL,		/* Destination type */
107*5e7646d2SAndroid Build Coastguard Worker 			  0,		/* Cost */
108*5e7646d2SAndroid Build Coastguard Worker 			  "gziptoany"	/* Filter program to run */
109*5e7646d2SAndroid Build Coastguard Worker 			};
110*5e7646d2SAndroid Build Coastguard Worker 
111*5e7646d2SAndroid Build Coastguard Worker 
112*5e7646d2SAndroid Build Coastguard Worker /*
113*5e7646d2SAndroid Build Coastguard Worker  * Local functions...
114*5e7646d2SAndroid Build Coastguard Worker  */
115*5e7646d2SAndroid Build Coastguard Worker 
116*5e7646d2SAndroid Build Coastguard Worker static int	compare_active_jobs(void *first, void *second, void *data);
117*5e7646d2SAndroid Build Coastguard Worker static int	compare_completed_jobs(void *first, void *second, void *data);
118*5e7646d2SAndroid Build Coastguard Worker static int	compare_jobs(void *first, void *second, void *data);
119*5e7646d2SAndroid Build Coastguard Worker static void	dump_job_history(cupsd_job_t *job);
120*5e7646d2SAndroid Build Coastguard Worker static void	finalize_job(cupsd_job_t *job, int set_job_state);
121*5e7646d2SAndroid Build Coastguard Worker static void	free_job_history(cupsd_job_t *job);
122*5e7646d2SAndroid Build Coastguard Worker static char	*get_options(cupsd_job_t *job, int banner_page, char *copies,
123*5e7646d2SAndroid Build Coastguard Worker 		             size_t copies_size, char *title,
124*5e7646d2SAndroid Build Coastguard Worker 			     size_t title_size);
125*5e7646d2SAndroid Build Coastguard Worker static size_t	ipp_length(ipp_t *ipp);
126*5e7646d2SAndroid Build Coastguard Worker static void	load_job_cache(const char *filename);
127*5e7646d2SAndroid Build Coastguard Worker static void	load_next_job_id(const char *filename);
128*5e7646d2SAndroid Build Coastguard Worker static void	load_request_root(void);
129*5e7646d2SAndroid Build Coastguard Worker static void	remove_job_files(cupsd_job_t *job);
130*5e7646d2SAndroid Build Coastguard Worker static void	remove_job_history(cupsd_job_t *job);
131*5e7646d2SAndroid Build Coastguard Worker static void	set_time(cupsd_job_t *job, const char *name);
132*5e7646d2SAndroid Build Coastguard Worker static void	start_job(cupsd_job_t *job, cupsd_printer_t *printer);
133*5e7646d2SAndroid Build Coastguard Worker static void	stop_job(cupsd_job_t *job, cupsd_jobaction_t action);
134*5e7646d2SAndroid Build Coastguard Worker static void	unload_job(cupsd_job_t *job);
135*5e7646d2SAndroid Build Coastguard Worker static void	update_job(cupsd_job_t *job);
136*5e7646d2SAndroid Build Coastguard Worker static void	update_job_attrs(cupsd_job_t *job, int do_message);
137*5e7646d2SAndroid Build Coastguard Worker 
138*5e7646d2SAndroid Build Coastguard Worker 
139*5e7646d2SAndroid Build Coastguard Worker /*
140*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdAddJob()' - Add a new job to the job queue.
141*5e7646d2SAndroid Build Coastguard Worker  */
142*5e7646d2SAndroid Build Coastguard Worker 
143*5e7646d2SAndroid Build Coastguard Worker cupsd_job_t *				/* O - New job record */
cupsdAddJob(int priority,const char * dest)144*5e7646d2SAndroid Build Coastguard Worker cupsdAddJob(int        priority,	/* I - Job priority */
145*5e7646d2SAndroid Build Coastguard Worker             const char *dest)		/* I - Job destination */
146*5e7646d2SAndroid Build Coastguard Worker {
147*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* New job record */
148*5e7646d2SAndroid Build Coastguard Worker 
149*5e7646d2SAndroid Build Coastguard Worker 
150*5e7646d2SAndroid Build Coastguard Worker   if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL)
151*5e7646d2SAndroid Build Coastguard Worker     return (NULL);
152*5e7646d2SAndroid Build Coastguard Worker 
153*5e7646d2SAndroid Build Coastguard Worker   job->id              = NextJobId ++;
154*5e7646d2SAndroid Build Coastguard Worker   job->priority        = priority;
155*5e7646d2SAndroid Build Coastguard Worker   job->back_pipes[0]   = -1;
156*5e7646d2SAndroid Build Coastguard Worker   job->back_pipes[1]   = -1;
157*5e7646d2SAndroid Build Coastguard Worker   job->print_pipes[0]  = -1;
158*5e7646d2SAndroid Build Coastguard Worker   job->print_pipes[1]  = -1;
159*5e7646d2SAndroid Build Coastguard Worker   job->side_pipes[0]   = -1;
160*5e7646d2SAndroid Build Coastguard Worker   job->side_pipes[1]   = -1;
161*5e7646d2SAndroid Build Coastguard Worker   job->status_pipes[0] = -1;
162*5e7646d2SAndroid Build Coastguard Worker   job->status_pipes[1] = -1;
163*5e7646d2SAndroid Build Coastguard Worker 
164*5e7646d2SAndroid Build Coastguard Worker   cupsdSetString(&job->dest, dest);
165*5e7646d2SAndroid Build Coastguard Worker 
166*5e7646d2SAndroid Build Coastguard Worker  /*
167*5e7646d2SAndroid Build Coastguard Worker   * Add the new job to the "all jobs" and "active jobs" lists...
168*5e7646d2SAndroid Build Coastguard Worker   */
169*5e7646d2SAndroid Build Coastguard Worker 
170*5e7646d2SAndroid Build Coastguard Worker   cupsArrayAdd(Jobs, job);
171*5e7646d2SAndroid Build Coastguard Worker   cupsArrayAdd(ActiveJobs, job);
172*5e7646d2SAndroid Build Coastguard Worker 
173*5e7646d2SAndroid Build Coastguard Worker   return (job);
174*5e7646d2SAndroid Build Coastguard Worker }
175*5e7646d2SAndroid Build Coastguard Worker 
176*5e7646d2SAndroid Build Coastguard Worker 
177*5e7646d2SAndroid Build Coastguard Worker /*
178*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdCancelJobs()' - Cancel all jobs for the given destination/user.
179*5e7646d2SAndroid Build Coastguard Worker  */
180*5e7646d2SAndroid Build Coastguard Worker 
181*5e7646d2SAndroid Build Coastguard Worker void
cupsdCancelJobs(const char * dest,const char * username,int purge)182*5e7646d2SAndroid Build Coastguard Worker cupsdCancelJobs(const char *dest,	/* I - Destination to cancel */
183*5e7646d2SAndroid Build Coastguard Worker                 const char *username,	/* I - Username or NULL */
184*5e7646d2SAndroid Build Coastguard Worker 	        int        purge)	/* I - Purge jobs? */
185*5e7646d2SAndroid Build Coastguard Worker {
186*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
187*5e7646d2SAndroid Build Coastguard Worker 
188*5e7646d2SAndroid Build Coastguard Worker 
189*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
190*5e7646d2SAndroid Build Coastguard Worker        job;
191*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(Jobs))
192*5e7646d2SAndroid Build Coastguard Worker   {
193*5e7646d2SAndroid Build Coastguard Worker     if ((!job->dest || !job->username) && !cupsdLoadJob(job))
194*5e7646d2SAndroid Build Coastguard Worker       continue;
195*5e7646d2SAndroid Build Coastguard Worker 
196*5e7646d2SAndroid Build Coastguard Worker     if ((!dest || !strcmp(job->dest, dest)) &&
197*5e7646d2SAndroid Build Coastguard Worker         (!username || !strcmp(job->username, username)))
198*5e7646d2SAndroid Build Coastguard Worker     {
199*5e7646d2SAndroid Build Coastguard Worker      /*
200*5e7646d2SAndroid Build Coastguard Worker       * Cancel all jobs matching this destination/user...
201*5e7646d2SAndroid Build Coastguard Worker       */
202*5e7646d2SAndroid Build Coastguard Worker 
203*5e7646d2SAndroid Build Coastguard Worker       if (purge)
204*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_PURGE,
205*5e7646d2SAndroid Build Coastguard Worker 	                 "Job purged by user.");
206*5e7646d2SAndroid Build Coastguard Worker       else if (job->state_value < IPP_JOB_CANCELED)
207*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT,
208*5e7646d2SAndroid Build Coastguard Worker 			 "Job canceled by user.");
209*5e7646d2SAndroid Build Coastguard Worker     }
210*5e7646d2SAndroid Build Coastguard Worker   }
211*5e7646d2SAndroid Build Coastguard Worker }
212*5e7646d2SAndroid Build Coastguard Worker 
213*5e7646d2SAndroid Build Coastguard Worker 
214*5e7646d2SAndroid Build Coastguard Worker /*
215*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdCheckJobs()' - Check the pending jobs and start any if the destination
216*5e7646d2SAndroid Build Coastguard Worker  *                      is available.
217*5e7646d2SAndroid Build Coastguard Worker  */
218*5e7646d2SAndroid Build Coastguard Worker 
219*5e7646d2SAndroid Build Coastguard Worker void
cupsdCheckJobs(void)220*5e7646d2SAndroid Build Coastguard Worker cupsdCheckJobs(void)
221*5e7646d2SAndroid Build Coastguard Worker {
222*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Current job in queue */
223*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer,	/* Printer destination */
224*5e7646d2SAndroid Build Coastguard Worker 			*pclass;	/* Printer class destination */
225*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Job attribute */
226*5e7646d2SAndroid Build Coastguard Worker   time_t		curtime;	/* Current time */
227*5e7646d2SAndroid Build Coastguard Worker   const char		*reasons;	/* job-state-reasons value */
228*5e7646d2SAndroid Build Coastguard Worker 
229*5e7646d2SAndroid Build Coastguard Worker 
230*5e7646d2SAndroid Build Coastguard Worker   curtime = time(NULL);
231*5e7646d2SAndroid Build Coastguard Worker 
232*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckJobs: %d active jobs, sleeping=%d, ac-power=%d, reload=%d, curtime=%ld", cupsArrayCount(ActiveJobs), Sleeping, ACPower, NeedReload, (long)curtime);
233*5e7646d2SAndroid Build Coastguard Worker 
234*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
235*5e7646d2SAndroid Build Coastguard Worker        job;
236*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
237*5e7646d2SAndroid Build Coastguard Worker   {
238*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2,
239*5e7646d2SAndroid Build Coastguard Worker                     "cupsdCheckJobs: Job %d - dest=\"%s\", printer=%p, "
240*5e7646d2SAndroid Build Coastguard Worker                     "state=%d, cancel_time=%ld, hold_until=%ld, kill_time=%ld, "
241*5e7646d2SAndroid Build Coastguard Worker                     "pending_cost=%d, pending_timeout=%ld", job->id, job->dest,
242*5e7646d2SAndroid Build Coastguard Worker                     job->printer, job->state_value, (long)job->cancel_time,
243*5e7646d2SAndroid Build Coastguard Worker                     (long)job->hold_until, (long)job->kill_time,
244*5e7646d2SAndroid Build Coastguard Worker                     job->pending_cost, (long)job->pending_timeout);
245*5e7646d2SAndroid Build Coastguard Worker 
246*5e7646d2SAndroid Build Coastguard Worker    /*
247*5e7646d2SAndroid Build Coastguard Worker     * Kill jobs if they are unresponsive...
248*5e7646d2SAndroid Build Coastguard Worker     */
249*5e7646d2SAndroid Build Coastguard Worker 
250*5e7646d2SAndroid Build Coastguard Worker     if (job->kill_time && job->kill_time <= curtime)
251*5e7646d2SAndroid Build Coastguard Worker     {
252*5e7646d2SAndroid Build Coastguard Worker       if (!job->completed)
253*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_ERROR, "Stopping unresponsive job.");
254*5e7646d2SAndroid Build Coastguard Worker 
255*5e7646d2SAndroid Build Coastguard Worker       stop_job(job, CUPSD_JOB_FORCE);
256*5e7646d2SAndroid Build Coastguard Worker       continue;
257*5e7646d2SAndroid Build Coastguard Worker     }
258*5e7646d2SAndroid Build Coastguard Worker 
259*5e7646d2SAndroid Build Coastguard Worker    /*
260*5e7646d2SAndroid Build Coastguard Worker     * Cancel stuck jobs...
261*5e7646d2SAndroid Build Coastguard Worker     */
262*5e7646d2SAndroid Build Coastguard Worker 
263*5e7646d2SAndroid Build Coastguard Worker     if (job->cancel_time && job->cancel_time <= curtime)
264*5e7646d2SAndroid Build Coastguard Worker     {
265*5e7646d2SAndroid Build Coastguard Worker       int cancel_after;			/* job-cancel-after value */
266*5e7646d2SAndroid Build Coastguard Worker 
267*5e7646d2SAndroid Build Coastguard Worker       attr         = ippFindAttribute(job->attrs, "job-cancel-after", IPP_TAG_INTEGER);
268*5e7646d2SAndroid Build Coastguard Worker       cancel_after = attr ? ippGetInteger(attr, 0) : MaxJobTime;
269*5e7646d2SAndroid Build Coastguard Worker 
270*5e7646d2SAndroid Build Coastguard Worker       if (job->completed)
271*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_FORCE, "Marking stuck job as completed after %d seconds.", cancel_after);
272*5e7646d2SAndroid Build Coastguard Worker       else
273*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_CANCELED, CUPSD_JOB_DEFAULT, "Canceling stuck job after %d seconds.", cancel_after);
274*5e7646d2SAndroid Build Coastguard Worker       continue;
275*5e7646d2SAndroid Build Coastguard Worker     }
276*5e7646d2SAndroid Build Coastguard Worker 
277*5e7646d2SAndroid Build Coastguard Worker    /*
278*5e7646d2SAndroid Build Coastguard Worker     * Start held jobs if they are ready...
279*5e7646d2SAndroid Build Coastguard Worker     */
280*5e7646d2SAndroid Build Coastguard Worker 
281*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value == IPP_JOB_HELD &&
282*5e7646d2SAndroid Build Coastguard Worker         job->hold_until &&
283*5e7646d2SAndroid Build Coastguard Worker 	job->hold_until < curtime)
284*5e7646d2SAndroid Build Coastguard Worker     {
285*5e7646d2SAndroid Build Coastguard Worker       if (job->pending_timeout)
286*5e7646d2SAndroid Build Coastguard Worker       {
287*5e7646d2SAndroid Build Coastguard Worker        /*
288*5e7646d2SAndroid Build Coastguard Worker         * This job is pending; check that we don't have an active Send-Document
289*5e7646d2SAndroid Build Coastguard Worker 	* operation in progress on any of the client connections, then timeout
290*5e7646d2SAndroid Build Coastguard Worker 	* the job so we can start printing...
291*5e7646d2SAndroid Build Coastguard Worker 	*/
292*5e7646d2SAndroid Build Coastguard Worker 
293*5e7646d2SAndroid Build Coastguard Worker         cupsd_client_t	*con;		/* Current client connection */
294*5e7646d2SAndroid Build Coastguard Worker 
295*5e7646d2SAndroid Build Coastguard Worker 	for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
296*5e7646d2SAndroid Build Coastguard Worker 	     con;
297*5e7646d2SAndroid Build Coastguard Worker 	     con = (cupsd_client_t *)cupsArrayNext(Clients))
298*5e7646d2SAndroid Build Coastguard Worker 	  if (con->request &&
299*5e7646d2SAndroid Build Coastguard Worker 	      con->request->request.op.operation_id == IPP_SEND_DOCUMENT)
300*5e7646d2SAndroid Build Coastguard Worker 	    break;
301*5e7646d2SAndroid Build Coastguard Worker 
302*5e7646d2SAndroid Build Coastguard Worker         if (con)
303*5e7646d2SAndroid Build Coastguard Worker 	  continue;
304*5e7646d2SAndroid Build Coastguard Worker 
305*5e7646d2SAndroid Build Coastguard Worker         if (cupsdTimeoutJob(job))
306*5e7646d2SAndroid Build Coastguard Worker 	  continue;
307*5e7646d2SAndroid Build Coastguard Worker 
308*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT, "Job submission timed out.");
309*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogJob(job, CUPSD_LOG_ERROR, "Job submission timed out.");
310*5e7646d2SAndroid Build Coastguard Worker       }
311*5e7646d2SAndroid Build Coastguard Worker       else
312*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT, "Job hold expired.");
313*5e7646d2SAndroid Build Coastguard Worker     }
314*5e7646d2SAndroid Build Coastguard Worker 
315*5e7646d2SAndroid Build Coastguard Worker    /*
316*5e7646d2SAndroid Build Coastguard Worker     * Continue jobs that are waiting on the FilterLimit...
317*5e7646d2SAndroid Build Coastguard Worker     */
318*5e7646d2SAndroid Build Coastguard Worker 
319*5e7646d2SAndroid Build Coastguard Worker     if (job->pending_cost > 0 &&
320*5e7646d2SAndroid Build Coastguard Worker 	((FilterLevel + job->pending_cost) < FilterLimit || FilterLevel == 0))
321*5e7646d2SAndroid Build Coastguard Worker       cupsdContinueJob(job);
322*5e7646d2SAndroid Build Coastguard Worker 
323*5e7646d2SAndroid Build Coastguard Worker    /*
324*5e7646d2SAndroid Build Coastguard Worker     * Skip jobs that where held-on-create
325*5e7646d2SAndroid Build Coastguard Worker     */
326*5e7646d2SAndroid Build Coastguard Worker 
327*5e7646d2SAndroid Build Coastguard Worker     reasons = ippGetString(job->reasons, 0, NULL);
328*5e7646d2SAndroid Build Coastguard Worker     if (reasons && !strcmp(reasons, "job-held-on-create"))
329*5e7646d2SAndroid Build Coastguard Worker     {
330*5e7646d2SAndroid Build Coastguard Worker      /*
331*5e7646d2SAndroid Build Coastguard Worker       * Check whether the printer is still holding new jobs...
332*5e7646d2SAndroid Build Coastguard Worker       */
333*5e7646d2SAndroid Build Coastguard Worker 
334*5e7646d2SAndroid Build Coastguard Worker       printer = cupsdFindDest(job->dest);
335*5e7646d2SAndroid Build Coastguard Worker 
336*5e7646d2SAndroid Build Coastguard Worker       if (printer->holding_new_jobs)
337*5e7646d2SAndroid Build Coastguard Worker         continue;
338*5e7646d2SAndroid Build Coastguard Worker 
339*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &job->reasons, 0, "none");
340*5e7646d2SAndroid Build Coastguard Worker     }
341*5e7646d2SAndroid Build Coastguard Worker 
342*5e7646d2SAndroid Build Coastguard Worker    /*
343*5e7646d2SAndroid Build Coastguard Worker     * Start pending jobs if the destination is available...
344*5e7646d2SAndroid Build Coastguard Worker     */
345*5e7646d2SAndroid Build Coastguard Worker 
346*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value == IPP_JOB_PENDING && !NeedReload &&
347*5e7646d2SAndroid Build Coastguard Worker         (!Sleeping || ACPower) && !DoingShutdown && !job->printer)
348*5e7646d2SAndroid Build Coastguard Worker     {
349*5e7646d2SAndroid Build Coastguard Worker       printer = cupsdFindDest(job->dest);
350*5e7646d2SAndroid Build Coastguard Worker       pclass  = NULL;
351*5e7646d2SAndroid Build Coastguard Worker 
352*5e7646d2SAndroid Build Coastguard Worker       while (printer && (printer->type & CUPS_PRINTER_CLASS))
353*5e7646d2SAndroid Build Coastguard Worker       {
354*5e7646d2SAndroid Build Coastguard Worker        /*
355*5e7646d2SAndroid Build Coastguard Worker         * If the class is remote, just pass it to the remote server...
356*5e7646d2SAndroid Build Coastguard Worker 	*/
357*5e7646d2SAndroid Build Coastguard Worker 
358*5e7646d2SAndroid Build Coastguard Worker         pclass = printer;
359*5e7646d2SAndroid Build Coastguard Worker 
360*5e7646d2SAndroid Build Coastguard Worker         if (pclass->state == IPP_PRINTER_STOPPED)
361*5e7646d2SAndroid Build Coastguard Worker 	  printer = NULL;
362*5e7646d2SAndroid Build Coastguard Worker         else if (pclass->type & CUPS_PRINTER_REMOTE)
363*5e7646d2SAndroid Build Coastguard Worker 	  break;
364*5e7646d2SAndroid Build Coastguard Worker 	else
365*5e7646d2SAndroid Build Coastguard Worker 	  printer = cupsdFindAvailablePrinter(printer->name);
366*5e7646d2SAndroid Build Coastguard Worker       }
367*5e7646d2SAndroid Build Coastguard Worker 
368*5e7646d2SAndroid Build Coastguard Worker       if (!printer && !pclass)
369*5e7646d2SAndroid Build Coastguard Worker       {
370*5e7646d2SAndroid Build Coastguard Worker        /*
371*5e7646d2SAndroid Build Coastguard Worker         * Whoa, the printer and/or class for this destination went away;
372*5e7646d2SAndroid Build Coastguard Worker 	* cancel the job...
373*5e7646d2SAndroid Build Coastguard Worker 	*/
374*5e7646d2SAndroid Build Coastguard Worker 
375*5e7646d2SAndroid Build Coastguard Worker         cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_PURGE,
376*5e7646d2SAndroid Build Coastguard Worker 	                 "Job aborted because the destination printer/class "
377*5e7646d2SAndroid Build Coastguard Worker 			 "has gone away.");
378*5e7646d2SAndroid Build Coastguard Worker       }
379*5e7646d2SAndroid Build Coastguard Worker       else if (printer)
380*5e7646d2SAndroid Build Coastguard Worker       {
381*5e7646d2SAndroid Build Coastguard Worker        /*
382*5e7646d2SAndroid Build Coastguard Worker         * See if the printer is available or remote and not printing a job;
383*5e7646d2SAndroid Build Coastguard Worker 	* if so, start the job...
384*5e7646d2SAndroid Build Coastguard Worker 	*/
385*5e7646d2SAndroid Build Coastguard Worker 
386*5e7646d2SAndroid Build Coastguard Worker         if (pclass)
387*5e7646d2SAndroid Build Coastguard Worker 	{
388*5e7646d2SAndroid Build Coastguard Worker 	 /*
389*5e7646d2SAndroid Build Coastguard Worker 	  * Add/update a job-printer-uri-actual attribute for this job
390*5e7646d2SAndroid Build Coastguard Worker 	  * so that we know which printer actually printed the job...
391*5e7646d2SAndroid Build Coastguard Worker 	  */
392*5e7646d2SAndroid Build Coastguard Worker 
393*5e7646d2SAndroid Build Coastguard Worker           if ((attr = ippFindAttribute(job->attrs, "job-printer-uri-actual", IPP_TAG_URI)) != NULL)
394*5e7646d2SAndroid Build Coastguard Worker             ippSetString(job->attrs, &attr, 0, printer->uri);
395*5e7646d2SAndroid Build Coastguard Worker 	  else
396*5e7646d2SAndroid Build Coastguard Worker 	    ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, "job-printer-uri-actual", NULL, printer->uri);
397*5e7646d2SAndroid Build Coastguard Worker 
398*5e7646d2SAndroid Build Coastguard Worker           job->dirty = 1;
399*5e7646d2SAndroid Build Coastguard Worker           cupsdMarkDirty(CUPSD_DIRTY_JOBS);
400*5e7646d2SAndroid Build Coastguard Worker 	}
401*5e7646d2SAndroid Build Coastguard Worker 
402*5e7646d2SAndroid Build Coastguard Worker         if (!printer->job && printer->state == IPP_PRINTER_IDLE)
403*5e7646d2SAndroid Build Coastguard Worker         {
404*5e7646d2SAndroid Build Coastguard Worker 	 /*
405*5e7646d2SAndroid Build Coastguard Worker 	  * Start the job...
406*5e7646d2SAndroid Build Coastguard Worker 	  */
407*5e7646d2SAndroid Build Coastguard Worker 
408*5e7646d2SAndroid Build Coastguard Worker 	  cupsArraySave(ActiveJobs);
409*5e7646d2SAndroid Build Coastguard Worker 	  start_job(job, printer);
410*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayRestore(ActiveJobs);
411*5e7646d2SAndroid Build Coastguard Worker 	}
412*5e7646d2SAndroid Build Coastguard Worker       }
413*5e7646d2SAndroid Build Coastguard Worker     }
414*5e7646d2SAndroid Build Coastguard Worker   }
415*5e7646d2SAndroid Build Coastguard Worker }
416*5e7646d2SAndroid Build Coastguard Worker 
417*5e7646d2SAndroid Build Coastguard Worker 
418*5e7646d2SAndroid Build Coastguard Worker /*
419*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdCleanJobs()' - Clean out old jobs.
420*5e7646d2SAndroid Build Coastguard Worker  */
421*5e7646d2SAndroid Build Coastguard Worker 
422*5e7646d2SAndroid Build Coastguard Worker void
cupsdCleanJobs(void)423*5e7646d2SAndroid Build Coastguard Worker cupsdCleanJobs(void)
424*5e7646d2SAndroid Build Coastguard Worker {
425*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
426*5e7646d2SAndroid Build Coastguard Worker   time_t	curtime;		/* Current time */
427*5e7646d2SAndroid Build Coastguard Worker 
428*5e7646d2SAndroid Build Coastguard Worker 
429*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
430*5e7646d2SAndroid Build Coastguard Worker                   "cupsdCleanJobs: MaxJobs=%d, JobHistory=%d, JobFiles=%d",
431*5e7646d2SAndroid Build Coastguard Worker                   MaxJobs, JobHistory, JobFiles);
432*5e7646d2SAndroid Build Coastguard Worker 
433*5e7646d2SAndroid Build Coastguard Worker   if (MaxJobs <= 0 && JobHistory == INT_MAX && JobFiles == INT_MAX)
434*5e7646d2SAndroid Build Coastguard Worker     return;
435*5e7646d2SAndroid Build Coastguard Worker 
436*5e7646d2SAndroid Build Coastguard Worker   curtime          = time(NULL);
437*5e7646d2SAndroid Build Coastguard Worker   JobHistoryUpdate = 0;
438*5e7646d2SAndroid Build Coastguard Worker 
439*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: curtime=%d", (int)curtime);
440*5e7646d2SAndroid Build Coastguard Worker 
441*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
442*5e7646d2SAndroid Build Coastguard Worker        job;
443*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(Jobs))
444*5e7646d2SAndroid Build Coastguard Worker   {
445*5e7646d2SAndroid Build Coastguard Worker     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);
446*5e7646d2SAndroid Build Coastguard Worker 
447*5e7646d2SAndroid Build Coastguard Worker     if ((job->history_time && job->history_time < JobHistoryUpdate) || !JobHistoryUpdate)
448*5e7646d2SAndroid Build Coastguard Worker       JobHistoryUpdate = job->history_time;
449*5e7646d2SAndroid Build Coastguard Worker 
450*5e7646d2SAndroid Build Coastguard Worker     if ((job->file_time && job->file_time < JobHistoryUpdate) || !JobHistoryUpdate)
451*5e7646d2SAndroid Build Coastguard Worker       JobHistoryUpdate = job->file_time;
452*5e7646d2SAndroid Build Coastguard Worker 
453*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value >= IPP_JOB_CANCELED && !job->printer)
454*5e7646d2SAndroid Build Coastguard Worker     {
455*5e7646d2SAndroid Build Coastguard Worker      /*
456*5e7646d2SAndroid Build Coastguard Worker       * Expire old jobs (or job files)...
457*5e7646d2SAndroid Build Coastguard Worker       */
458*5e7646d2SAndroid Build Coastguard Worker 
459*5e7646d2SAndroid Build Coastguard Worker       if ((MaxJobs > 0 && cupsArrayCount(Jobs) >= MaxJobs) ||
460*5e7646d2SAndroid Build Coastguard Worker           (job->history_time && job->history_time <= curtime))
461*5e7646d2SAndroid Build Coastguard Worker       {
462*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing from history.");
463*5e7646d2SAndroid Build Coastguard Worker 	cupsdDeleteJob(job, CUPSD_JOB_PURGE);
464*5e7646d2SAndroid Build Coastguard Worker       }
465*5e7646d2SAndroid Build Coastguard Worker       else if (job->file_time && job->file_time <= curtime && job->num_files > 0)
466*5e7646d2SAndroid Build Coastguard Worker       {
467*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG, "Removing document files.");
468*5e7646d2SAndroid Build Coastguard Worker         remove_job_files(job);
469*5e7646d2SAndroid Build Coastguard Worker 
470*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_JOBS);
471*5e7646d2SAndroid Build Coastguard Worker       }
472*5e7646d2SAndroid Build Coastguard Worker     }
473*5e7646d2SAndroid Build Coastguard Worker   }
474*5e7646d2SAndroid Build Coastguard Worker 
475*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCleanJobs: JobHistoryUpdate=%ld",
476*5e7646d2SAndroid Build Coastguard Worker                   (long)JobHistoryUpdate);
477*5e7646d2SAndroid Build Coastguard Worker }
478*5e7646d2SAndroid Build Coastguard Worker 
479*5e7646d2SAndroid Build Coastguard Worker 
480*5e7646d2SAndroid Build Coastguard Worker /*
481*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdContinueJob()' - Continue printing with the next file in a job.
482*5e7646d2SAndroid Build Coastguard Worker  */
483*5e7646d2SAndroid Build Coastguard Worker 
484*5e7646d2SAndroid Build Coastguard Worker void
cupsdContinueJob(cupsd_job_t * job)485*5e7646d2SAndroid Build Coastguard Worker cupsdContinueJob(cupsd_job_t *job)	/* I - Job */
486*5e7646d2SAndroid Build Coastguard Worker {
487*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
488*5e7646d2SAndroid Build Coastguard Worker   int			slot;		/* Pipe slot */
489*5e7646d2SAndroid Build Coastguard Worker   cups_array_t		*filters = NULL,/* Filters for job */
490*5e7646d2SAndroid Build Coastguard Worker 			*prefilters;	/* Filters with prefilters */
491*5e7646d2SAndroid Build Coastguard Worker   mime_filter_t		*filter,	/* Current filter */
492*5e7646d2SAndroid Build Coastguard Worker 			*prefilter,	/* Prefilter */
493*5e7646d2SAndroid Build Coastguard Worker 			port_monitor;	/* Port monitor filter */
494*5e7646d2SAndroid Build Coastguard Worker   char			scheme[255];	/* Device URI scheme */
495*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
496*5e7646d2SAndroid Build Coastguard Worker   const char		*ptr,		/* Pointer into value */
497*5e7646d2SAndroid Build Coastguard Worker 			*abort_message;	/* Abort message */
498*5e7646d2SAndroid Build Coastguard Worker   ipp_jstate_t		abort_state = IPP_JOB_STOPPED;
499*5e7646d2SAndroid Build Coastguard Worker 					/* New job state on abort */
500*5e7646d2SAndroid Build Coastguard Worker   struct stat		backinfo;	/* Backend file information */
501*5e7646d2SAndroid Build Coastguard Worker   int			backroot;	/* Run backend as root? */
502*5e7646d2SAndroid Build Coastguard Worker   int			pid;		/* Process ID of new filter process */
503*5e7646d2SAndroid Build Coastguard Worker   int			banner_page;	/* 1 if banner page, 0 otherwise */
504*5e7646d2SAndroid Build Coastguard Worker   int			filterfds[2][2] = { { -1, -1 }, { -1, -1 } };
505*5e7646d2SAndroid Build Coastguard Worker 					/* Pipes used between filters */
506*5e7646d2SAndroid Build Coastguard Worker   int			envc;		/* Number of environment variables */
507*5e7646d2SAndroid Build Coastguard Worker   struct stat		fileinfo;	/* Job file information */
508*5e7646d2SAndroid Build Coastguard Worker   int			argc = 0;	/* Number of arguments */
509*5e7646d2SAndroid Build Coastguard Worker   char			**argv = NULL,	/* Filter command-line arguments */
510*5e7646d2SAndroid Build Coastguard Worker 			filename[1024],	/* Job filename */
511*5e7646d2SAndroid Build Coastguard Worker 			command[1024],	/* Full path to command */
512*5e7646d2SAndroid Build Coastguard Worker 			jobid[255],	/* Job ID string */
513*5e7646d2SAndroid Build Coastguard Worker 			title[IPP_MAX_NAME],
514*5e7646d2SAndroid Build Coastguard Worker 					/* Job title string */
515*5e7646d2SAndroid Build Coastguard Worker 			copies[255],	/* # copies string */
516*5e7646d2SAndroid Build Coastguard Worker 			*options,	/* Options string */
517*5e7646d2SAndroid Build Coastguard Worker 			*envp[MAX_ENV + 21],
518*5e7646d2SAndroid Build Coastguard Worker 					/* Environment variables */
519*5e7646d2SAndroid Build Coastguard Worker 			charset[255],	/* CHARSET env variable */
520*5e7646d2SAndroid Build Coastguard Worker 			class_name[255],/* CLASS env variable */
521*5e7646d2SAndroid Build Coastguard Worker 			classification[1024],
522*5e7646d2SAndroid Build Coastguard Worker 					/* CLASSIFICATION env variable */
523*5e7646d2SAndroid Build Coastguard Worker 			content_type[1024],
524*5e7646d2SAndroid Build Coastguard Worker 					/* CONTENT_TYPE env variable */
525*5e7646d2SAndroid Build Coastguard Worker 			device_uri[1024],
526*5e7646d2SAndroid Build Coastguard Worker 					/* DEVICE_URI env variable */
527*5e7646d2SAndroid Build Coastguard Worker 			final_content_type[1024] = "",
528*5e7646d2SAndroid Build Coastguard Worker 					/* FINAL_CONTENT_TYPE env variable */
529*5e7646d2SAndroid Build Coastguard Worker 			lang[255],	/* LANG env variable */
530*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
531*5e7646d2SAndroid Build Coastguard Worker 			apple_language[255],
532*5e7646d2SAndroid Build Coastguard Worker 					/* APPLE_LANGUAGE env variable */
533*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
534*5e7646d2SAndroid Build Coastguard Worker 			auth_info_required[255],
535*5e7646d2SAndroid Build Coastguard Worker 					/* AUTH_INFO_REQUIRED env variable */
536*5e7646d2SAndroid Build Coastguard Worker 			ppd[1024],	/* PPD env variable */
537*5e7646d2SAndroid Build Coastguard Worker 			printer_info[255],
538*5e7646d2SAndroid Build Coastguard Worker 					/* PRINTER_INFO env variable */
539*5e7646d2SAndroid Build Coastguard Worker 			printer_location[255],
540*5e7646d2SAndroid Build Coastguard Worker 					/* PRINTER_LOCATION env variable */
541*5e7646d2SAndroid Build Coastguard Worker 			printer_name[255],
542*5e7646d2SAndroid Build Coastguard Worker 					/* PRINTER env variable */
543*5e7646d2SAndroid Build Coastguard Worker 			*printer_state_reasons = NULL,
544*5e7646d2SAndroid Build Coastguard Worker 					/* PRINTER_STATE_REASONS env var */
545*5e7646d2SAndroid Build Coastguard Worker 			rip_max_cache[255];
546*5e7646d2SAndroid Build Coastguard Worker 					/* RIP_MAX_CACHE env variable */
547*5e7646d2SAndroid Build Coastguard Worker 
548*5e7646d2SAndroid Build Coastguard Worker 
549*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
550*5e7646d2SAndroid Build Coastguard Worker                   "cupsdContinueJob(job=%p(%d)): current_file=%d, num_files=%d",
551*5e7646d2SAndroid Build Coastguard Worker 	          job, job->id, job->current_file, job->num_files);
552*5e7646d2SAndroid Build Coastguard Worker 
553*5e7646d2SAndroid Build Coastguard Worker  /*
554*5e7646d2SAndroid Build Coastguard Worker   * Figure out what filters are required to convert from
555*5e7646d2SAndroid Build Coastguard Worker   * the source to the destination type...
556*5e7646d2SAndroid Build Coastguard Worker   */
557*5e7646d2SAndroid Build Coastguard Worker 
558*5e7646d2SAndroid Build Coastguard Worker   FilterLevel -= job->cost;
559*5e7646d2SAndroid Build Coastguard Worker 
560*5e7646d2SAndroid Build Coastguard Worker   job->cost         = 0;
561*5e7646d2SAndroid Build Coastguard Worker   job->pending_cost = 0;
562*5e7646d2SAndroid Build Coastguard Worker 
563*5e7646d2SAndroid Build Coastguard Worker   memset(job->filters, 0, sizeof(job->filters));
564*5e7646d2SAndroid Build Coastguard Worker 
565*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->raw)
566*5e7646d2SAndroid Build Coastguard Worker   {
567*5e7646d2SAndroid Build Coastguard Worker    /*
568*5e7646d2SAndroid Build Coastguard Worker     * Remote jobs and raw queues go directly to the printer without
569*5e7646d2SAndroid Build Coastguard Worker     * filtering...
570*5e7646d2SAndroid Build Coastguard Worker     */
571*5e7646d2SAndroid Build Coastguard Worker 
572*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG, "Sending job to queue tagged as raw...");
573*5e7646d2SAndroid Build Coastguard Worker   }
574*5e7646d2SAndroid Build Coastguard Worker   else
575*5e7646d2SAndroid Build Coastguard Worker   {
576*5e7646d2SAndroid Build Coastguard Worker    /*
577*5e7646d2SAndroid Build Coastguard Worker     * Local jobs get filtered...
578*5e7646d2SAndroid Build Coastguard Worker     */
579*5e7646d2SAndroid Build Coastguard Worker 
580*5e7646d2SAndroid Build Coastguard Worker     mime_type_t	*dst = job->printer->filetype;
581*5e7646d2SAndroid Build Coastguard Worker 					/* Destination file type */
582*5e7646d2SAndroid Build Coastguard Worker 
583*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
584*5e7646d2SAndroid Build Coastguard Worker              job->id, job->current_file + 1);
585*5e7646d2SAndroid Build Coastguard Worker     if (stat(filename, &fileinfo))
586*5e7646d2SAndroid Build Coastguard Worker       fileinfo.st_size = 0;
587*5e7646d2SAndroid Build Coastguard Worker 
588*5e7646d2SAndroid Build Coastguard Worker     if (job->retry_as_raster)
589*5e7646d2SAndroid Build Coastguard Worker     {
590*5e7646d2SAndroid Build Coastguard Worker      /*
591*5e7646d2SAndroid Build Coastguard Worker       * Need to figure out whether the printer supports image/pwg-raster or
592*5e7646d2SAndroid Build Coastguard Worker       * image/urf, and use the corresponding type...
593*5e7646d2SAndroid Build Coastguard Worker       */
594*5e7646d2SAndroid Build Coastguard Worker 
595*5e7646d2SAndroid Build Coastguard Worker       char	type[MIME_MAX_TYPE];	/* MIME media type for printer */
596*5e7646d2SAndroid Build Coastguard Worker 
597*5e7646d2SAndroid Build Coastguard Worker       snprintf(type, sizeof(type), "%s/image/urf", job->printer->name);
598*5e7646d2SAndroid Build Coastguard Worker       if ((dst = mimeType(MimeDatabase, "printer", type)) == NULL)
599*5e7646d2SAndroid Build Coastguard Worker       {
600*5e7646d2SAndroid Build Coastguard Worker 	snprintf(type, sizeof(type), "%s/image/pwg-raster", job->printer->name);
601*5e7646d2SAndroid Build Coastguard Worker 	dst = mimeType(MimeDatabase, "printer", type);
602*5e7646d2SAndroid Build Coastguard Worker       }
603*5e7646d2SAndroid Build Coastguard Worker 
604*5e7646d2SAndroid Build Coastguard Worker       if (dst)
605*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG, "Retrying job as \"%s\".", strchr(dst->type, '/') + 1);
606*5e7646d2SAndroid Build Coastguard Worker       else
607*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to retry job using a supported raster format.");
608*5e7646d2SAndroid Build Coastguard Worker     }
609*5e7646d2SAndroid Build Coastguard Worker 
610*5e7646d2SAndroid Build Coastguard Worker     filters = mimeFilter2(MimeDatabase, job->filetypes[job->current_file], (size_t)fileinfo.st_size, dst, &(job->cost));
611*5e7646d2SAndroid Build Coastguard Worker 
612*5e7646d2SAndroid Build Coastguard Worker     if (!filters)
613*5e7646d2SAndroid Build Coastguard Worker     {
614*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_ERROR,
615*5e7646d2SAndroid Build Coastguard Worker 		  "Unable to convert file %d to printable format.",
616*5e7646d2SAndroid Build Coastguard Worker 		  job->current_file);
617*5e7646d2SAndroid Build Coastguard Worker 
618*5e7646d2SAndroid Build Coastguard Worker       abort_message = "Aborting job because it cannot be printed.";
619*5e7646d2SAndroid Build Coastguard Worker       abort_state   = IPP_JOB_ABORTED;
620*5e7646d2SAndroid Build Coastguard Worker 
621*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &job->reasons, 0, "document-unprintable-error");
622*5e7646d2SAndroid Build Coastguard Worker       goto abort_job;
623*5e7646d2SAndroid Build Coastguard Worker     }
624*5e7646d2SAndroid Build Coastguard Worker 
625*5e7646d2SAndroid Build Coastguard Worker    /*
626*5e7646d2SAndroid Build Coastguard Worker     * Figure out the final content type...
627*5e7646d2SAndroid Build Coastguard Worker     */
628*5e7646d2SAndroid Build Coastguard Worker 
629*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG, "%d filters for job:",
630*5e7646d2SAndroid Build Coastguard Worker                 cupsArrayCount(filters));
631*5e7646d2SAndroid Build Coastguard Worker     for (filter = (mime_filter_t *)cupsArrayFirst(filters);
632*5e7646d2SAndroid Build Coastguard Worker          filter;
633*5e7646d2SAndroid Build Coastguard Worker          filter = (mime_filter_t *)cupsArrayNext(filters))
634*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "%s (%s/%s to %s/%s, cost %d)",
635*5e7646d2SAndroid Build Coastguard Worker 		  filter->filter,
636*5e7646d2SAndroid Build Coastguard Worker 		  filter->src ? filter->src->super : "???",
637*5e7646d2SAndroid Build Coastguard Worker 		  filter->src ? filter->src->type : "???",
638*5e7646d2SAndroid Build Coastguard Worker 		  filter->dst ? filter->dst->super : "???",
639*5e7646d2SAndroid Build Coastguard Worker 		  filter->dst ? filter->dst->type : "???",
640*5e7646d2SAndroid Build Coastguard Worker 		  filter->cost);
641*5e7646d2SAndroid Build Coastguard Worker 
642*5e7646d2SAndroid Build Coastguard Worker     if (!job->printer->remote)
643*5e7646d2SAndroid Build Coastguard Worker     {
644*5e7646d2SAndroid Build Coastguard Worker       for (filter = (mime_filter_t *)cupsArrayLast(filters);
645*5e7646d2SAndroid Build Coastguard Worker            filter && filter->dst;
646*5e7646d2SAndroid Build Coastguard Worker            filter = (mime_filter_t *)cupsArrayPrev(filters))
647*5e7646d2SAndroid Build Coastguard Worker         if (strcmp(filter->dst->super, "printer") ||
648*5e7646d2SAndroid Build Coastguard Worker             strcmp(filter->dst->type, job->printer->name))
649*5e7646d2SAndroid Build Coastguard Worker           break;
650*5e7646d2SAndroid Build Coastguard Worker 
651*5e7646d2SAndroid Build Coastguard Worker       if (filter && filter->dst)
652*5e7646d2SAndroid Build Coastguard Worker       {
653*5e7646d2SAndroid Build Coastguard Worker 	if ((ptr = strchr(filter->dst->type, '/')) != NULL)
654*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(final_content_type, sizeof(final_content_type),
655*5e7646d2SAndroid Build Coastguard Worker 		   "FINAL_CONTENT_TYPE=%s", ptr + 1);
656*5e7646d2SAndroid Build Coastguard Worker 	else
657*5e7646d2SAndroid Build Coastguard Worker 	  snprintf(final_content_type, sizeof(final_content_type),
658*5e7646d2SAndroid Build Coastguard Worker 		   "FINAL_CONTENT_TYPE=%s/%s", filter->dst->super,
659*5e7646d2SAndroid Build Coastguard Worker 		   filter->dst->type);
660*5e7646d2SAndroid Build Coastguard Worker       }
661*5e7646d2SAndroid Build Coastguard Worker       else
662*5e7646d2SAndroid Build Coastguard Worker         snprintf(final_content_type, sizeof(final_content_type),
663*5e7646d2SAndroid Build Coastguard Worker                  "FINAL_CONTENT_TYPE=printer/%s", job->printer->name);
664*5e7646d2SAndroid Build Coastguard Worker     }
665*5e7646d2SAndroid Build Coastguard Worker 
666*5e7646d2SAndroid Build Coastguard Worker    /*
667*5e7646d2SAndroid Build Coastguard Worker     * Remove NULL ("-") filters...
668*5e7646d2SAndroid Build Coastguard Worker     */
669*5e7646d2SAndroid Build Coastguard Worker 
670*5e7646d2SAndroid Build Coastguard Worker     for (filter = (mime_filter_t *)cupsArrayFirst(filters);
671*5e7646d2SAndroid Build Coastguard Worker          filter;
672*5e7646d2SAndroid Build Coastguard Worker 	 filter = (mime_filter_t *)cupsArrayNext(filters))
673*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(filter->filter, "-"))
674*5e7646d2SAndroid Build Coastguard Worker         cupsArrayRemove(filters, filter);
675*5e7646d2SAndroid Build Coastguard Worker 
676*5e7646d2SAndroid Build Coastguard Worker     if (cupsArrayCount(filters) == 0)
677*5e7646d2SAndroid Build Coastguard Worker     {
678*5e7646d2SAndroid Build Coastguard Worker       cupsArrayDelete(filters);
679*5e7646d2SAndroid Build Coastguard Worker       filters = NULL;
680*5e7646d2SAndroid Build Coastguard Worker     }
681*5e7646d2SAndroid Build Coastguard Worker 
682*5e7646d2SAndroid Build Coastguard Worker    /*
683*5e7646d2SAndroid Build Coastguard Worker     * If this printer has any pre-filters, insert the required pre-filter
684*5e7646d2SAndroid Build Coastguard Worker     * in the filters array...
685*5e7646d2SAndroid Build Coastguard Worker     */
686*5e7646d2SAndroid Build Coastguard Worker 
687*5e7646d2SAndroid Build Coastguard Worker     if (job->printer->prefiltertype && filters)
688*5e7646d2SAndroid Build Coastguard Worker     {
689*5e7646d2SAndroid Build Coastguard Worker       prefilters = cupsArrayNew(NULL, NULL);
690*5e7646d2SAndroid Build Coastguard Worker 
691*5e7646d2SAndroid Build Coastguard Worker       for (filter = (mime_filter_t *)cupsArrayFirst(filters);
692*5e7646d2SAndroid Build Coastguard Worker 	   filter;
693*5e7646d2SAndroid Build Coastguard Worker 	   filter = (mime_filter_t *)cupsArrayNext(filters))
694*5e7646d2SAndroid Build Coastguard Worker       {
695*5e7646d2SAndroid Build Coastguard Worker 	if ((prefilter = mimeFilterLookup(MimeDatabase, filter->src,
696*5e7646d2SAndroid Build Coastguard Worker 					  job->printer->prefiltertype)))
697*5e7646d2SAndroid Build Coastguard Worker 	{
698*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayAdd(prefilters, prefilter);
699*5e7646d2SAndroid Build Coastguard Worker 	  job->cost += prefilter->cost;
700*5e7646d2SAndroid Build Coastguard Worker 	}
701*5e7646d2SAndroid Build Coastguard Worker 
702*5e7646d2SAndroid Build Coastguard Worker 	cupsArrayAdd(prefilters, filter);
703*5e7646d2SAndroid Build Coastguard Worker       }
704*5e7646d2SAndroid Build Coastguard Worker 
705*5e7646d2SAndroid Build Coastguard Worker       cupsArrayDelete(filters);
706*5e7646d2SAndroid Build Coastguard Worker       filters = prefilters;
707*5e7646d2SAndroid Build Coastguard Worker     }
708*5e7646d2SAndroid Build Coastguard Worker   }
709*5e7646d2SAndroid Build Coastguard Worker 
710*5e7646d2SAndroid Build Coastguard Worker  /*
711*5e7646d2SAndroid Build Coastguard Worker   * Set a minimum cost of 100 for all jobs so that FilterLimit
712*5e7646d2SAndroid Build Coastguard Worker   * works with raw queues and other low-cost paths.
713*5e7646d2SAndroid Build Coastguard Worker   */
714*5e7646d2SAndroid Build Coastguard Worker 
715*5e7646d2SAndroid Build Coastguard Worker   if (job->cost < 100)
716*5e7646d2SAndroid Build Coastguard Worker     job->cost = 100;
717*5e7646d2SAndroid Build Coastguard Worker 
718*5e7646d2SAndroid Build Coastguard Worker  /*
719*5e7646d2SAndroid Build Coastguard Worker   * See if the filter cost is too high...
720*5e7646d2SAndroid Build Coastguard Worker   */
721*5e7646d2SAndroid Build Coastguard Worker 
722*5e7646d2SAndroid Build Coastguard Worker   if ((FilterLevel + job->cost) > FilterLimit && FilterLevel > 0 &&
723*5e7646d2SAndroid Build Coastguard Worker       FilterLimit > 0)
724*5e7646d2SAndroid Build Coastguard Worker   {
725*5e7646d2SAndroid Build Coastguard Worker    /*
726*5e7646d2SAndroid Build Coastguard Worker     * Don't print this job quite yet...
727*5e7646d2SAndroid Build Coastguard Worker     */
728*5e7646d2SAndroid Build Coastguard Worker 
729*5e7646d2SAndroid Build Coastguard Worker     cupsArrayDelete(filters);
730*5e7646d2SAndroid Build Coastguard Worker 
731*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_INFO,
732*5e7646d2SAndroid Build Coastguard Worker 		"Holding because filter limit has been reached.");
733*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG2,
734*5e7646d2SAndroid Build Coastguard Worker 		"cupsdContinueJob: file=%d, cost=%d, level=%d, limit=%d",
735*5e7646d2SAndroid Build Coastguard Worker 		job->current_file, job->cost, FilterLevel,
736*5e7646d2SAndroid Build Coastguard Worker 		FilterLimit);
737*5e7646d2SAndroid Build Coastguard Worker 
738*5e7646d2SAndroid Build Coastguard Worker     job->pending_cost = job->cost;
739*5e7646d2SAndroid Build Coastguard Worker     job->cost         = 0;
740*5e7646d2SAndroid Build Coastguard Worker     return;
741*5e7646d2SAndroid Build Coastguard Worker   }
742*5e7646d2SAndroid Build Coastguard Worker 
743*5e7646d2SAndroid Build Coastguard Worker   FilterLevel += job->cost;
744*5e7646d2SAndroid Build Coastguard Worker 
745*5e7646d2SAndroid Build Coastguard Worker  /*
746*5e7646d2SAndroid Build Coastguard Worker   * Add decompression/raw filter as needed...
747*5e7646d2SAndroid Build Coastguard Worker   */
748*5e7646d2SAndroid Build Coastguard Worker 
749*5e7646d2SAndroid Build Coastguard Worker   if ((job->compressions[job->current_file] && (!job->printer->remote || job->num_files == 1)) ||
750*5e7646d2SAndroid Build Coastguard Worker       (!job->printer->remote && job->printer->raw && job->num_files > 1))
751*5e7646d2SAndroid Build Coastguard Worker   {
752*5e7646d2SAndroid Build Coastguard Worker    /*
753*5e7646d2SAndroid Build Coastguard Worker     * Add gziptoany filter to the front of the list...
754*5e7646d2SAndroid Build Coastguard Worker     */
755*5e7646d2SAndroid Build Coastguard Worker 
756*5e7646d2SAndroid Build Coastguard Worker     if (!filters)
757*5e7646d2SAndroid Build Coastguard Worker       filters = cupsArrayNew(NULL, NULL);
758*5e7646d2SAndroid Build Coastguard Worker 
759*5e7646d2SAndroid Build Coastguard Worker     if (!cupsArrayInsert(filters, &gziptoany_filter))
760*5e7646d2SAndroid Build Coastguard Worker     {
761*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG,
762*5e7646d2SAndroid Build Coastguard Worker 		  "Unable to add decompression filter - %s", strerror(errno));
763*5e7646d2SAndroid Build Coastguard Worker 
764*5e7646d2SAndroid Build Coastguard Worker       cupsArrayDelete(filters);
765*5e7646d2SAndroid Build Coastguard Worker 
766*5e7646d2SAndroid Build Coastguard Worker       abort_message = "Stopping job because the scheduler ran out of memory.";
767*5e7646d2SAndroid Build Coastguard Worker 
768*5e7646d2SAndroid Build Coastguard Worker       goto abort_job;
769*5e7646d2SAndroid Build Coastguard Worker     }
770*5e7646d2SAndroid Build Coastguard Worker   }
771*5e7646d2SAndroid Build Coastguard Worker 
772*5e7646d2SAndroid Build Coastguard Worker  /*
773*5e7646d2SAndroid Build Coastguard Worker   * Add port monitor, if any...
774*5e7646d2SAndroid Build Coastguard Worker   */
775*5e7646d2SAndroid Build Coastguard Worker 
776*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->port_monitor)
777*5e7646d2SAndroid Build Coastguard Worker   {
778*5e7646d2SAndroid Build Coastguard Worker    /*
779*5e7646d2SAndroid Build Coastguard Worker     * Add port monitor to the end of the list...
780*5e7646d2SAndroid Build Coastguard Worker     */
781*5e7646d2SAndroid Build Coastguard Worker 
782*5e7646d2SAndroid Build Coastguard Worker     if (!filters)
783*5e7646d2SAndroid Build Coastguard Worker       filters = cupsArrayNew(NULL, NULL);
784*5e7646d2SAndroid Build Coastguard Worker 
785*5e7646d2SAndroid Build Coastguard Worker     port_monitor.src  = NULL;
786*5e7646d2SAndroid Build Coastguard Worker     port_monitor.dst  = NULL;
787*5e7646d2SAndroid Build Coastguard Worker     port_monitor.cost = 0;
788*5e7646d2SAndroid Build Coastguard Worker 
789*5e7646d2SAndroid Build Coastguard Worker     snprintf(port_monitor.filter, sizeof(port_monitor.filter),
790*5e7646d2SAndroid Build Coastguard Worker              "%s/monitor/%s", ServerBin, job->printer->port_monitor);
791*5e7646d2SAndroid Build Coastguard Worker 
792*5e7646d2SAndroid Build Coastguard Worker     if (!cupsArrayAdd(filters, &port_monitor))
793*5e7646d2SAndroid Build Coastguard Worker     {
794*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG,
795*5e7646d2SAndroid Build Coastguard Worker 		  "Unable to add port monitor - %s", strerror(errno));
796*5e7646d2SAndroid Build Coastguard Worker 
797*5e7646d2SAndroid Build Coastguard Worker       abort_message = "Stopping job because the scheduler ran out of memory.";
798*5e7646d2SAndroid Build Coastguard Worker 
799*5e7646d2SAndroid Build Coastguard Worker       goto abort_job;
800*5e7646d2SAndroid Build Coastguard Worker     }
801*5e7646d2SAndroid Build Coastguard Worker   }
802*5e7646d2SAndroid Build Coastguard Worker 
803*5e7646d2SAndroid Build Coastguard Worker  /*
804*5e7646d2SAndroid Build Coastguard Worker   * Make sure we don't go over the "MAX_FILTERS" limit...
805*5e7646d2SAndroid Build Coastguard Worker   */
806*5e7646d2SAndroid Build Coastguard Worker 
807*5e7646d2SAndroid Build Coastguard Worker   if (cupsArrayCount(filters) > MAX_FILTERS)
808*5e7646d2SAndroid Build Coastguard Worker   {
809*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG,
810*5e7646d2SAndroid Build Coastguard Worker 		"Too many filters (%d > %d), unable to print.",
811*5e7646d2SAndroid Build Coastguard Worker 		cupsArrayCount(filters), MAX_FILTERS);
812*5e7646d2SAndroid Build Coastguard Worker 
813*5e7646d2SAndroid Build Coastguard Worker     abort_message = "Aborting job because it needs too many filters to print.";
814*5e7646d2SAndroid Build Coastguard Worker     abort_state   = IPP_JOB_ABORTED;
815*5e7646d2SAndroid Build Coastguard Worker 
816*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "document-unprintable-error");
817*5e7646d2SAndroid Build Coastguard Worker 
818*5e7646d2SAndroid Build Coastguard Worker     goto abort_job;
819*5e7646d2SAndroid Build Coastguard Worker   }
820*5e7646d2SAndroid Build Coastguard Worker 
821*5e7646d2SAndroid Build Coastguard Worker  /*
822*5e7646d2SAndroid Build Coastguard Worker   * Determine if we are printing a banner page or not...
823*5e7646d2SAndroid Build Coastguard Worker   */
824*5e7646d2SAndroid Build Coastguard Worker 
825*5e7646d2SAndroid Build Coastguard Worker   if (job->job_sheets == NULL)
826*5e7646d2SAndroid Build Coastguard Worker   {
827*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG, "No job-sheets attribute.");
828*5e7646d2SAndroid Build Coastguard Worker     if ((job->job_sheets =
829*5e7646d2SAndroid Build Coastguard Worker          ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
830*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG,
831*5e7646d2SAndroid Build Coastguard Worker 		  "... but someone added one without setting job_sheets.");
832*5e7646d2SAndroid Build Coastguard Worker   }
833*5e7646d2SAndroid Build Coastguard Worker   else if (job->job_sheets->num_values == 1)
834*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-sheets=%s",
835*5e7646d2SAndroid Build Coastguard Worker 		job->job_sheets->values[0].string.text);
836*5e7646d2SAndroid Build Coastguard Worker   else
837*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-sheets=%s,%s",
838*5e7646d2SAndroid Build Coastguard Worker                 job->job_sheets->values[0].string.text,
839*5e7646d2SAndroid Build Coastguard Worker                 job->job_sheets->values[1].string.text);
840*5e7646d2SAndroid Build Coastguard Worker 
841*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->type & CUPS_PRINTER_REMOTE)
842*5e7646d2SAndroid Build Coastguard Worker     banner_page = 0;
843*5e7646d2SAndroid Build Coastguard Worker   else if (job->job_sheets == NULL)
844*5e7646d2SAndroid Build Coastguard Worker     banner_page = 0;
845*5e7646d2SAndroid Build Coastguard Worker   else if (_cups_strcasecmp(job->job_sheets->values[0].string.text, "none") != 0 &&
846*5e7646d2SAndroid Build Coastguard Worker 	   job->current_file == 0)
847*5e7646d2SAndroid Build Coastguard Worker     banner_page = 1;
848*5e7646d2SAndroid Build Coastguard Worker   else if (job->job_sheets->num_values > 1 &&
849*5e7646d2SAndroid Build Coastguard Worker 	   _cups_strcasecmp(job->job_sheets->values[1].string.text, "none") != 0 &&
850*5e7646d2SAndroid Build Coastguard Worker 	   job->current_file == (job->num_files - 1))
851*5e7646d2SAndroid Build Coastguard Worker     banner_page = 1;
852*5e7646d2SAndroid Build Coastguard Worker   else
853*5e7646d2SAndroid Build Coastguard Worker     banner_page = 0;
854*5e7646d2SAndroid Build Coastguard Worker 
855*5e7646d2SAndroid Build Coastguard Worker   if ((options = get_options(job, banner_page, copies, sizeof(copies), title,
856*5e7646d2SAndroid Build Coastguard Worker                              sizeof(title))) == NULL)
857*5e7646d2SAndroid Build Coastguard Worker   {
858*5e7646d2SAndroid Build Coastguard Worker     abort_message = "Stopping job because the scheduler ran out of memory.";
859*5e7646d2SAndroid Build Coastguard Worker 
860*5e7646d2SAndroid Build Coastguard Worker     goto abort_job;
861*5e7646d2SAndroid Build Coastguard Worker   }
862*5e7646d2SAndroid Build Coastguard Worker 
863*5e7646d2SAndroid Build Coastguard Worker  /*
864*5e7646d2SAndroid Build Coastguard Worker   * Build the command-line arguments for the filters.  Each filter
865*5e7646d2SAndroid Build Coastguard Worker   * has 6 or 7 arguments:
866*5e7646d2SAndroid Build Coastguard Worker   *
867*5e7646d2SAndroid Build Coastguard Worker   *     argv[0] = printer
868*5e7646d2SAndroid Build Coastguard Worker   *     argv[1] = job ID
869*5e7646d2SAndroid Build Coastguard Worker   *     argv[2] = username
870*5e7646d2SAndroid Build Coastguard Worker   *     argv[3] = title
871*5e7646d2SAndroid Build Coastguard Worker   *     argv[4] = # copies
872*5e7646d2SAndroid Build Coastguard Worker   *     argv[5] = options
873*5e7646d2SAndroid Build Coastguard Worker   *     argv[6] = filename (optional; normally stdin)
874*5e7646d2SAndroid Build Coastguard Worker   *
875*5e7646d2SAndroid Build Coastguard Worker   * This allows legacy printer drivers that use the old System V
876*5e7646d2SAndroid Build Coastguard Worker   * printing interface to be used by CUPS.
877*5e7646d2SAndroid Build Coastguard Worker   *
878*5e7646d2SAndroid Build Coastguard Worker   * For remote jobs, we send all of the files in the argument list.
879*5e7646d2SAndroid Build Coastguard Worker   */
880*5e7646d2SAndroid Build Coastguard Worker 
881*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->remote)
882*5e7646d2SAndroid Build Coastguard Worker     argc = 6 + job->num_files;
883*5e7646d2SAndroid Build Coastguard Worker   else
884*5e7646d2SAndroid Build Coastguard Worker     argc = 7;
885*5e7646d2SAndroid Build Coastguard Worker 
886*5e7646d2SAndroid Build Coastguard Worker   if ((argv = calloc((size_t)argc + 1, sizeof(char *))) == NULL)
887*5e7646d2SAndroid Build Coastguard Worker   {
888*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG, "Unable to allocate argument array - %s",
889*5e7646d2SAndroid Build Coastguard Worker                     strerror(errno));
890*5e7646d2SAndroid Build Coastguard Worker 
891*5e7646d2SAndroid Build Coastguard Worker     abort_message = "Stopping job because the scheduler ran out of memory.";
892*5e7646d2SAndroid Build Coastguard Worker 
893*5e7646d2SAndroid Build Coastguard Worker     goto abort_job;
894*5e7646d2SAndroid Build Coastguard Worker   }
895*5e7646d2SAndroid Build Coastguard Worker 
896*5e7646d2SAndroid Build Coastguard Worker   snprintf(jobid, sizeof(jobid), "%d", job->id);
897*5e7646d2SAndroid Build Coastguard Worker 
898*5e7646d2SAndroid Build Coastguard Worker   argv[0] = job->printer->name;
899*5e7646d2SAndroid Build Coastguard Worker   argv[1] = jobid;
900*5e7646d2SAndroid Build Coastguard Worker   argv[2] = job->username;
901*5e7646d2SAndroid Build Coastguard Worker   argv[3] = title;
902*5e7646d2SAndroid Build Coastguard Worker   argv[4] = copies;
903*5e7646d2SAndroid Build Coastguard Worker   argv[5] = options;
904*5e7646d2SAndroid Build Coastguard Worker 
905*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->remote && job->num_files > 1)
906*5e7646d2SAndroid Build Coastguard Worker   {
907*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < job->num_files; i ++)
908*5e7646d2SAndroid Build Coastguard Worker     {
909*5e7646d2SAndroid Build Coastguard Worker       snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
910*5e7646d2SAndroid Build Coastguard Worker                job->id, i + 1);
911*5e7646d2SAndroid Build Coastguard Worker       argv[6 + i] = strdup(filename);
912*5e7646d2SAndroid Build Coastguard Worker     }
913*5e7646d2SAndroid Build Coastguard Worker   }
914*5e7646d2SAndroid Build Coastguard Worker   else
915*5e7646d2SAndroid Build Coastguard Worker   {
916*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
917*5e7646d2SAndroid Build Coastguard Worker              job->id, job->current_file + 1);
918*5e7646d2SAndroid Build Coastguard Worker     argv[6] = strdup(filename);
919*5e7646d2SAndroid Build Coastguard Worker   }
920*5e7646d2SAndroid Build Coastguard Worker 
921*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; argv[i]; i ++)
922*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG, "argv[%d]=\"%s\"", i, argv[i]);
923*5e7646d2SAndroid Build Coastguard Worker 
924*5e7646d2SAndroid Build Coastguard Worker  /*
925*5e7646d2SAndroid Build Coastguard Worker   * Create environment variable strings for the filters...
926*5e7646d2SAndroid Build Coastguard Worker   */
927*5e7646d2SAndroid Build Coastguard Worker 
928*5e7646d2SAndroid Build Coastguard Worker   attr = ippFindAttribute(job->attrs, "attributes-natural-language",
929*5e7646d2SAndroid Build Coastguard Worker                           IPP_TAG_LANGUAGE);
930*5e7646d2SAndroid Build Coastguard Worker 
931*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
932*5e7646d2SAndroid Build Coastguard Worker   strlcpy(apple_language, "APPLE_LANGUAGE=", sizeof(apple_language));
933*5e7646d2SAndroid Build Coastguard Worker   _cupsAppleLanguage(attr->values[0].string.text,
934*5e7646d2SAndroid Build Coastguard Worker 		     apple_language + 15, sizeof(apple_language) - 15);
935*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
936*5e7646d2SAndroid Build Coastguard Worker 
937*5e7646d2SAndroid Build Coastguard Worker   switch (strlen(attr->values[0].string.text))
938*5e7646d2SAndroid Build Coastguard Worker   {
939*5e7646d2SAndroid Build Coastguard Worker     default :
940*5e7646d2SAndroid Build Coastguard Worker        /*
941*5e7646d2SAndroid Build Coastguard Worker         * This is an unknown or badly formatted language code; use
942*5e7646d2SAndroid Build Coastguard Worker 	* the POSIX locale...
943*5e7646d2SAndroid Build Coastguard Worker 	*/
944*5e7646d2SAndroid Build Coastguard Worker 
945*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(lang, "LANG=C", sizeof(lang));
946*5e7646d2SAndroid Build Coastguard Worker 	break;
947*5e7646d2SAndroid Build Coastguard Worker 
948*5e7646d2SAndroid Build Coastguard Worker     case 2 :
949*5e7646d2SAndroid Build Coastguard Worker        /*
950*5e7646d2SAndroid Build Coastguard Worker         * Just the language code (ll)...
951*5e7646d2SAndroid Build Coastguard Worker 	*/
952*5e7646d2SAndroid Build Coastguard Worker 
953*5e7646d2SAndroid Build Coastguard Worker         snprintf(lang, sizeof(lang), "LANG=%s.UTF-8",
954*5e7646d2SAndroid Build Coastguard Worker 	         attr->values[0].string.text);
955*5e7646d2SAndroid Build Coastguard Worker         break;
956*5e7646d2SAndroid Build Coastguard Worker 
957*5e7646d2SAndroid Build Coastguard Worker     case 5 :
958*5e7646d2SAndroid Build Coastguard Worker        /*
959*5e7646d2SAndroid Build Coastguard Worker         * Language and country code (ll-cc)...
960*5e7646d2SAndroid Build Coastguard Worker 	*/
961*5e7646d2SAndroid Build Coastguard Worker 
962*5e7646d2SAndroid Build Coastguard Worker         snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c.UTF-8",
963*5e7646d2SAndroid Build Coastguard Worker 	         attr->values[0].string.text[0],
964*5e7646d2SAndroid Build Coastguard Worker 		 attr->values[0].string.text[1],
965*5e7646d2SAndroid Build Coastguard Worker 		 toupper(attr->values[0].string.text[3] & 255),
966*5e7646d2SAndroid Build Coastguard Worker 		 toupper(attr->values[0].string.text[4] & 255));
967*5e7646d2SAndroid Build Coastguard Worker         break;
968*5e7646d2SAndroid Build Coastguard Worker   }
969*5e7646d2SAndroid Build Coastguard Worker 
970*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "document-format",
971*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_MIMETYPE)) != NULL &&
972*5e7646d2SAndroid Build Coastguard Worker       (ptr = strstr(attr->values[0].string.text, "charset=")) != NULL)
973*5e7646d2SAndroid Build Coastguard Worker     snprintf(charset, sizeof(charset), "CHARSET=%s", ptr + 8);
974*5e7646d2SAndroid Build Coastguard Worker   else
975*5e7646d2SAndroid Build Coastguard Worker     strlcpy(charset, "CHARSET=utf-8", sizeof(charset));
976*5e7646d2SAndroid Build Coastguard Worker 
977*5e7646d2SAndroid Build Coastguard Worker   snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
978*5e7646d2SAndroid Build Coastguard Worker            job->filetypes[job->current_file]->super,
979*5e7646d2SAndroid Build Coastguard Worker            job->filetypes[job->current_file]->type);
980*5e7646d2SAndroid Build Coastguard Worker   snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s",
981*5e7646d2SAndroid Build Coastguard Worker            job->printer->device_uri);
982*5e7646d2SAndroid Build Coastguard Worker   snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot,
983*5e7646d2SAndroid Build Coastguard Worker 	   job->printer->name);
984*5e7646d2SAndroid Build Coastguard Worker   snprintf(printer_info, sizeof(printer_name), "PRINTER_INFO=%s",
985*5e7646d2SAndroid Build Coastguard Worker            job->printer->info ? job->printer->info : "");
986*5e7646d2SAndroid Build Coastguard Worker   snprintf(printer_location, sizeof(printer_name), "PRINTER_LOCATION=%s",
987*5e7646d2SAndroid Build Coastguard Worker            job->printer->location ? job->printer->location : "");
988*5e7646d2SAndroid Build Coastguard Worker   snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", job->printer->name);
989*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->num_reasons > 0)
990*5e7646d2SAndroid Build Coastguard Worker   {
991*5e7646d2SAndroid Build Coastguard Worker     char	*psrptr;		/* Pointer into PRINTER_STATE_REASONS */
992*5e7646d2SAndroid Build Coastguard Worker     size_t	psrlen;			/* Size of PRINTER_STATE_REASONS */
993*5e7646d2SAndroid Build Coastguard Worker 
994*5e7646d2SAndroid Build Coastguard Worker     for (psrlen = 22, i = 0; i < job->printer->num_reasons; i ++)
995*5e7646d2SAndroid Build Coastguard Worker       psrlen += strlen(job->printer->reasons[i]) + 1;
996*5e7646d2SAndroid Build Coastguard Worker 
997*5e7646d2SAndroid Build Coastguard Worker     if ((printer_state_reasons = malloc(psrlen)) != NULL)
998*5e7646d2SAndroid Build Coastguard Worker     {
999*5e7646d2SAndroid Build Coastguard Worker      /*
1000*5e7646d2SAndroid Build Coastguard Worker       * All of these strcpy's are safe because we allocated the psr string...
1001*5e7646d2SAndroid Build Coastguard Worker       */
1002*5e7646d2SAndroid Build Coastguard Worker 
1003*5e7646d2SAndroid Build Coastguard Worker       strlcpy(printer_state_reasons, "PRINTER_STATE_REASONS=", psrlen);
1004*5e7646d2SAndroid Build Coastguard Worker       for (psrptr = printer_state_reasons + 22, i = 0;
1005*5e7646d2SAndroid Build Coastguard Worker            i < job->printer->num_reasons;
1006*5e7646d2SAndroid Build Coastguard Worker 	   i ++)
1007*5e7646d2SAndroid Build Coastguard Worker       {
1008*5e7646d2SAndroid Build Coastguard Worker         if (i)
1009*5e7646d2SAndroid Build Coastguard Worker 	  *psrptr++ = ',';
1010*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(psrptr, job->printer->reasons[i], psrlen - (size_t)(psrptr - printer_state_reasons));
1011*5e7646d2SAndroid Build Coastguard Worker 	psrptr += strlen(psrptr);
1012*5e7646d2SAndroid Build Coastguard Worker       }
1013*5e7646d2SAndroid Build Coastguard Worker     }
1014*5e7646d2SAndroid Build Coastguard Worker   }
1015*5e7646d2SAndroid Build Coastguard Worker   snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache);
1016*5e7646d2SAndroid Build Coastguard Worker 
1017*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->num_auth_info_required == 1)
1018*5e7646d2SAndroid Build Coastguard Worker     snprintf(auth_info_required, sizeof(auth_info_required),
1019*5e7646d2SAndroid Build Coastguard Worker              "AUTH_INFO_REQUIRED=%s",
1020*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[0]);
1021*5e7646d2SAndroid Build Coastguard Worker   else if (job->printer->num_auth_info_required == 2)
1022*5e7646d2SAndroid Build Coastguard Worker     snprintf(auth_info_required, sizeof(auth_info_required),
1023*5e7646d2SAndroid Build Coastguard Worker              "AUTH_INFO_REQUIRED=%s,%s",
1024*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[0],
1025*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[1]);
1026*5e7646d2SAndroid Build Coastguard Worker   else if (job->printer->num_auth_info_required == 3)
1027*5e7646d2SAndroid Build Coastguard Worker     snprintf(auth_info_required, sizeof(auth_info_required),
1028*5e7646d2SAndroid Build Coastguard Worker              "AUTH_INFO_REQUIRED=%s,%s,%s",
1029*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[0],
1030*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[1],
1031*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[2]);
1032*5e7646d2SAndroid Build Coastguard Worker   else if (job->printer->num_auth_info_required == 4)
1033*5e7646d2SAndroid Build Coastguard Worker     snprintf(auth_info_required, sizeof(auth_info_required),
1034*5e7646d2SAndroid Build Coastguard Worker              "AUTH_INFO_REQUIRED=%s,%s,%s,%s",
1035*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[0],
1036*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[1],
1037*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[2],
1038*5e7646d2SAndroid Build Coastguard Worker 	     job->printer->auth_info_required[3]);
1039*5e7646d2SAndroid Build Coastguard Worker   else
1040*5e7646d2SAndroid Build Coastguard Worker     strlcpy(auth_info_required, "AUTH_INFO_REQUIRED=none",
1041*5e7646d2SAndroid Build Coastguard Worker 	    sizeof(auth_info_required));
1042*5e7646d2SAndroid Build Coastguard Worker 
1043*5e7646d2SAndroid Build Coastguard Worker   envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1044*5e7646d2SAndroid Build Coastguard Worker 
1045*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = charset;
1046*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = lang;
1047*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
1048*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = apple_language;
1049*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
1050*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = ppd;
1051*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = rip_max_cache;
1052*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = content_type;
1053*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = device_uri;
1054*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = printer_info;
1055*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = printer_location;
1056*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = printer_name;
1057*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = printer_state_reasons ? printer_state_reasons :
1058*5e7646d2SAndroid Build Coastguard Worker                                           "PRINTER_STATE_REASONS=none";
1059*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = banner_page ? "CUPS_FILETYPE=job-sheet" :
1060*5e7646d2SAndroid Build Coastguard Worker                                 "CUPS_FILETYPE=document";
1061*5e7646d2SAndroid Build Coastguard Worker 
1062*5e7646d2SAndroid Build Coastguard Worker   if (final_content_type[0])
1063*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = final_content_type;
1064*5e7646d2SAndroid Build Coastguard Worker 
1065*5e7646d2SAndroid Build Coastguard Worker   if (Classification && !banner_page)
1066*5e7646d2SAndroid Build Coastguard Worker   {
1067*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-sheets",
1068*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_NAME)) == NULL)
1069*5e7646d2SAndroid Build Coastguard Worker       snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1070*5e7646d2SAndroid Build Coastguard Worker                Classification);
1071*5e7646d2SAndroid Build Coastguard Worker     else if (attr->num_values > 1 &&
1072*5e7646d2SAndroid Build Coastguard Worker              strcmp(attr->values[1].string.text, "none") != 0)
1073*5e7646d2SAndroid Build Coastguard Worker       snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1074*5e7646d2SAndroid Build Coastguard Worker                attr->values[1].string.text);
1075*5e7646d2SAndroid Build Coastguard Worker     else
1076*5e7646d2SAndroid Build Coastguard Worker       snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1077*5e7646d2SAndroid Build Coastguard Worker                attr->values[0].string.text);
1078*5e7646d2SAndroid Build Coastguard Worker 
1079*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = classification;
1080*5e7646d2SAndroid Build Coastguard Worker   }
1081*5e7646d2SAndroid Build Coastguard Worker 
1082*5e7646d2SAndroid Build Coastguard Worker   if (job->dtype & CUPS_PRINTER_CLASS)
1083*5e7646d2SAndroid Build Coastguard Worker   {
1084*5e7646d2SAndroid Build Coastguard Worker     snprintf(class_name, sizeof(class_name), "CLASS=%s", job->dest);
1085*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = class_name;
1086*5e7646d2SAndroid Build Coastguard Worker   }
1087*5e7646d2SAndroid Build Coastguard Worker 
1088*5e7646d2SAndroid Build Coastguard Worker   envp[envc ++] = auth_info_required;
1089*5e7646d2SAndroid Build Coastguard Worker 
1090*5e7646d2SAndroid Build Coastguard Worker   for (i = 0;
1091*5e7646d2SAndroid Build Coastguard Worker        i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
1092*5e7646d2SAndroid Build Coastguard Worker        i ++)
1093*5e7646d2SAndroid Build Coastguard Worker     if (job->auth_env[i])
1094*5e7646d2SAndroid Build Coastguard Worker       envp[envc ++] = job->auth_env[i];
1095*5e7646d2SAndroid Build Coastguard Worker     else
1096*5e7646d2SAndroid Build Coastguard Worker       break;
1097*5e7646d2SAndroid Build Coastguard Worker 
1098*5e7646d2SAndroid Build Coastguard Worker   if (job->auth_uid)
1099*5e7646d2SAndroid Build Coastguard Worker     envp[envc ++] = job->auth_uid;
1100*5e7646d2SAndroid Build Coastguard Worker 
1101*5e7646d2SAndroid Build Coastguard Worker   envp[envc] = NULL;
1102*5e7646d2SAndroid Build Coastguard Worker 
1103*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < envc; i ++)
1104*5e7646d2SAndroid Build Coastguard Worker     if (!strncmp(envp[i], "AUTH_", 5))
1105*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"AUTH_%c****\"", i,
1106*5e7646d2SAndroid Build Coastguard Worker                   envp[i][5]);
1107*5e7646d2SAndroid Build Coastguard Worker     else if (strncmp(envp[i], "DEVICE_URI=", 11))
1108*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"%s\"", i, envp[i]);
1109*5e7646d2SAndroid Build Coastguard Worker     else
1110*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "envp[%d]=\"DEVICE_URI=%s\"", i,
1111*5e7646d2SAndroid Build Coastguard Worker                   job->printer->sanitized_device_uri);
1112*5e7646d2SAndroid Build Coastguard Worker 
1113*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->remote)
1114*5e7646d2SAndroid Build Coastguard Worker     job->current_file = job->num_files;
1115*5e7646d2SAndroid Build Coastguard Worker   else
1116*5e7646d2SAndroid Build Coastguard Worker     job->current_file ++;
1117*5e7646d2SAndroid Build Coastguard Worker 
1118*5e7646d2SAndroid Build Coastguard Worker  /*
1119*5e7646d2SAndroid Build Coastguard Worker   * Now create processes for all of the filters...
1120*5e7646d2SAndroid Build Coastguard Worker   */
1121*5e7646d2SAndroid Build Coastguard Worker 
1122*5e7646d2SAndroid Build Coastguard Worker   for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters);
1123*5e7646d2SAndroid Build Coastguard Worker        filter;
1124*5e7646d2SAndroid Build Coastguard Worker        i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
1125*5e7646d2SAndroid Build Coastguard Worker   {
1126*5e7646d2SAndroid Build Coastguard Worker     if (filter->filter[0] != '/')
1127*5e7646d2SAndroid Build Coastguard Worker       snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
1128*5e7646d2SAndroid Build Coastguard Worker                filter->filter);
1129*5e7646d2SAndroid Build Coastguard Worker     else
1130*5e7646d2SAndroid Build Coastguard Worker       strlcpy(command, filter->filter, sizeof(command));
1131*5e7646d2SAndroid Build Coastguard Worker 
1132*5e7646d2SAndroid Build Coastguard Worker     if (i < (cupsArrayCount(filters) - 1))
1133*5e7646d2SAndroid Build Coastguard Worker     {
1134*5e7646d2SAndroid Build Coastguard Worker       if (cupsdOpenPipe(filterfds[slot]))
1135*5e7646d2SAndroid Build Coastguard Worker       {
1136*5e7646d2SAndroid Build Coastguard Worker         abort_message = "Stopping job because the scheduler could not create "
1137*5e7646d2SAndroid Build Coastguard Worker 	                "the filter pipes.";
1138*5e7646d2SAndroid Build Coastguard Worker 
1139*5e7646d2SAndroid Build Coastguard Worker         goto abort_job;
1140*5e7646d2SAndroid Build Coastguard Worker       }
1141*5e7646d2SAndroid Build Coastguard Worker     }
1142*5e7646d2SAndroid Build Coastguard Worker     else
1143*5e7646d2SAndroid Build Coastguard Worker     {
1144*5e7646d2SAndroid Build Coastguard Worker       if (job->current_file == 1 ||
1145*5e7646d2SAndroid Build Coastguard Worker           (job->printer->pc && job->printer->pc->single_file))
1146*5e7646d2SAndroid Build Coastguard Worker       {
1147*5e7646d2SAndroid Build Coastguard Worker 	if (strncmp(job->printer->device_uri, "file:", 5) != 0)
1148*5e7646d2SAndroid Build Coastguard Worker 	{
1149*5e7646d2SAndroid Build Coastguard Worker 	  if (cupsdOpenPipe(job->print_pipes))
1150*5e7646d2SAndroid Build Coastguard Worker 	  {
1151*5e7646d2SAndroid Build Coastguard Worker 	    abort_message = "Stopping job because the scheduler could not "
1152*5e7646d2SAndroid Build Coastguard Worker 	                    "create the backend pipes.";
1153*5e7646d2SAndroid Build Coastguard Worker 
1154*5e7646d2SAndroid Build Coastguard Worker             goto abort_job;
1155*5e7646d2SAndroid Build Coastguard Worker 	  }
1156*5e7646d2SAndroid Build Coastguard Worker 	}
1157*5e7646d2SAndroid Build Coastguard Worker 	else
1158*5e7646d2SAndroid Build Coastguard Worker 	{
1159*5e7646d2SAndroid Build Coastguard Worker 	  job->print_pipes[0] = -1;
1160*5e7646d2SAndroid Build Coastguard Worker 	  if (!strcmp(job->printer->device_uri, "file:/dev/null") ||
1161*5e7646d2SAndroid Build Coastguard Worker 	      !strcmp(job->printer->device_uri, "file:///dev/null"))
1162*5e7646d2SAndroid Build Coastguard Worker 	    job->print_pipes[1] = -1;
1163*5e7646d2SAndroid Build Coastguard Worker 	  else
1164*5e7646d2SAndroid Build Coastguard Worker 	  {
1165*5e7646d2SAndroid Build Coastguard Worker 	    if (!strncmp(job->printer->device_uri, "file:/dev/", 10))
1166*5e7646d2SAndroid Build Coastguard Worker 	      job->print_pipes[1] = open(job->printer->device_uri + 5,
1167*5e7646d2SAndroid Build Coastguard Worker 	                        	 O_WRONLY | O_EXCL);
1168*5e7646d2SAndroid Build Coastguard Worker 	    else if (!strncmp(job->printer->device_uri, "file:///dev/", 12))
1169*5e7646d2SAndroid Build Coastguard Worker 	      job->print_pipes[1] = open(job->printer->device_uri + 7,
1170*5e7646d2SAndroid Build Coastguard Worker 	                        	 O_WRONLY | O_EXCL);
1171*5e7646d2SAndroid Build Coastguard Worker 	    else if (!strncmp(job->printer->device_uri, "file:///", 8))
1172*5e7646d2SAndroid Build Coastguard Worker 	      job->print_pipes[1] = open(job->printer->device_uri + 7,
1173*5e7646d2SAndroid Build Coastguard Worker 	                        	 O_WRONLY | O_CREAT | O_TRUNC, 0600);
1174*5e7646d2SAndroid Build Coastguard Worker 	    else
1175*5e7646d2SAndroid Build Coastguard Worker 	      job->print_pipes[1] = open(job->printer->device_uri + 5,
1176*5e7646d2SAndroid Build Coastguard Worker 	                        	 O_WRONLY | O_CREAT | O_TRUNC, 0600);
1177*5e7646d2SAndroid Build Coastguard Worker 
1178*5e7646d2SAndroid Build Coastguard Worker 	    if (job->print_pipes[1] < 0)
1179*5e7646d2SAndroid Build Coastguard Worker 	    {
1180*5e7646d2SAndroid Build Coastguard Worker 	      abort_message = "Stopping job because the scheduler could not "
1181*5e7646d2SAndroid Build Coastguard Worker 	                      "open the output file.";
1182*5e7646d2SAndroid Build Coastguard Worker 
1183*5e7646d2SAndroid Build Coastguard Worker               goto abort_job;
1184*5e7646d2SAndroid Build Coastguard Worker 	    }
1185*5e7646d2SAndroid Build Coastguard Worker 
1186*5e7646d2SAndroid Build Coastguard Worker 	    fcntl(job->print_pipes[1], F_SETFD,
1187*5e7646d2SAndroid Build Coastguard Worker         	  fcntl(job->print_pipes[1], F_GETFD) | FD_CLOEXEC);
1188*5e7646d2SAndroid Build Coastguard Worker           }
1189*5e7646d2SAndroid Build Coastguard Worker 	}
1190*5e7646d2SAndroid Build Coastguard Worker       }
1191*5e7646d2SAndroid Build Coastguard Worker 
1192*5e7646d2SAndroid Build Coastguard Worker       filterfds[slot][0] = job->print_pipes[0];
1193*5e7646d2SAndroid Build Coastguard Worker       filterfds[slot][1] = job->print_pipes[1];
1194*5e7646d2SAndroid Build Coastguard Worker     }
1195*5e7646d2SAndroid Build Coastguard Worker 
1196*5e7646d2SAndroid Build Coastguard Worker     pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
1197*5e7646d2SAndroid Build Coastguard Worker                             filterfds[slot][1], job->status_pipes[1],
1198*5e7646d2SAndroid Build Coastguard Worker 		            job->back_pipes[0], job->side_pipes[0], 0,
1199*5e7646d2SAndroid Build Coastguard Worker 			    job->profile, job, job->filters + i);
1200*5e7646d2SAndroid Build Coastguard Worker 
1201*5e7646d2SAndroid Build Coastguard Worker     cupsdClosePipe(filterfds[!slot]);
1202*5e7646d2SAndroid Build Coastguard Worker 
1203*5e7646d2SAndroid Build Coastguard Worker     if (pid == 0)
1204*5e7646d2SAndroid Build Coastguard Worker     {
1205*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to start filter \"%s\" - %s.",
1206*5e7646d2SAndroid Build Coastguard Worker 		  filter->filter, strerror(errno));
1207*5e7646d2SAndroid Build Coastguard Worker 
1208*5e7646d2SAndroid Build Coastguard Worker       abort_message = "Stopping job because the scheduler could not execute a "
1209*5e7646d2SAndroid Build Coastguard Worker 		      "filter.";
1210*5e7646d2SAndroid Build Coastguard Worker 
1211*5e7646d2SAndroid Build Coastguard Worker       goto abort_job;
1212*5e7646d2SAndroid Build Coastguard Worker     }
1213*5e7646d2SAndroid Build Coastguard Worker 
1214*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_INFO, "Started filter %s (PID %d)", command,
1215*5e7646d2SAndroid Build Coastguard Worker                 pid);
1216*5e7646d2SAndroid Build Coastguard Worker 
1217*5e7646d2SAndroid Build Coastguard Worker     if (argv[6])
1218*5e7646d2SAndroid Build Coastguard Worker     {
1219*5e7646d2SAndroid Build Coastguard Worker       free(argv[6]);
1220*5e7646d2SAndroid Build Coastguard Worker       argv[6] = NULL;
1221*5e7646d2SAndroid Build Coastguard Worker     }
1222*5e7646d2SAndroid Build Coastguard Worker 
1223*5e7646d2SAndroid Build Coastguard Worker     slot = !slot;
1224*5e7646d2SAndroid Build Coastguard Worker   }
1225*5e7646d2SAndroid Build Coastguard Worker 
1226*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(filters);
1227*5e7646d2SAndroid Build Coastguard Worker   filters = NULL;
1228*5e7646d2SAndroid Build Coastguard Worker 
1229*5e7646d2SAndroid Build Coastguard Worker  /*
1230*5e7646d2SAndroid Build Coastguard Worker   * Finally, pipe the final output into a backend process if needed...
1231*5e7646d2SAndroid Build Coastguard Worker   */
1232*5e7646d2SAndroid Build Coastguard Worker 
1233*5e7646d2SAndroid Build Coastguard Worker   if (strncmp(job->printer->device_uri, "file:", 5) != 0)
1234*5e7646d2SAndroid Build Coastguard Worker   {
1235*5e7646d2SAndroid Build Coastguard Worker     if (job->current_file == 1 || job->printer->remote ||
1236*5e7646d2SAndroid Build Coastguard Worker         (job->printer->pc && job->printer->pc->single_file))
1237*5e7646d2SAndroid Build Coastguard Worker     {
1238*5e7646d2SAndroid Build Coastguard Worker       sscanf(job->printer->device_uri, "%254[^:]", scheme);
1239*5e7646d2SAndroid Build Coastguard Worker       snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, scheme);
1240*5e7646d2SAndroid Build Coastguard Worker 
1241*5e7646d2SAndroid Build Coastguard Worker      /*
1242*5e7646d2SAndroid Build Coastguard Worker       * See if the backend needs to run as root...
1243*5e7646d2SAndroid Build Coastguard Worker       */
1244*5e7646d2SAndroid Build Coastguard Worker 
1245*5e7646d2SAndroid Build Coastguard Worker       if (RunUser)
1246*5e7646d2SAndroid Build Coastguard Worker         backroot = 0;
1247*5e7646d2SAndroid Build Coastguard Worker       else if (stat(command, &backinfo))
1248*5e7646d2SAndroid Build Coastguard Worker 	backroot = 0;
1249*5e7646d2SAndroid Build Coastguard Worker       else
1250*5e7646d2SAndroid Build Coastguard Worker         backroot = !(backinfo.st_mode & (S_IWGRP | S_IWOTH | S_IXOTH));
1251*5e7646d2SAndroid Build Coastguard Worker 
1252*5e7646d2SAndroid Build Coastguard Worker       argv[0] = job->printer->sanitized_device_uri;
1253*5e7646d2SAndroid Build Coastguard Worker 
1254*5e7646d2SAndroid Build Coastguard Worker       filterfds[slot][0] = -1;
1255*5e7646d2SAndroid Build Coastguard Worker       filterfds[slot][1] = -1;
1256*5e7646d2SAndroid Build Coastguard Worker 
1257*5e7646d2SAndroid Build Coastguard Worker       pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
1258*5e7646d2SAndroid Build Coastguard Worker 			      filterfds[slot][1], job->status_pipes[1],
1259*5e7646d2SAndroid Build Coastguard Worker 			      job->back_pipes[1], job->side_pipes[1],
1260*5e7646d2SAndroid Build Coastguard Worker 			      backroot, job->bprofile, job, &(job->backend));
1261*5e7646d2SAndroid Build Coastguard Worker 
1262*5e7646d2SAndroid Build Coastguard Worker       if (pid == 0)
1263*5e7646d2SAndroid Build Coastguard Worker       {
1264*5e7646d2SAndroid Build Coastguard Worker 	abort_message = "Stopping job because the sheduler could not execute "
1265*5e7646d2SAndroid Build Coastguard Worker 			"the backend.";
1266*5e7646d2SAndroid Build Coastguard Worker 
1267*5e7646d2SAndroid Build Coastguard Worker         goto abort_job;
1268*5e7646d2SAndroid Build Coastguard Worker       }
1269*5e7646d2SAndroid Build Coastguard Worker       else
1270*5e7646d2SAndroid Build Coastguard Worker       {
1271*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogJob(job, CUPSD_LOG_INFO, "Started backend %s (PID %d)",
1272*5e7646d2SAndroid Build Coastguard Worker 		    command, pid);
1273*5e7646d2SAndroid Build Coastguard Worker       }
1274*5e7646d2SAndroid Build Coastguard Worker     }
1275*5e7646d2SAndroid Build Coastguard Worker 
1276*5e7646d2SAndroid Build Coastguard Worker     if (job->current_file == job->num_files ||
1277*5e7646d2SAndroid Build Coastguard Worker         (job->printer->pc && job->printer->pc->single_file))
1278*5e7646d2SAndroid Build Coastguard Worker       cupsdClosePipe(job->print_pipes);
1279*5e7646d2SAndroid Build Coastguard Worker 
1280*5e7646d2SAndroid Build Coastguard Worker     if (job->current_file == job->num_files)
1281*5e7646d2SAndroid Build Coastguard Worker     {
1282*5e7646d2SAndroid Build Coastguard Worker       cupsdClosePipe(job->back_pipes);
1283*5e7646d2SAndroid Build Coastguard Worker       cupsdClosePipe(job->side_pipes);
1284*5e7646d2SAndroid Build Coastguard Worker 
1285*5e7646d2SAndroid Build Coastguard Worker       close(job->status_pipes[1]);
1286*5e7646d2SAndroid Build Coastguard Worker       job->status_pipes[1] = -1;
1287*5e7646d2SAndroid Build Coastguard Worker     }
1288*5e7646d2SAndroid Build Coastguard Worker   }
1289*5e7646d2SAndroid Build Coastguard Worker   else
1290*5e7646d2SAndroid Build Coastguard Worker   {
1291*5e7646d2SAndroid Build Coastguard Worker     filterfds[slot][0] = -1;
1292*5e7646d2SAndroid Build Coastguard Worker     filterfds[slot][1] = -1;
1293*5e7646d2SAndroid Build Coastguard Worker 
1294*5e7646d2SAndroid Build Coastguard Worker     if (job->current_file == job->num_files ||
1295*5e7646d2SAndroid Build Coastguard Worker         (job->printer->pc && job->printer->pc->single_file))
1296*5e7646d2SAndroid Build Coastguard Worker       cupsdClosePipe(job->print_pipes);
1297*5e7646d2SAndroid Build Coastguard Worker 
1298*5e7646d2SAndroid Build Coastguard Worker     if (job->current_file == job->num_files)
1299*5e7646d2SAndroid Build Coastguard Worker     {
1300*5e7646d2SAndroid Build Coastguard Worker       close(job->status_pipes[1]);
1301*5e7646d2SAndroid Build Coastguard Worker       job->status_pipes[1] = -1;
1302*5e7646d2SAndroid Build Coastguard Worker     }
1303*5e7646d2SAndroid Build Coastguard Worker   }
1304*5e7646d2SAndroid Build Coastguard Worker 
1305*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(filterfds[slot]);
1306*5e7646d2SAndroid Build Coastguard Worker 
1307*5e7646d2SAndroid Build Coastguard Worker   for (i = 6; i < argc; i ++)
1308*5e7646d2SAndroid Build Coastguard Worker     free(argv[i]);
1309*5e7646d2SAndroid Build Coastguard Worker   free(argv);
1310*5e7646d2SAndroid Build Coastguard Worker 
1311*5e7646d2SAndroid Build Coastguard Worker   if (printer_state_reasons)
1312*5e7646d2SAndroid Build Coastguard Worker     free(printer_state_reasons);
1313*5e7646d2SAndroid Build Coastguard Worker 
1314*5e7646d2SAndroid Build Coastguard Worker   cupsdAddSelect(job->status_buffer->fd, (cupsd_selfunc_t)update_job, NULL,
1315*5e7646d2SAndroid Build Coastguard Worker                  job);
1316*5e7646d2SAndroid Build Coastguard Worker 
1317*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "Job #%d started.",
1318*5e7646d2SAndroid Build Coastguard Worker                 job->id);
1319*5e7646d2SAndroid Build Coastguard Worker 
1320*5e7646d2SAndroid Build Coastguard Worker   return;
1321*5e7646d2SAndroid Build Coastguard Worker 
1322*5e7646d2SAndroid Build Coastguard Worker 
1323*5e7646d2SAndroid Build Coastguard Worker  /*
1324*5e7646d2SAndroid Build Coastguard Worker   * If we get here, we need to abort the current job and close out all
1325*5e7646d2SAndroid Build Coastguard Worker   * files and pipes...
1326*5e7646d2SAndroid Build Coastguard Worker   */
1327*5e7646d2SAndroid Build Coastguard Worker 
1328*5e7646d2SAndroid Build Coastguard Worker   abort_job:
1329*5e7646d2SAndroid Build Coastguard Worker 
1330*5e7646d2SAndroid Build Coastguard Worker   FilterLevel -= job->cost;
1331*5e7646d2SAndroid Build Coastguard Worker   job->cost = 0;
1332*5e7646d2SAndroid Build Coastguard Worker 
1333*5e7646d2SAndroid Build Coastguard Worker   for (slot = 0; slot < 2; slot ++)
1334*5e7646d2SAndroid Build Coastguard Worker     cupsdClosePipe(filterfds[slot]);
1335*5e7646d2SAndroid Build Coastguard Worker 
1336*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(filters);
1337*5e7646d2SAndroid Build Coastguard Worker 
1338*5e7646d2SAndroid Build Coastguard Worker   if (argv)
1339*5e7646d2SAndroid Build Coastguard Worker   {
1340*5e7646d2SAndroid Build Coastguard Worker     for (i = 6; i < argc; i ++)
1341*5e7646d2SAndroid Build Coastguard Worker       free(argv[i]);
1342*5e7646d2SAndroid Build Coastguard Worker 
1343*5e7646d2SAndroid Build Coastguard Worker     free(argv);
1344*5e7646d2SAndroid Build Coastguard Worker   }
1345*5e7646d2SAndroid Build Coastguard Worker 
1346*5e7646d2SAndroid Build Coastguard Worker   if (printer_state_reasons)
1347*5e7646d2SAndroid Build Coastguard Worker     free(printer_state_reasons);
1348*5e7646d2SAndroid Build Coastguard Worker 
1349*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->print_pipes);
1350*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->back_pipes);
1351*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->side_pipes);
1352*5e7646d2SAndroid Build Coastguard Worker 
1353*5e7646d2SAndroid Build Coastguard Worker   cupsdRemoveSelect(job->status_pipes[0]);
1354*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->status_pipes);
1355*5e7646d2SAndroid Build Coastguard Worker   cupsdStatBufDelete(job->status_buffer);
1356*5e7646d2SAndroid Build Coastguard Worker   job->status_buffer = NULL;
1357*5e7646d2SAndroid Build Coastguard Worker 
1358*5e7646d2SAndroid Build Coastguard Worker  /*
1359*5e7646d2SAndroid Build Coastguard Worker   * Update the printer and job state.
1360*5e7646d2SAndroid Build Coastguard Worker   */
1361*5e7646d2SAndroid Build Coastguard Worker 
1362*5e7646d2SAndroid Build Coastguard Worker   cupsdSetJobState(job, abort_state, CUPSD_JOB_DEFAULT, "%s", abort_message);
1363*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterState(job->printer, IPP_PRINTER_IDLE, 0);
1364*5e7646d2SAndroid Build Coastguard Worker   update_job_attrs(job, 0);
1365*5e7646d2SAndroid Build Coastguard Worker 
1366*5e7646d2SAndroid Build Coastguard Worker   if (job->history)
1367*5e7646d2SAndroid Build Coastguard Worker     free_job_history(job);
1368*5e7646d2SAndroid Build Coastguard Worker 
1369*5e7646d2SAndroid Build Coastguard Worker   cupsArrayRemove(PrintingJobs, job);
1370*5e7646d2SAndroid Build Coastguard Worker 
1371*5e7646d2SAndroid Build Coastguard Worker  /*
1372*5e7646d2SAndroid Build Coastguard Worker   * Clear the printer <-> job association...
1373*5e7646d2SAndroid Build Coastguard Worker   */
1374*5e7646d2SAndroid Build Coastguard Worker 
1375*5e7646d2SAndroid Build Coastguard Worker   job->printer->job = NULL;
1376*5e7646d2SAndroid Build Coastguard Worker   job->printer      = NULL;
1377*5e7646d2SAndroid Build Coastguard Worker }
1378*5e7646d2SAndroid Build Coastguard Worker 
1379*5e7646d2SAndroid Build Coastguard Worker 
1380*5e7646d2SAndroid Build Coastguard Worker /*
1381*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdDeleteJob()' - Free all memory used by a job.
1382*5e7646d2SAndroid Build Coastguard Worker  */
1383*5e7646d2SAndroid Build Coastguard Worker 
1384*5e7646d2SAndroid Build Coastguard Worker void
cupsdDeleteJob(cupsd_job_t * job,cupsd_jobaction_t action)1385*5e7646d2SAndroid Build Coastguard Worker cupsdDeleteJob(cupsd_job_t       *job,	/* I - Job */
1386*5e7646d2SAndroid Build Coastguard Worker                cupsd_jobaction_t action)/* I - Action */
1387*5e7646d2SAndroid Build Coastguard Worker {
1388*5e7646d2SAndroid Build Coastguard Worker   int	i;				/* Looping var */
1389*5e7646d2SAndroid Build Coastguard Worker 
1390*5e7646d2SAndroid Build Coastguard Worker 
1391*5e7646d2SAndroid Build Coastguard Worker   if (job->printer)
1392*5e7646d2SAndroid Build Coastguard Worker     finalize_job(job, 1);
1393*5e7646d2SAndroid Build Coastguard Worker 
1394*5e7646d2SAndroid Build Coastguard Worker   if (action == CUPSD_JOB_PURGE)
1395*5e7646d2SAndroid Build Coastguard Worker     remove_job_history(job);
1396*5e7646d2SAndroid Build Coastguard Worker 
1397*5e7646d2SAndroid Build Coastguard Worker   cupsdClearString(&job->username);
1398*5e7646d2SAndroid Build Coastguard Worker   cupsdClearString(&job->dest);
1399*5e7646d2SAndroid Build Coastguard Worker   for (i = 0;
1400*5e7646d2SAndroid Build Coastguard Worker        i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
1401*5e7646d2SAndroid Build Coastguard Worker        i ++)
1402*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(job->auth_env + i);
1403*5e7646d2SAndroid Build Coastguard Worker   cupsdClearString(&job->auth_uid);
1404*5e7646d2SAndroid Build Coastguard Worker 
1405*5e7646d2SAndroid Build Coastguard Worker   if (action == CUPSD_JOB_PURGE)
1406*5e7646d2SAndroid Build Coastguard Worker     remove_job_files(job);
1407*5e7646d2SAndroid Build Coastguard Worker   else if (job->num_files > 0)
1408*5e7646d2SAndroid Build Coastguard Worker   {
1409*5e7646d2SAndroid Build Coastguard Worker     free(job->compressions);
1410*5e7646d2SAndroid Build Coastguard Worker     free(job->filetypes);
1411*5e7646d2SAndroid Build Coastguard Worker 
1412*5e7646d2SAndroid Build Coastguard Worker     job->num_files = 0;
1413*5e7646d2SAndroid Build Coastguard Worker   }
1414*5e7646d2SAndroid Build Coastguard Worker 
1415*5e7646d2SAndroid Build Coastguard Worker   if (job->history)
1416*5e7646d2SAndroid Build Coastguard Worker     free_job_history(job);
1417*5e7646d2SAndroid Build Coastguard Worker 
1418*5e7646d2SAndroid Build Coastguard Worker   unload_job(job);
1419*5e7646d2SAndroid Build Coastguard Worker 
1420*5e7646d2SAndroid Build Coastguard Worker   cupsArrayRemove(Jobs, job);
1421*5e7646d2SAndroid Build Coastguard Worker   cupsArrayRemove(ActiveJobs, job);
1422*5e7646d2SAndroid Build Coastguard Worker   cupsArrayRemove(PrintingJobs, job);
1423*5e7646d2SAndroid Build Coastguard Worker 
1424*5e7646d2SAndroid Build Coastguard Worker   free(job);
1425*5e7646d2SAndroid Build Coastguard Worker }
1426*5e7646d2SAndroid Build Coastguard Worker 
1427*5e7646d2SAndroid Build Coastguard Worker 
1428*5e7646d2SAndroid Build Coastguard Worker /*
1429*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdFreeAllJobs()' - Free all jobs from memory.
1430*5e7646d2SAndroid Build Coastguard Worker  */
1431*5e7646d2SAndroid Build Coastguard Worker 
1432*5e7646d2SAndroid Build Coastguard Worker void
cupsdFreeAllJobs(void)1433*5e7646d2SAndroid Build Coastguard Worker cupsdFreeAllJobs(void)
1434*5e7646d2SAndroid Build Coastguard Worker {
1435*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
1436*5e7646d2SAndroid Build Coastguard Worker 
1437*5e7646d2SAndroid Build Coastguard Worker 
1438*5e7646d2SAndroid Build Coastguard Worker   if (!Jobs)
1439*5e7646d2SAndroid Build Coastguard Worker     return;
1440*5e7646d2SAndroid Build Coastguard Worker 
1441*5e7646d2SAndroid Build Coastguard Worker   cupsdHoldSignals();
1442*5e7646d2SAndroid Build Coastguard Worker 
1443*5e7646d2SAndroid Build Coastguard Worker   cupsdStopAllJobs(CUPSD_JOB_FORCE, 0);
1444*5e7646d2SAndroid Build Coastguard Worker   cupsdSaveAllJobs();
1445*5e7646d2SAndroid Build Coastguard Worker 
1446*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
1447*5e7646d2SAndroid Build Coastguard Worker        job;
1448*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(Jobs))
1449*5e7646d2SAndroid Build Coastguard Worker     cupsdDeleteJob(job, CUPSD_JOB_DEFAULT);
1450*5e7646d2SAndroid Build Coastguard Worker 
1451*5e7646d2SAndroid Build Coastguard Worker   cupsdReleaseSignals();
1452*5e7646d2SAndroid Build Coastguard Worker }
1453*5e7646d2SAndroid Build Coastguard Worker 
1454*5e7646d2SAndroid Build Coastguard Worker 
1455*5e7646d2SAndroid Build Coastguard Worker /*
1456*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdFindJob()' - Find the specified job.
1457*5e7646d2SAndroid Build Coastguard Worker  */
1458*5e7646d2SAndroid Build Coastguard Worker 
1459*5e7646d2SAndroid Build Coastguard Worker cupsd_job_t *				/* O - Job data */
cupsdFindJob(int id)1460*5e7646d2SAndroid Build Coastguard Worker cupsdFindJob(int id)			/* I - Job ID */
1461*5e7646d2SAndroid Build Coastguard Worker {
1462*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	key;			/* Search key */
1463*5e7646d2SAndroid Build Coastguard Worker 
1464*5e7646d2SAndroid Build Coastguard Worker 
1465*5e7646d2SAndroid Build Coastguard Worker   key.id = id;
1466*5e7646d2SAndroid Build Coastguard Worker 
1467*5e7646d2SAndroid Build Coastguard Worker   return ((cupsd_job_t *)cupsArrayFind(Jobs, &key));
1468*5e7646d2SAndroid Build Coastguard Worker }
1469*5e7646d2SAndroid Build Coastguard Worker 
1470*5e7646d2SAndroid Build Coastguard Worker 
1471*5e7646d2SAndroid Build Coastguard Worker /*
1472*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdGetCompletedJobs()'- Generate a completed jobs list.
1473*5e7646d2SAndroid Build Coastguard Worker  */
1474*5e7646d2SAndroid Build Coastguard Worker 
1475*5e7646d2SAndroid Build Coastguard Worker cups_array_t *				/* O - Array of jobs */
cupsdGetCompletedJobs(cupsd_printer_t * p)1476*5e7646d2SAndroid Build Coastguard Worker cupsdGetCompletedJobs(
1477*5e7646d2SAndroid Build Coastguard Worker     cupsd_printer_t *p)			/* I - Printer */
1478*5e7646d2SAndroid Build Coastguard Worker {
1479*5e7646d2SAndroid Build Coastguard Worker   cups_array_t	*list;			/* Array of jobs */
1480*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
1481*5e7646d2SAndroid Build Coastguard Worker 
1482*5e7646d2SAndroid Build Coastguard Worker 
1483*5e7646d2SAndroid Build Coastguard Worker   list = cupsArrayNew(compare_completed_jobs, NULL);
1484*5e7646d2SAndroid Build Coastguard Worker 
1485*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
1486*5e7646d2SAndroid Build Coastguard Worker        job;
1487*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(Jobs))
1488*5e7646d2SAndroid Build Coastguard Worker     if ((!p || !_cups_strcasecmp(p->name, job->dest)) && job->state_value >= IPP_JOB_STOPPED && job->completed_time)
1489*5e7646d2SAndroid Build Coastguard Worker       cupsArrayAdd(list, job);
1490*5e7646d2SAndroid Build Coastguard Worker 
1491*5e7646d2SAndroid Build Coastguard Worker   return (list);
1492*5e7646d2SAndroid Build Coastguard Worker }
1493*5e7646d2SAndroid Build Coastguard Worker 
1494*5e7646d2SAndroid Build Coastguard Worker 
1495*5e7646d2SAndroid Build Coastguard Worker /*
1496*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdGetPrinterJobCount()' - Get the number of pending, processing,
1497*5e7646d2SAndroid Build Coastguard Worker  *                               or held jobs in a printer or class.
1498*5e7646d2SAndroid Build Coastguard Worker  */
1499*5e7646d2SAndroid Build Coastguard Worker 
1500*5e7646d2SAndroid Build Coastguard Worker int					/* O - Job count */
cupsdGetPrinterJobCount(const char * dest)1501*5e7646d2SAndroid Build Coastguard Worker cupsdGetPrinterJobCount(
1502*5e7646d2SAndroid Build Coastguard Worker     const char *dest)			/* I - Printer or class name */
1503*5e7646d2SAndroid Build Coastguard Worker {
1504*5e7646d2SAndroid Build Coastguard Worker   int		count;			/* Job count */
1505*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
1506*5e7646d2SAndroid Build Coastguard Worker 
1507*5e7646d2SAndroid Build Coastguard Worker 
1508*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0;
1509*5e7646d2SAndroid Build Coastguard Worker        job;
1510*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
1511*5e7646d2SAndroid Build Coastguard Worker     if (job->dest && !_cups_strcasecmp(job->dest, dest))
1512*5e7646d2SAndroid Build Coastguard Worker       count ++;
1513*5e7646d2SAndroid Build Coastguard Worker 
1514*5e7646d2SAndroid Build Coastguard Worker   return (count);
1515*5e7646d2SAndroid Build Coastguard Worker }
1516*5e7646d2SAndroid Build Coastguard Worker 
1517*5e7646d2SAndroid Build Coastguard Worker 
1518*5e7646d2SAndroid Build Coastguard Worker /*
1519*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdGetUserJobCount()' - Get the number of pending, processing,
1520*5e7646d2SAndroid Build Coastguard Worker  *                            or held jobs for a user.
1521*5e7646d2SAndroid Build Coastguard Worker  */
1522*5e7646d2SAndroid Build Coastguard Worker 
1523*5e7646d2SAndroid Build Coastguard Worker int					/* O - Job count */
cupsdGetUserJobCount(const char * username)1524*5e7646d2SAndroid Build Coastguard Worker cupsdGetUserJobCount(
1525*5e7646d2SAndroid Build Coastguard Worker     const char *username)		/* I - Username */
1526*5e7646d2SAndroid Build Coastguard Worker {
1527*5e7646d2SAndroid Build Coastguard Worker   int		count;			/* Job count */
1528*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
1529*5e7646d2SAndroid Build Coastguard Worker 
1530*5e7646d2SAndroid Build Coastguard Worker 
1531*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0;
1532*5e7646d2SAndroid Build Coastguard Worker        job;
1533*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
1534*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strcasecmp(job->username, username))
1535*5e7646d2SAndroid Build Coastguard Worker       count ++;
1536*5e7646d2SAndroid Build Coastguard Worker 
1537*5e7646d2SAndroid Build Coastguard Worker   return (count);
1538*5e7646d2SAndroid Build Coastguard Worker }
1539*5e7646d2SAndroid Build Coastguard Worker 
1540*5e7646d2SAndroid Build Coastguard Worker 
1541*5e7646d2SAndroid Build Coastguard Worker /*
1542*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdLoadAllJobs()' - Load all jobs from disk.
1543*5e7646d2SAndroid Build Coastguard Worker  */
1544*5e7646d2SAndroid Build Coastguard Worker 
1545*5e7646d2SAndroid Build Coastguard Worker void
cupsdLoadAllJobs(void)1546*5e7646d2SAndroid Build Coastguard Worker cupsdLoadAllJobs(void)
1547*5e7646d2SAndroid Build Coastguard Worker {
1548*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024];		/* Full filename of job.cache file */
1549*5e7646d2SAndroid Build Coastguard Worker   struct stat	fileinfo;		/* Information on job.cache file */
1550*5e7646d2SAndroid Build Coastguard Worker   cups_dir_t	*dir;			/* RequestRoot dir */
1551*5e7646d2SAndroid Build Coastguard Worker   cups_dentry_t	*dent;			/* Entry in RequestRoot */
1552*5e7646d2SAndroid Build Coastguard Worker   int		load_cache = 1;		/* Load the job.cache file? */
1553*5e7646d2SAndroid Build Coastguard Worker 
1554*5e7646d2SAndroid Build Coastguard Worker 
1555*5e7646d2SAndroid Build Coastguard Worker  /*
1556*5e7646d2SAndroid Build Coastguard Worker   * Create the job arrays as needed...
1557*5e7646d2SAndroid Build Coastguard Worker   */
1558*5e7646d2SAndroid Build Coastguard Worker 
1559*5e7646d2SAndroid Build Coastguard Worker   if (!Jobs)
1560*5e7646d2SAndroid Build Coastguard Worker     Jobs = cupsArrayNew(compare_jobs, NULL);
1561*5e7646d2SAndroid Build Coastguard Worker 
1562*5e7646d2SAndroid Build Coastguard Worker   if (!ActiveJobs)
1563*5e7646d2SAndroid Build Coastguard Worker     ActiveJobs = cupsArrayNew(compare_active_jobs, NULL);
1564*5e7646d2SAndroid Build Coastguard Worker 
1565*5e7646d2SAndroid Build Coastguard Worker   if (!PrintingJobs)
1566*5e7646d2SAndroid Build Coastguard Worker     PrintingJobs = cupsArrayNew(compare_jobs, NULL);
1567*5e7646d2SAndroid Build Coastguard Worker 
1568*5e7646d2SAndroid Build Coastguard Worker  /*
1569*5e7646d2SAndroid Build Coastguard Worker   * See whether the job.cache file is older than the RequestRoot directory...
1570*5e7646d2SAndroid Build Coastguard Worker   */
1571*5e7646d2SAndroid Build Coastguard Worker 
1572*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/job.cache", CacheDir);
1573*5e7646d2SAndroid Build Coastguard Worker 
1574*5e7646d2SAndroid Build Coastguard Worker   if (stat(filename, &fileinfo))
1575*5e7646d2SAndroid Build Coastguard Worker   {
1576*5e7646d2SAndroid Build Coastguard Worker    /*
1577*5e7646d2SAndroid Build Coastguard Worker     * No job.cache file...
1578*5e7646d2SAndroid Build Coastguard Worker     */
1579*5e7646d2SAndroid Build Coastguard Worker 
1580*5e7646d2SAndroid Build Coastguard Worker     load_cache = 0;
1581*5e7646d2SAndroid Build Coastguard Worker 
1582*5e7646d2SAndroid Build Coastguard Worker     if (errno != ENOENT)
1583*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR,
1584*5e7646d2SAndroid Build Coastguard Worker                       "Unable to get file information for \"%s\" - %s",
1585*5e7646d2SAndroid Build Coastguard Worker 		      filename, strerror(errno));
1586*5e7646d2SAndroid Build Coastguard Worker   }
1587*5e7646d2SAndroid Build Coastguard Worker   else if ((dir = cupsDirOpen(RequestRoot)) == NULL)
1588*5e7646d2SAndroid Build Coastguard Worker   {
1589*5e7646d2SAndroid Build Coastguard Worker    /*
1590*5e7646d2SAndroid Build Coastguard Worker     * No spool directory...
1591*5e7646d2SAndroid Build Coastguard Worker     */
1592*5e7646d2SAndroid Build Coastguard Worker 
1593*5e7646d2SAndroid Build Coastguard Worker     load_cache = 0;
1594*5e7646d2SAndroid Build Coastguard Worker   }
1595*5e7646d2SAndroid Build Coastguard Worker   else
1596*5e7646d2SAndroid Build Coastguard Worker   {
1597*5e7646d2SAndroid Build Coastguard Worker     while ((dent = cupsDirRead(dir)) != NULL)
1598*5e7646d2SAndroid Build Coastguard Worker     {
1599*5e7646d2SAndroid Build Coastguard Worker       if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c' && dent->fileinfo.st_mtime > fileinfo.st_mtime)
1600*5e7646d2SAndroid Build Coastguard Worker       {
1601*5e7646d2SAndroid Build Coastguard Worker        /*
1602*5e7646d2SAndroid Build Coastguard Worker         * Job history file is newer than job.cache file...
1603*5e7646d2SAndroid Build Coastguard Worker 	*/
1604*5e7646d2SAndroid Build Coastguard Worker 
1605*5e7646d2SAndroid Build Coastguard Worker         load_cache = 0;
1606*5e7646d2SAndroid Build Coastguard Worker 	break;
1607*5e7646d2SAndroid Build Coastguard Worker       }
1608*5e7646d2SAndroid Build Coastguard Worker     }
1609*5e7646d2SAndroid Build Coastguard Worker 
1610*5e7646d2SAndroid Build Coastguard Worker     cupsDirClose(dir);
1611*5e7646d2SAndroid Build Coastguard Worker   }
1612*5e7646d2SAndroid Build Coastguard Worker 
1613*5e7646d2SAndroid Build Coastguard Worker  /*
1614*5e7646d2SAndroid Build Coastguard Worker   * Load the most recent source for job data...
1615*5e7646d2SAndroid Build Coastguard Worker   */
1616*5e7646d2SAndroid Build Coastguard Worker 
1617*5e7646d2SAndroid Build Coastguard Worker   if (load_cache)
1618*5e7646d2SAndroid Build Coastguard Worker   {
1619*5e7646d2SAndroid Build Coastguard Worker    /*
1620*5e7646d2SAndroid Build Coastguard Worker     * Load the job.cache file...
1621*5e7646d2SAndroid Build Coastguard Worker     */
1622*5e7646d2SAndroid Build Coastguard Worker 
1623*5e7646d2SAndroid Build Coastguard Worker     load_job_cache(filename);
1624*5e7646d2SAndroid Build Coastguard Worker   }
1625*5e7646d2SAndroid Build Coastguard Worker   else
1626*5e7646d2SAndroid Build Coastguard Worker   {
1627*5e7646d2SAndroid Build Coastguard Worker    /*
1628*5e7646d2SAndroid Build Coastguard Worker     * Load the job history files...
1629*5e7646d2SAndroid Build Coastguard Worker     */
1630*5e7646d2SAndroid Build Coastguard Worker 
1631*5e7646d2SAndroid Build Coastguard Worker     load_request_root();
1632*5e7646d2SAndroid Build Coastguard Worker 
1633*5e7646d2SAndroid Build Coastguard Worker     load_next_job_id(filename);
1634*5e7646d2SAndroid Build Coastguard Worker   }
1635*5e7646d2SAndroid Build Coastguard Worker 
1636*5e7646d2SAndroid Build Coastguard Worker  /*
1637*5e7646d2SAndroid Build Coastguard Worker   * Clean out old jobs as needed...
1638*5e7646d2SAndroid Build Coastguard Worker   */
1639*5e7646d2SAndroid Build Coastguard Worker 
1640*5e7646d2SAndroid Build Coastguard Worker   if (MaxJobs > 0 && cupsArrayCount(Jobs) >= MaxJobs)
1641*5e7646d2SAndroid Build Coastguard Worker     cupsdCleanJobs();
1642*5e7646d2SAndroid Build Coastguard Worker }
1643*5e7646d2SAndroid Build Coastguard Worker 
1644*5e7646d2SAndroid Build Coastguard Worker 
1645*5e7646d2SAndroid Build Coastguard Worker /*
1646*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdLoadJob()' - Load a single job.
1647*5e7646d2SAndroid Build Coastguard Worker  */
1648*5e7646d2SAndroid Build Coastguard Worker 
1649*5e7646d2SAndroid Build Coastguard Worker int					/* O - 1 on success, 0 on failure */
cupsdLoadJob(cupsd_job_t * job)1650*5e7646d2SAndroid Build Coastguard Worker cupsdLoadJob(cupsd_job_t *job)		/* I - Job */
1651*5e7646d2SAndroid Build Coastguard Worker {
1652*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
1653*5e7646d2SAndroid Build Coastguard Worker   char			jobfile[1024];	/* Job filename */
1654*5e7646d2SAndroid Build Coastguard Worker   cups_file_t		*fp;		/* Job file */
1655*5e7646d2SAndroid Build Coastguard Worker   int			fileid;		/* Current file ID */
1656*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Job attribute */
1657*5e7646d2SAndroid Build Coastguard Worker   const char		*dest;		/* Destination name */
1658*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*destptr;	/* Pointer to destination */
1659*5e7646d2SAndroid Build Coastguard Worker   mime_type_t		**filetypes;	/* New filetypes array */
1660*5e7646d2SAndroid Build Coastguard Worker   int			*compressions;	/* New compressions array */
1661*5e7646d2SAndroid Build Coastguard Worker 
1662*5e7646d2SAndroid Build Coastguard Worker 
1663*5e7646d2SAndroid Build Coastguard Worker   if (job->attrs)
1664*5e7646d2SAndroid Build Coastguard Worker   {
1665*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value > IPP_JOB_STOPPED)
1666*5e7646d2SAndroid Build Coastguard Worker       job->access_time = time(NULL);
1667*5e7646d2SAndroid Build Coastguard Worker 
1668*5e7646d2SAndroid Build Coastguard Worker     return (1);
1669*5e7646d2SAndroid Build Coastguard Worker   }
1670*5e7646d2SAndroid Build Coastguard Worker 
1671*5e7646d2SAndroid Build Coastguard Worker   if ((job->attrs = ippNew()) == NULL)
1672*5e7646d2SAndroid Build Coastguard Worker   {
1673*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR, "Ran out of memory for job attributes.");
1674*5e7646d2SAndroid Build Coastguard Worker     return (0);
1675*5e7646d2SAndroid Build Coastguard Worker   }
1676*5e7646d2SAndroid Build Coastguard Worker 
1677*5e7646d2SAndroid Build Coastguard Worker  /*
1678*5e7646d2SAndroid Build Coastguard Worker   * Load job attributes...
1679*5e7646d2SAndroid Build Coastguard Worker   */
1680*5e7646d2SAndroid Build Coastguard Worker 
1681*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading attributes...");
1682*5e7646d2SAndroid Build Coastguard Worker 
1683*5e7646d2SAndroid Build Coastguard Worker   snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, job->id);
1684*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsdOpenConfFile(jobfile)) == NULL)
1685*5e7646d2SAndroid Build Coastguard Worker     goto error;
1686*5e7646d2SAndroid Build Coastguard Worker 
1687*5e7646d2SAndroid Build Coastguard Worker   if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL, job->attrs) != IPP_DATA)
1688*5e7646d2SAndroid Build Coastguard Worker   {
1689*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR,
1690*5e7646d2SAndroid Build Coastguard Worker 		"Unable to read job control file \"%s\".", jobfile);
1691*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(fp);
1692*5e7646d2SAndroid Build Coastguard Worker     goto error;
1693*5e7646d2SAndroid Build Coastguard Worker   }
1694*5e7646d2SAndroid Build Coastguard Worker 
1695*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
1696*5e7646d2SAndroid Build Coastguard Worker 
1697*5e7646d2SAndroid Build Coastguard Worker  /*
1698*5e7646d2SAndroid Build Coastguard Worker   * Copy attribute data to the job object...
1699*5e7646d2SAndroid Build Coastguard Worker   */
1700*5e7646d2SAndroid Build Coastguard Worker 
1701*5e7646d2SAndroid Build Coastguard Worker   if (!ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER))
1702*5e7646d2SAndroid Build Coastguard Worker   {
1703*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR,
1704*5e7646d2SAndroid Build Coastguard Worker 		"Missing or bad time-at-creation attribute in control file.");
1705*5e7646d2SAndroid Build Coastguard Worker     goto error;
1706*5e7646d2SAndroid Build Coastguard Worker   }
1707*5e7646d2SAndroid Build Coastguard Worker 
1708*5e7646d2SAndroid Build Coastguard Worker   if ((job->state = ippFindAttribute(job->attrs, "job-state",
1709*5e7646d2SAndroid Build Coastguard Worker                                      IPP_TAG_ENUM)) == NULL)
1710*5e7646d2SAndroid Build Coastguard Worker   {
1711*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR,
1712*5e7646d2SAndroid Build Coastguard Worker 		"Missing or bad job-state attribute in control file.");
1713*5e7646d2SAndroid Build Coastguard Worker     goto error;
1714*5e7646d2SAndroid Build Coastguard Worker   }
1715*5e7646d2SAndroid Build Coastguard Worker 
1716*5e7646d2SAndroid Build Coastguard Worker   job->state_value  = (ipp_jstate_t)job->state->values[0].integer;
1717*5e7646d2SAndroid Build Coastguard Worker   job->file_time    = 0;
1718*5e7646d2SAndroid Build Coastguard Worker   job->history_time = 0;
1719*5e7646d2SAndroid Build Coastguard Worker 
1720*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "time-at-creation", IPP_TAG_INTEGER)) != NULL)
1721*5e7646d2SAndroid Build Coastguard Worker     job->creation_time = attr->values[0].integer;
1722*5e7646d2SAndroid Build Coastguard Worker 
1723*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value >= IPP_JOB_CANCELED && (attr = ippFindAttribute(job->attrs, "time-at-completed", IPP_TAG_INTEGER)) != NULL)
1724*5e7646d2SAndroid Build Coastguard Worker   {
1725*5e7646d2SAndroid Build Coastguard Worker     job->completed_time = attr->values[0].integer;
1726*5e7646d2SAndroid Build Coastguard Worker 
1727*5e7646d2SAndroid Build Coastguard Worker     if (JobHistory < INT_MAX)
1728*5e7646d2SAndroid Build Coastguard Worker       job->history_time = job->completed_time + JobHistory;
1729*5e7646d2SAndroid Build Coastguard Worker     else
1730*5e7646d2SAndroid Build Coastguard Worker       job->history_time = INT_MAX;
1731*5e7646d2SAndroid Build Coastguard Worker 
1732*5e7646d2SAndroid Build Coastguard Worker     if (job->history_time < time(NULL))
1733*5e7646d2SAndroid Build Coastguard Worker       goto error;			/* Expired, remove from history */
1734*5e7646d2SAndroid Build Coastguard Worker 
1735*5e7646d2SAndroid Build Coastguard Worker     if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
1736*5e7646d2SAndroid Build Coastguard Worker       JobHistoryUpdate = job->history_time;
1737*5e7646d2SAndroid Build Coastguard Worker 
1738*5e7646d2SAndroid Build Coastguard Worker     if (JobFiles < INT_MAX)
1739*5e7646d2SAndroid Build Coastguard Worker       job->file_time = job->completed_time + JobFiles;
1740*5e7646d2SAndroid Build Coastguard Worker     else
1741*5e7646d2SAndroid Build Coastguard Worker       job->file_time = INT_MAX;
1742*5e7646d2SAndroid Build Coastguard Worker 
1743*5e7646d2SAndroid Build Coastguard Worker     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);
1744*5e7646d2SAndroid Build Coastguard Worker 
1745*5e7646d2SAndroid Build Coastguard Worker     if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
1746*5e7646d2SAndroid Build Coastguard Worker       JobHistoryUpdate = job->file_time;
1747*5e7646d2SAndroid Build Coastguard Worker 
1748*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdLoadJob: JobHistoryUpdate=%ld",
1749*5e7646d2SAndroid Build Coastguard Worker 		    (long)JobHistoryUpdate);
1750*5e7646d2SAndroid Build Coastguard Worker   }
1751*5e7646d2SAndroid Build Coastguard Worker 
1752*5e7646d2SAndroid Build Coastguard Worker   if (!job->dest)
1753*5e7646d2SAndroid Build Coastguard Worker   {
1754*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
1755*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_URI)) == NULL)
1756*5e7646d2SAndroid Build Coastguard Worker     {
1757*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_ERROR,
1758*5e7646d2SAndroid Build Coastguard Worker 		  "No job-printer-uri attribute in control file.");
1759*5e7646d2SAndroid Build Coastguard Worker       goto error;
1760*5e7646d2SAndroid Build Coastguard Worker     }
1761*5e7646d2SAndroid Build Coastguard Worker 
1762*5e7646d2SAndroid Build Coastguard Worker     if ((dest = cupsdValidateDest(attr->values[0].string.text, &(job->dtype),
1763*5e7646d2SAndroid Build Coastguard Worker                                   &destptr)) == NULL)
1764*5e7646d2SAndroid Build Coastguard Worker     {
1765*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_ERROR,
1766*5e7646d2SAndroid Build Coastguard Worker 		  "Unable to queue job for destination \"%s\".",
1767*5e7646d2SAndroid Build Coastguard Worker 		  attr->values[0].string.text);
1768*5e7646d2SAndroid Build Coastguard Worker       goto error;
1769*5e7646d2SAndroid Build Coastguard Worker     }
1770*5e7646d2SAndroid Build Coastguard Worker 
1771*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&job->dest, dest);
1772*5e7646d2SAndroid Build Coastguard Worker   }
1773*5e7646d2SAndroid Build Coastguard Worker   else if ((destptr = cupsdFindDest(job->dest)) == NULL)
1774*5e7646d2SAndroid Build Coastguard Worker   {
1775*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR,
1776*5e7646d2SAndroid Build Coastguard Worker 		"Unable to queue job for destination \"%s\".",
1777*5e7646d2SAndroid Build Coastguard Worker 		job->dest);
1778*5e7646d2SAndroid Build Coastguard Worker     goto error;
1779*5e7646d2SAndroid Build Coastguard Worker   }
1780*5e7646d2SAndroid Build Coastguard Worker 
1781*5e7646d2SAndroid Build Coastguard Worker   if ((job->reasons = ippFindAttribute(job->attrs, "job-state-reasons",
1782*5e7646d2SAndroid Build Coastguard Worker                                        IPP_TAG_KEYWORD)) == NULL)
1783*5e7646d2SAndroid Build Coastguard Worker   {
1784*5e7646d2SAndroid Build Coastguard Worker     const char	*reason;		/* job-state-reason keyword */
1785*5e7646d2SAndroid Build Coastguard Worker 
1786*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG,
1787*5e7646d2SAndroid Build Coastguard Worker 		"Adding missing job-state-reasons attribute to  control file.");
1788*5e7646d2SAndroid Build Coastguard Worker 
1789*5e7646d2SAndroid Build Coastguard Worker     switch (job->state_value)
1790*5e7646d2SAndroid Build Coastguard Worker     {
1791*5e7646d2SAndroid Build Coastguard Worker       default :
1792*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_PENDING :
1793*5e7646d2SAndroid Build Coastguard Worker           if (destptr->state == IPP_PRINTER_STOPPED)
1794*5e7646d2SAndroid Build Coastguard Worker             reason = "printer-stopped";
1795*5e7646d2SAndroid Build Coastguard Worker           else
1796*5e7646d2SAndroid Build Coastguard Worker             reason = "none";
1797*5e7646d2SAndroid Build Coastguard Worker           break;
1798*5e7646d2SAndroid Build Coastguard Worker 
1799*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_HELD :
1800*5e7646d2SAndroid Build Coastguard Worker           if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
1801*5e7646d2SAndroid Build Coastguard Worker                                        IPP_TAG_ZERO)) != NULL &&
1802*5e7646d2SAndroid Build Coastguard Worker               (attr->value_tag == IPP_TAG_NAME ||
1803*5e7646d2SAndroid Build Coastguard Worker 	       attr->value_tag == IPP_TAG_NAMELANG ||
1804*5e7646d2SAndroid Build Coastguard Worker 	       attr->value_tag == IPP_TAG_KEYWORD) &&
1805*5e7646d2SAndroid Build Coastguard Worker 	      strcmp(attr->values[0].string.text, "no-hold"))
1806*5e7646d2SAndroid Build Coastguard Worker 	    reason = "job-hold-until-specified";
1807*5e7646d2SAndroid Build Coastguard Worker 	  else
1808*5e7646d2SAndroid Build Coastguard Worker 	    reason = "job-incoming";
1809*5e7646d2SAndroid Build Coastguard Worker           break;
1810*5e7646d2SAndroid Build Coastguard Worker 
1811*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_PROCESSING :
1812*5e7646d2SAndroid Build Coastguard Worker           reason = "job-printing";
1813*5e7646d2SAndroid Build Coastguard Worker           break;
1814*5e7646d2SAndroid Build Coastguard Worker 
1815*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_STOPPED :
1816*5e7646d2SAndroid Build Coastguard Worker           reason = "job-stopped";
1817*5e7646d2SAndroid Build Coastguard Worker           break;
1818*5e7646d2SAndroid Build Coastguard Worker 
1819*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_CANCELED :
1820*5e7646d2SAndroid Build Coastguard Worker           reason = "job-canceled-by-user";
1821*5e7646d2SAndroid Build Coastguard Worker           break;
1822*5e7646d2SAndroid Build Coastguard Worker 
1823*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_ABORTED :
1824*5e7646d2SAndroid Build Coastguard Worker           reason = "aborted-by-system";
1825*5e7646d2SAndroid Build Coastguard Worker           break;
1826*5e7646d2SAndroid Build Coastguard Worker 
1827*5e7646d2SAndroid Build Coastguard Worker       case IPP_JOB_COMPLETED :
1828*5e7646d2SAndroid Build Coastguard Worker           reason = "job-completed-successfully";
1829*5e7646d2SAndroid Build Coastguard Worker           break;
1830*5e7646d2SAndroid Build Coastguard Worker     }
1831*5e7646d2SAndroid Build Coastguard Worker 
1832*5e7646d2SAndroid Build Coastguard Worker     job->reasons = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
1833*5e7646d2SAndroid Build Coastguard Worker                                 "job-state-reasons", NULL, reason);
1834*5e7646d2SAndroid Build Coastguard Worker   }
1835*5e7646d2SAndroid Build Coastguard Worker   else if (job->state_value == IPP_JOB_PENDING)
1836*5e7646d2SAndroid Build Coastguard Worker   {
1837*5e7646d2SAndroid Build Coastguard Worker     if (destptr->state == IPP_PRINTER_STOPPED)
1838*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &job->reasons, 0, "printer-stopped");
1839*5e7646d2SAndroid Build Coastguard Worker     else
1840*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &job->reasons, 0, "none");
1841*5e7646d2SAndroid Build Coastguard Worker   }
1842*5e7646d2SAndroid Build Coastguard Worker 
1843*5e7646d2SAndroid Build Coastguard Worker   job->impressions = ippFindAttribute(job->attrs, "job-impressions-completed", IPP_TAG_INTEGER);
1844*5e7646d2SAndroid Build Coastguard Worker   job->sheets      = ippFindAttribute(job->attrs, "job-media-sheets-completed", IPP_TAG_INTEGER);
1845*5e7646d2SAndroid Build Coastguard Worker   job->job_sheets  = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
1846*5e7646d2SAndroid Build Coastguard Worker 
1847*5e7646d2SAndroid Build Coastguard Worker   if (!job->impressions)
1848*5e7646d2SAndroid Build Coastguard Worker     job->impressions = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-impressions-completed", 0);
1849*5e7646d2SAndroid Build Coastguard Worker   if (!job->sheets)
1850*5e7646d2SAndroid Build Coastguard Worker     job->sheets = ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-media-sheets-completed", 0);
1851*5e7646d2SAndroid Build Coastguard Worker 
1852*5e7646d2SAndroid Build Coastguard Worker   if (!job->priority)
1853*5e7646d2SAndroid Build Coastguard Worker   {
1854*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-priority",
1855*5e7646d2SAndroid Build Coastguard Worker                         	 IPP_TAG_INTEGER)) == NULL)
1856*5e7646d2SAndroid Build Coastguard Worker     {
1857*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_ERROR,
1858*5e7646d2SAndroid Build Coastguard Worker 		  "Missing or bad job-priority attribute in control file.");
1859*5e7646d2SAndroid Build Coastguard Worker       goto error;
1860*5e7646d2SAndroid Build Coastguard Worker     }
1861*5e7646d2SAndroid Build Coastguard Worker 
1862*5e7646d2SAndroid Build Coastguard Worker     job->priority = attr->values[0].integer;
1863*5e7646d2SAndroid Build Coastguard Worker   }
1864*5e7646d2SAndroid Build Coastguard Worker 
1865*5e7646d2SAndroid Build Coastguard Worker   if (!job->username)
1866*5e7646d2SAndroid Build Coastguard Worker   {
1867*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name",
1868*5e7646d2SAndroid Build Coastguard Worker                         	 IPP_TAG_NAME)) == NULL)
1869*5e7646d2SAndroid Build Coastguard Worker     {
1870*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_ERROR,
1871*5e7646d2SAndroid Build Coastguard Worker 		  "Missing or bad job-originating-user-name "
1872*5e7646d2SAndroid Build Coastguard Worker 		  "attribute in control file.");
1873*5e7646d2SAndroid Build Coastguard Worker       goto error;
1874*5e7646d2SAndroid Build Coastguard Worker     }
1875*5e7646d2SAndroid Build Coastguard Worker 
1876*5e7646d2SAndroid Build Coastguard Worker     cupsdSetString(&job->username, attr->values[0].string.text);
1877*5e7646d2SAndroid Build Coastguard Worker   }
1878*5e7646d2SAndroid Build Coastguard Worker 
1879*5e7646d2SAndroid Build Coastguard Worker   if (!job->name)
1880*5e7646d2SAndroid Build Coastguard Worker   {
1881*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME)) != NULL)
1882*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&job->name, attr->values[0].string.text);
1883*5e7646d2SAndroid Build Coastguard Worker   }
1884*5e7646d2SAndroid Build Coastguard Worker 
1885*5e7646d2SAndroid Build Coastguard Worker  /*
1886*5e7646d2SAndroid Build Coastguard Worker   * Set the job hold-until time and state...
1887*5e7646d2SAndroid Build Coastguard Worker   */
1888*5e7646d2SAndroid Build Coastguard Worker 
1889*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value == IPP_JOB_HELD)
1890*5e7646d2SAndroid Build Coastguard Worker   {
1891*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
1892*5e7646d2SAndroid Build Coastguard Worker 	                         IPP_TAG_KEYWORD)) == NULL)
1893*5e7646d2SAndroid Build Coastguard Worker       attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
1894*5e7646d2SAndroid Build Coastguard Worker 
1895*5e7646d2SAndroid Build Coastguard Worker     if (attr)
1896*5e7646d2SAndroid Build Coastguard Worker       cupsdSetJobHoldUntil(job, attr->values[0].string.text, CUPSD_JOB_DEFAULT);
1897*5e7646d2SAndroid Build Coastguard Worker     else
1898*5e7646d2SAndroid Build Coastguard Worker     {
1899*5e7646d2SAndroid Build Coastguard Worker       job->state->values[0].integer = IPP_JOB_PENDING;
1900*5e7646d2SAndroid Build Coastguard Worker       job->state_value              = IPP_JOB_PENDING;
1901*5e7646d2SAndroid Build Coastguard Worker     }
1902*5e7646d2SAndroid Build Coastguard Worker   }
1903*5e7646d2SAndroid Build Coastguard Worker   else if (job->state_value == IPP_JOB_PROCESSING)
1904*5e7646d2SAndroid Build Coastguard Worker   {
1905*5e7646d2SAndroid Build Coastguard Worker     job->state->values[0].integer = IPP_JOB_PENDING;
1906*5e7646d2SAndroid Build Coastguard Worker     job->state_value              = IPP_JOB_PENDING;
1907*5e7646d2SAndroid Build Coastguard Worker   }
1908*5e7646d2SAndroid Build Coastguard Worker 
1909*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL)
1910*5e7646d2SAndroid Build Coastguard Worker     job->koctets = attr->values[0].integer;
1911*5e7646d2SAndroid Build Coastguard Worker 
1912*5e7646d2SAndroid Build Coastguard Worker   if (!job->num_files)
1913*5e7646d2SAndroid Build Coastguard Worker   {
1914*5e7646d2SAndroid Build Coastguard Worker    /*
1915*5e7646d2SAndroid Build Coastguard Worker     * Find all the d##### files...
1916*5e7646d2SAndroid Build Coastguard Worker     */
1917*5e7646d2SAndroid Build Coastguard Worker 
1918*5e7646d2SAndroid Build Coastguard Worker     for (fileid = 1; fileid < 10000; fileid ++)
1919*5e7646d2SAndroid Build Coastguard Worker     {
1920*5e7646d2SAndroid Build Coastguard Worker       snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot,
1921*5e7646d2SAndroid Build Coastguard Worker                job->id, fileid);
1922*5e7646d2SAndroid Build Coastguard Worker 
1923*5e7646d2SAndroid Build Coastguard Worker       if (access(jobfile, 0))
1924*5e7646d2SAndroid Build Coastguard Worker         break;
1925*5e7646d2SAndroid Build Coastguard Worker 
1926*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG,
1927*5e7646d2SAndroid Build Coastguard Worker 		  "Auto-typing document file \"%s\"...", jobfile);
1928*5e7646d2SAndroid Build Coastguard Worker 
1929*5e7646d2SAndroid Build Coastguard Worker       if (fileid > job->num_files)
1930*5e7646d2SAndroid Build Coastguard Worker       {
1931*5e7646d2SAndroid Build Coastguard Worker         if (job->num_files == 0)
1932*5e7646d2SAndroid Build Coastguard Worker 	{
1933*5e7646d2SAndroid Build Coastguard Worker 	  compressions = (int *)calloc((size_t)fileid, sizeof(int));
1934*5e7646d2SAndroid Build Coastguard Worker 	  filetypes    = (mime_type_t **)calloc((size_t)fileid, sizeof(mime_type_t *));
1935*5e7646d2SAndroid Build Coastguard Worker 	}
1936*5e7646d2SAndroid Build Coastguard Worker 	else
1937*5e7646d2SAndroid Build Coastguard Worker 	{
1938*5e7646d2SAndroid Build Coastguard Worker 	  compressions = (int *)realloc(job->compressions, sizeof(int) * (size_t)fileid);
1939*5e7646d2SAndroid Build Coastguard Worker 	  filetypes    = (mime_type_t **)realloc(job->filetypes, sizeof(mime_type_t *) * (size_t)fileid);
1940*5e7646d2SAndroid Build Coastguard Worker         }
1941*5e7646d2SAndroid Build Coastguard Worker 
1942*5e7646d2SAndroid Build Coastguard Worker 	if (compressions)
1943*5e7646d2SAndroid Build Coastguard Worker 	  job->compressions = compressions;
1944*5e7646d2SAndroid Build Coastguard Worker 
1945*5e7646d2SAndroid Build Coastguard Worker 	if (filetypes)
1946*5e7646d2SAndroid Build Coastguard Worker 	  job->filetypes = filetypes;
1947*5e7646d2SAndroid Build Coastguard Worker 
1948*5e7646d2SAndroid Build Coastguard Worker         if (!compressions || !filetypes)
1949*5e7646d2SAndroid Build Coastguard Worker 	{
1950*5e7646d2SAndroid Build Coastguard Worker           cupsdLogJob(job, CUPSD_LOG_ERROR,
1951*5e7646d2SAndroid Build Coastguard Worker 		      "Ran out of memory for job file types.");
1952*5e7646d2SAndroid Build Coastguard Worker 
1953*5e7646d2SAndroid Build Coastguard Worker 	  ippDelete(job->attrs);
1954*5e7646d2SAndroid Build Coastguard Worker 	  job->attrs = NULL;
1955*5e7646d2SAndroid Build Coastguard Worker 
1956*5e7646d2SAndroid Build Coastguard Worker 	  if (job->compressions)
1957*5e7646d2SAndroid Build Coastguard Worker 	  {
1958*5e7646d2SAndroid Build Coastguard Worker 	    free(job->compressions);
1959*5e7646d2SAndroid Build Coastguard Worker 	    job->compressions = NULL;
1960*5e7646d2SAndroid Build Coastguard Worker 	  }
1961*5e7646d2SAndroid Build Coastguard Worker 
1962*5e7646d2SAndroid Build Coastguard Worker 	  if (job->filetypes)
1963*5e7646d2SAndroid Build Coastguard Worker 	  {
1964*5e7646d2SAndroid Build Coastguard Worker 	    free(job->filetypes);
1965*5e7646d2SAndroid Build Coastguard Worker 	    job->filetypes = NULL;
1966*5e7646d2SAndroid Build Coastguard Worker 	  }
1967*5e7646d2SAndroid Build Coastguard Worker 
1968*5e7646d2SAndroid Build Coastguard Worker 	  job->num_files = 0;
1969*5e7646d2SAndroid Build Coastguard Worker 	  return (0);
1970*5e7646d2SAndroid Build Coastguard Worker 	}
1971*5e7646d2SAndroid Build Coastguard Worker 
1972*5e7646d2SAndroid Build Coastguard Worker 	job->num_files = fileid;
1973*5e7646d2SAndroid Build Coastguard Worker       }
1974*5e7646d2SAndroid Build Coastguard Worker 
1975*5e7646d2SAndroid Build Coastguard Worker       job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, jobfile, NULL,
1976*5e7646d2SAndroid Build Coastguard Worker                                                 job->compressions + fileid - 1);
1977*5e7646d2SAndroid Build Coastguard Worker 
1978*5e7646d2SAndroid Build Coastguard Worker       if (!job->filetypes[fileid - 1])
1979*5e7646d2SAndroid Build Coastguard Worker         job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application",
1980*5e7646d2SAndroid Build Coastguard Worker 	                                      "vnd.cups-raw");
1981*5e7646d2SAndroid Build Coastguard Worker     }
1982*5e7646d2SAndroid Build Coastguard Worker   }
1983*5e7646d2SAndroid Build Coastguard Worker 
1984*5e7646d2SAndroid Build Coastguard Worker  /*
1985*5e7646d2SAndroid Build Coastguard Worker   * Load authentication information as needed...
1986*5e7646d2SAndroid Build Coastguard Worker   */
1987*5e7646d2SAndroid Build Coastguard Worker 
1988*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value < IPP_JOB_STOPPED)
1989*5e7646d2SAndroid Build Coastguard Worker   {
1990*5e7646d2SAndroid Build Coastguard Worker     snprintf(jobfile, sizeof(jobfile), "%s/a%05d", RequestRoot, job->id);
1991*5e7646d2SAndroid Build Coastguard Worker 
1992*5e7646d2SAndroid Build Coastguard Worker     for (i = 0;
1993*5e7646d2SAndroid Build Coastguard Worker 	 i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
1994*5e7646d2SAndroid Build Coastguard Worker 	 i ++)
1995*5e7646d2SAndroid Build Coastguard Worker       cupsdClearString(job->auth_env + i);
1996*5e7646d2SAndroid Build Coastguard Worker     cupsdClearString(&job->auth_uid);
1997*5e7646d2SAndroid Build Coastguard Worker 
1998*5e7646d2SAndroid Build Coastguard Worker     if ((fp = cupsFileOpen(jobfile, "r")) != NULL)
1999*5e7646d2SAndroid Build Coastguard Worker     {
2000*5e7646d2SAndroid Build Coastguard Worker       int	bytes,			/* Size of auth data */
2001*5e7646d2SAndroid Build Coastguard Worker 		linenum = 1;		/* Current line number */
2002*5e7646d2SAndroid Build Coastguard Worker       char	line[65536],		/* Line from file */
2003*5e7646d2SAndroid Build Coastguard Worker 		*value,			/* Value from line */
2004*5e7646d2SAndroid Build Coastguard Worker 		data[65536];		/* Decoded data */
2005*5e7646d2SAndroid Build Coastguard Worker 
2006*5e7646d2SAndroid Build Coastguard Worker 
2007*5e7646d2SAndroid Build Coastguard Worker       if (cupsFileGets(fp, line, sizeof(line)) &&
2008*5e7646d2SAndroid Build Coastguard Worker           !strcmp(line, "CUPSD-AUTH-V3"))
2009*5e7646d2SAndroid Build Coastguard Worker       {
2010*5e7646d2SAndroid Build Coastguard Worker         i = 0;
2011*5e7646d2SAndroid Build Coastguard Worker         while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
2012*5e7646d2SAndroid Build Coastguard Worker         {
2013*5e7646d2SAndroid Build Coastguard Worker          /*
2014*5e7646d2SAndroid Build Coastguard Worker           * Decode value...
2015*5e7646d2SAndroid Build Coastguard Worker           */
2016*5e7646d2SAndroid Build Coastguard Worker 
2017*5e7646d2SAndroid Build Coastguard Worker           if (strcmp(line, "negotiate") && strcmp(line, "uid"))
2018*5e7646d2SAndroid Build Coastguard Worker           {
2019*5e7646d2SAndroid Build Coastguard Worker 	    bytes = sizeof(data);
2020*5e7646d2SAndroid Build Coastguard Worker 	    httpDecode64_2(data, &bytes, value);
2021*5e7646d2SAndroid Build Coastguard Worker 	  }
2022*5e7646d2SAndroid Build Coastguard Worker 
2023*5e7646d2SAndroid Build Coastguard Worker          /*
2024*5e7646d2SAndroid Build Coastguard Worker           * Assign environment variables...
2025*5e7646d2SAndroid Build Coastguard Worker           */
2026*5e7646d2SAndroid Build Coastguard Worker 
2027*5e7646d2SAndroid Build Coastguard Worker           if (!strcmp(line, "uid"))
2028*5e7646d2SAndroid Build Coastguard Worker           {
2029*5e7646d2SAndroid Build Coastguard Worker             cupsdSetStringf(&job->auth_uid, "AUTH_UID=%s", value);
2030*5e7646d2SAndroid Build Coastguard Worker             continue;
2031*5e7646d2SAndroid Build Coastguard Worker           }
2032*5e7646d2SAndroid Build Coastguard Worker           else if (i >= (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0])))
2033*5e7646d2SAndroid Build Coastguard Worker             break;
2034*5e7646d2SAndroid Build Coastguard Worker 
2035*5e7646d2SAndroid Build Coastguard Worker 	  if (!strcmp(line, "username"))
2036*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSetStringf(job->auth_env + i, "AUTH_USERNAME=%s", data);
2037*5e7646d2SAndroid Build Coastguard Worker 	  else if (!strcmp(line, "domain"))
2038*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSetStringf(job->auth_env + i, "AUTH_DOMAIN=%s", data);
2039*5e7646d2SAndroid Build Coastguard Worker 	  else if (!strcmp(line, "password"))
2040*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSetStringf(job->auth_env + i, "AUTH_PASSWORD=%s", data);
2041*5e7646d2SAndroid Build Coastguard Worker 	  else if (!strcmp(line, "negotiate"))
2042*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSetStringf(job->auth_env + i, "AUTH_NEGOTIATE=%s", value);
2043*5e7646d2SAndroid Build Coastguard Worker 	  else
2044*5e7646d2SAndroid Build Coastguard Worker 	    continue;
2045*5e7646d2SAndroid Build Coastguard Worker 
2046*5e7646d2SAndroid Build Coastguard Worker 	  i ++;
2047*5e7646d2SAndroid Build Coastguard Worker 	}
2048*5e7646d2SAndroid Build Coastguard Worker       }
2049*5e7646d2SAndroid Build Coastguard Worker 
2050*5e7646d2SAndroid Build Coastguard Worker       cupsFileClose(fp);
2051*5e7646d2SAndroid Build Coastguard Worker     }
2052*5e7646d2SAndroid Build Coastguard Worker   }
2053*5e7646d2SAndroid Build Coastguard Worker 
2054*5e7646d2SAndroid Build Coastguard Worker   job->access_time = time(NULL);
2055*5e7646d2SAndroid Build Coastguard Worker   return (1);
2056*5e7646d2SAndroid Build Coastguard Worker 
2057*5e7646d2SAndroid Build Coastguard Worker  /*
2058*5e7646d2SAndroid Build Coastguard Worker   * If we get here then something bad happened...
2059*5e7646d2SAndroid Build Coastguard Worker   */
2060*5e7646d2SAndroid Build Coastguard Worker 
2061*5e7646d2SAndroid Build Coastguard Worker   error:
2062*5e7646d2SAndroid Build Coastguard Worker 
2063*5e7646d2SAndroid Build Coastguard Worker   ippDelete(job->attrs);
2064*5e7646d2SAndroid Build Coastguard Worker   job->attrs = NULL;
2065*5e7646d2SAndroid Build Coastguard Worker 
2066*5e7646d2SAndroid Build Coastguard Worker   remove_job_history(job);
2067*5e7646d2SAndroid Build Coastguard Worker   remove_job_files(job);
2068*5e7646d2SAndroid Build Coastguard Worker 
2069*5e7646d2SAndroid Build Coastguard Worker   return (0);
2070*5e7646d2SAndroid Build Coastguard Worker }
2071*5e7646d2SAndroid Build Coastguard Worker 
2072*5e7646d2SAndroid Build Coastguard Worker 
2073*5e7646d2SAndroid Build Coastguard Worker /*
2074*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdMoveJob()' - Move the specified job to a different destination.
2075*5e7646d2SAndroid Build Coastguard Worker  */
2076*5e7646d2SAndroid Build Coastguard Worker 
2077*5e7646d2SAndroid Build Coastguard Worker void
cupsdMoveJob(cupsd_job_t * job,cupsd_printer_t * p)2078*5e7646d2SAndroid Build Coastguard Worker cupsdMoveJob(cupsd_job_t     *job,	/* I - Job */
2079*5e7646d2SAndroid Build Coastguard Worker              cupsd_printer_t *p)	/* I - Destination printer or class */
2080*5e7646d2SAndroid Build Coastguard Worker {
2081*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* job-printer-uri attribute */
2082*5e7646d2SAndroid Build Coastguard Worker   const char		*olddest;	/* Old destination */
2083*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*oldp;		/* Old pointer */
2084*5e7646d2SAndroid Build Coastguard Worker 
2085*5e7646d2SAndroid Build Coastguard Worker 
2086*5e7646d2SAndroid Build Coastguard Worker  /*
2087*5e7646d2SAndroid Build Coastguard Worker   * Don't move completed jobs...
2088*5e7646d2SAndroid Build Coastguard Worker   */
2089*5e7646d2SAndroid Build Coastguard Worker 
2090*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value > IPP_JOB_STOPPED)
2091*5e7646d2SAndroid Build Coastguard Worker     return;
2092*5e7646d2SAndroid Build Coastguard Worker 
2093*5e7646d2SAndroid Build Coastguard Worker  /*
2094*5e7646d2SAndroid Build Coastguard Worker   * Get the old destination...
2095*5e7646d2SAndroid Build Coastguard Worker   */
2096*5e7646d2SAndroid Build Coastguard Worker 
2097*5e7646d2SAndroid Build Coastguard Worker   olddest = job->dest;
2098*5e7646d2SAndroid Build Coastguard Worker 
2099*5e7646d2SAndroid Build Coastguard Worker   if (job->printer)
2100*5e7646d2SAndroid Build Coastguard Worker     oldp = job->printer;
2101*5e7646d2SAndroid Build Coastguard Worker   else
2102*5e7646d2SAndroid Build Coastguard Worker     oldp = cupsdFindDest(olddest);
2103*5e7646d2SAndroid Build Coastguard Worker 
2104*5e7646d2SAndroid Build Coastguard Worker  /*
2105*5e7646d2SAndroid Build Coastguard Worker   * Change the destination information...
2106*5e7646d2SAndroid Build Coastguard Worker   */
2107*5e7646d2SAndroid Build Coastguard Worker 
2108*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value > IPP_JOB_HELD)
2109*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
2110*5e7646d2SAndroid Build Coastguard Worker 		     "Stopping job prior to move.");
2111*5e7646d2SAndroid Build Coastguard Worker 
2112*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_JOB_CONFIG_CHANGED, oldp, job,
2113*5e7646d2SAndroid Build Coastguard Worker                 "Job #%d moved from %s to %s.", job->id, olddest,
2114*5e7646d2SAndroid Build Coastguard Worker 		p->name);
2115*5e7646d2SAndroid Build Coastguard Worker 
2116*5e7646d2SAndroid Build Coastguard Worker   cupsdSetString(&job->dest, p->name);
2117*5e7646d2SAndroid Build Coastguard Worker   job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
2118*5e7646d2SAndroid Build Coastguard Worker 
2119*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-printer-uri",
2120*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_URI)) != NULL)
2121*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &attr, 0, p->uri);
2122*5e7646d2SAndroid Build Coastguard Worker 
2123*5e7646d2SAndroid Build Coastguard Worker   cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, p, job,
2124*5e7646d2SAndroid Build Coastguard Worker                 "Job #%d moved from %s to %s.", job->id, olddest,
2125*5e7646d2SAndroid Build Coastguard Worker 		p->name);
2126*5e7646d2SAndroid Build Coastguard Worker 
2127*5e7646d2SAndroid Build Coastguard Worker   job->dirty = 1;
2128*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
2129*5e7646d2SAndroid Build Coastguard Worker }
2130*5e7646d2SAndroid Build Coastguard Worker 
2131*5e7646d2SAndroid Build Coastguard Worker 
2132*5e7646d2SAndroid Build Coastguard Worker /*
2133*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdReleaseJob()' - Release the specified job.
2134*5e7646d2SAndroid Build Coastguard Worker  */
2135*5e7646d2SAndroid Build Coastguard Worker 
2136*5e7646d2SAndroid Build Coastguard Worker void
cupsdReleaseJob(cupsd_job_t * job)2137*5e7646d2SAndroid Build Coastguard Worker cupsdReleaseJob(cupsd_job_t *job)	/* I - Job */
2138*5e7646d2SAndroid Build Coastguard Worker {
2139*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReleaseJob(job=%p(%d))", job,
2140*5e7646d2SAndroid Build Coastguard Worker                   job->id);
2141*5e7646d2SAndroid Build Coastguard Worker 
2142*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value == IPP_JOB_HELD)
2143*5e7646d2SAndroid Build Coastguard Worker   {
2144*5e7646d2SAndroid Build Coastguard Worker    /*
2145*5e7646d2SAndroid Build Coastguard Worker     * Add trailing banner as needed...
2146*5e7646d2SAndroid Build Coastguard Worker     */
2147*5e7646d2SAndroid Build Coastguard Worker 
2148*5e7646d2SAndroid Build Coastguard Worker     if (job->pending_timeout)
2149*5e7646d2SAndroid Build Coastguard Worker       cupsdTimeoutJob(job);
2150*5e7646d2SAndroid Build Coastguard Worker 
2151*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
2152*5e7646d2SAndroid Build Coastguard Worker                      "Job released by user.");
2153*5e7646d2SAndroid Build Coastguard Worker   }
2154*5e7646d2SAndroid Build Coastguard Worker }
2155*5e7646d2SAndroid Build Coastguard Worker 
2156*5e7646d2SAndroid Build Coastguard Worker 
2157*5e7646d2SAndroid Build Coastguard Worker /*
2158*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdRestartJob()' - Restart the specified job.
2159*5e7646d2SAndroid Build Coastguard Worker  */
2160*5e7646d2SAndroid Build Coastguard Worker 
2161*5e7646d2SAndroid Build Coastguard Worker void
cupsdRestartJob(cupsd_job_t * job)2162*5e7646d2SAndroid Build Coastguard Worker cupsdRestartJob(cupsd_job_t *job)	/* I - Job */
2163*5e7646d2SAndroid Build Coastguard Worker {
2164*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdRestartJob(job=%p(%d))", job,
2165*5e7646d2SAndroid Build Coastguard Worker                   job->id);
2166*5e7646d2SAndroid Build Coastguard Worker 
2167*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value == IPP_JOB_STOPPED || job->num_files)
2168*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_PENDING, CUPSD_JOB_DEFAULT,
2169*5e7646d2SAndroid Build Coastguard Worker                      "Job restarted by user.");
2170*5e7646d2SAndroid Build Coastguard Worker }
2171*5e7646d2SAndroid Build Coastguard Worker 
2172*5e7646d2SAndroid Build Coastguard Worker 
2173*5e7646d2SAndroid Build Coastguard Worker /*
2174*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSaveAllJobs()' - Save a summary of all jobs to disk.
2175*5e7646d2SAndroid Build Coastguard Worker  */
2176*5e7646d2SAndroid Build Coastguard Worker 
2177*5e7646d2SAndroid Build Coastguard Worker void
cupsdSaveAllJobs(void)2178*5e7646d2SAndroid Build Coastguard Worker cupsdSaveAllJobs(void)
2179*5e7646d2SAndroid Build Coastguard Worker {
2180*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
2181*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*fp;			/* job.cache file */
2182*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024];		/* job.cache filename */
2183*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
2184*5e7646d2SAndroid Build Coastguard Worker 
2185*5e7646d2SAndroid Build Coastguard Worker 
2186*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/job.cache", CacheDir);
2187*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm)) == NULL)
2188*5e7646d2SAndroid Build Coastguard Worker     return;
2189*5e7646d2SAndroid Build Coastguard Worker 
2190*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_INFO, "Saving job.cache...");
2191*5e7646d2SAndroid Build Coastguard Worker 
2192*5e7646d2SAndroid Build Coastguard Worker  /*
2193*5e7646d2SAndroid Build Coastguard Worker   * Write a small header to the file...
2194*5e7646d2SAndroid Build Coastguard Worker   */
2195*5e7646d2SAndroid Build Coastguard Worker 
2196*5e7646d2SAndroid Build Coastguard Worker   cupsFilePuts(fp, "# Job cache file for " CUPS_SVERSION "\n");
2197*5e7646d2SAndroid Build Coastguard Worker   cupsFilePrintf(fp, "# Written by cupsd\n");
2198*5e7646d2SAndroid Build Coastguard Worker   cupsFilePrintf(fp, "NextJobId %d\n", NextJobId);
2199*5e7646d2SAndroid Build Coastguard Worker 
2200*5e7646d2SAndroid Build Coastguard Worker  /*
2201*5e7646d2SAndroid Build Coastguard Worker   * Write each job known to the system...
2202*5e7646d2SAndroid Build Coastguard Worker   */
2203*5e7646d2SAndroid Build Coastguard Worker 
2204*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
2205*5e7646d2SAndroid Build Coastguard Worker        job;
2206*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(Jobs))
2207*5e7646d2SAndroid Build Coastguard Worker   {
2208*5e7646d2SAndroid Build Coastguard Worker     if (job->printer && job->printer->temporary)
2209*5e7646d2SAndroid Build Coastguard Worker     {
2210*5e7646d2SAndroid Build Coastguard Worker      /*
2211*5e7646d2SAndroid Build Coastguard Worker       * Don't save jobs on temporary printers...
2212*5e7646d2SAndroid Build Coastguard Worker       */
2213*5e7646d2SAndroid Build Coastguard Worker 
2214*5e7646d2SAndroid Build Coastguard Worker       continue;
2215*5e7646d2SAndroid Build Coastguard Worker     }
2216*5e7646d2SAndroid Build Coastguard Worker 
2217*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "<Job %d>\n", job->id);
2218*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "State %d\n", job->state_value);
2219*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "Created %ld\n", (long)job->creation_time);
2220*5e7646d2SAndroid Build Coastguard Worker     if (job->completed_time)
2221*5e7646d2SAndroid Build Coastguard Worker       cupsFilePrintf(fp, "Completed %ld\n", (long)job->completed_time);
2222*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "Priority %d\n", job->priority);
2223*5e7646d2SAndroid Build Coastguard Worker     if (job->hold_until)
2224*5e7646d2SAndroid Build Coastguard Worker       cupsFilePrintf(fp, "HoldUntil %ld\n", (long)job->hold_until);
2225*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "Username %s\n", job->username);
2226*5e7646d2SAndroid Build Coastguard Worker     if (job->name)
2227*5e7646d2SAndroid Build Coastguard Worker       cupsFilePutConf(fp, "Name", job->name);
2228*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "Destination %s\n", job->dest);
2229*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "DestType %d\n", job->dtype);
2230*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "KOctets %d\n", job->koctets);
2231*5e7646d2SAndroid Build Coastguard Worker     cupsFilePrintf(fp, "NumFiles %d\n", job->num_files);
2232*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < job->num_files; i ++)
2233*5e7646d2SAndroid Build Coastguard Worker       cupsFilePrintf(fp, "File %d %s/%s %d\n", i + 1, job->filetypes[i]->super,
2234*5e7646d2SAndroid Build Coastguard Worker                      job->filetypes[i]->type, job->compressions[i]);
2235*5e7646d2SAndroid Build Coastguard Worker     cupsFilePuts(fp, "</Job>\n");
2236*5e7646d2SAndroid Build Coastguard Worker   }
2237*5e7646d2SAndroid Build Coastguard Worker 
2238*5e7646d2SAndroid Build Coastguard Worker   cupsdCloseCreatedConfFile(fp, filename);
2239*5e7646d2SAndroid Build Coastguard Worker }
2240*5e7646d2SAndroid Build Coastguard Worker 
2241*5e7646d2SAndroid Build Coastguard Worker 
2242*5e7646d2SAndroid Build Coastguard Worker /*
2243*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSaveJob()' - Save a job to disk.
2244*5e7646d2SAndroid Build Coastguard Worker  */
2245*5e7646d2SAndroid Build Coastguard Worker 
2246*5e7646d2SAndroid Build Coastguard Worker void
cupsdSaveJob(cupsd_job_t * job)2247*5e7646d2SAndroid Build Coastguard Worker cupsdSaveJob(cupsd_job_t *job)		/* I - Job */
2248*5e7646d2SAndroid Build Coastguard Worker {
2249*5e7646d2SAndroid Build Coastguard Worker   char		filename[1024];		/* Job control filename */
2250*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*fp;			/* Job file */
2251*5e7646d2SAndroid Build Coastguard Worker 
2252*5e7646d2SAndroid Build Coastguard Worker 
2253*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob(job=%p(%d)): job->attrs=%p",
2254*5e7646d2SAndroid Build Coastguard Worker                   job, job->id, job->attrs);
2255*5e7646d2SAndroid Build Coastguard Worker 
2256*5e7646d2SAndroid Build Coastguard Worker   if (job->printer && job->printer->temporary)
2257*5e7646d2SAndroid Build Coastguard Worker   {
2258*5e7646d2SAndroid Build Coastguard Worker    /*
2259*5e7646d2SAndroid Build Coastguard Worker     * Don't save jobs on temporary printers...
2260*5e7646d2SAndroid Build Coastguard Worker     */
2261*5e7646d2SAndroid Build Coastguard Worker 
2262*5e7646d2SAndroid Build Coastguard Worker     job->dirty = 0;
2263*5e7646d2SAndroid Build Coastguard Worker     return;
2264*5e7646d2SAndroid Build Coastguard Worker   }
2265*5e7646d2SAndroid Build Coastguard Worker 
2266*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id);
2267*5e7646d2SAndroid Build Coastguard Worker 
2268*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL)
2269*5e7646d2SAndroid Build Coastguard Worker     return;
2270*5e7646d2SAndroid Build Coastguard Worker 
2271*5e7646d2SAndroid Build Coastguard Worker   fchown(cupsFileNumber(fp), RunUser, Group);
2272*5e7646d2SAndroid Build Coastguard Worker 
2273*5e7646d2SAndroid Build Coastguard Worker   job->attrs->state = IPP_IDLE;
2274*5e7646d2SAndroid Build Coastguard Worker 
2275*5e7646d2SAndroid Build Coastguard Worker   if (ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL,
2276*5e7646d2SAndroid Build Coastguard Worker                  job->attrs) != IPP_DATA)
2277*5e7646d2SAndroid Build Coastguard Worker   {
2278*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_ERROR, "Unable to write job control file.");
2279*5e7646d2SAndroid Build Coastguard Worker     cupsFileClose(fp);
2280*5e7646d2SAndroid Build Coastguard Worker     return;
2281*5e7646d2SAndroid Build Coastguard Worker   }
2282*5e7646d2SAndroid Build Coastguard Worker 
2283*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdCloseCreatedConfFile(fp, filename))
2284*5e7646d2SAndroid Build Coastguard Worker   {
2285*5e7646d2SAndroid Build Coastguard Worker    /*
2286*5e7646d2SAndroid Build Coastguard Worker     * Remove backup file and mark this job as clean...
2287*5e7646d2SAndroid Build Coastguard Worker     */
2288*5e7646d2SAndroid Build Coastguard Worker 
2289*5e7646d2SAndroid Build Coastguard Worker     strlcat(filename, ".O", sizeof(filename));
2290*5e7646d2SAndroid Build Coastguard Worker     unlink(filename);
2291*5e7646d2SAndroid Build Coastguard Worker 
2292*5e7646d2SAndroid Build Coastguard Worker     job->dirty = 0;
2293*5e7646d2SAndroid Build Coastguard Worker   }
2294*5e7646d2SAndroid Build Coastguard Worker }
2295*5e7646d2SAndroid Build Coastguard Worker 
2296*5e7646d2SAndroid Build Coastguard Worker 
2297*5e7646d2SAndroid Build Coastguard Worker /*
2298*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSetJobHoldUntil()' - Set the hold time for a job.
2299*5e7646d2SAndroid Build Coastguard Worker  */
2300*5e7646d2SAndroid Build Coastguard Worker 
2301*5e7646d2SAndroid Build Coastguard Worker void
cupsdSetJobHoldUntil(cupsd_job_t * job,const char * when,int update)2302*5e7646d2SAndroid Build Coastguard Worker cupsdSetJobHoldUntil(cupsd_job_t *job,	/* I - Job */
2303*5e7646d2SAndroid Build Coastguard Worker                      const char  *when,	/* I - When to resume */
2304*5e7646d2SAndroid Build Coastguard Worker 		     int         update)/* I - Update job-hold-until attr? */
2305*5e7646d2SAndroid Build Coastguard Worker {
2306*5e7646d2SAndroid Build Coastguard Worker   time_t	curtime;		/* Current time */
2307*5e7646d2SAndroid Build Coastguard Worker   struct tm	curdate;		/* Current date */
2308*5e7646d2SAndroid Build Coastguard Worker   int		hour;			/* Hold hour */
2309*5e7646d2SAndroid Build Coastguard Worker   int		minute;			/* Hold minute */
2310*5e7646d2SAndroid Build Coastguard Worker   int		second = 0;		/* Hold second */
2311*5e7646d2SAndroid Build Coastguard Worker 
2312*5e7646d2SAndroid Build Coastguard Worker 
2313*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
2314*5e7646d2SAndroid Build Coastguard Worker                   "cupsdSetJobHoldUntil(job=%p(%d), when=\"%s\", update=%d)",
2315*5e7646d2SAndroid Build Coastguard Worker                   job, job->id, when, update);
2316*5e7646d2SAndroid Build Coastguard Worker 
2317*5e7646d2SAndroid Build Coastguard Worker   if (update)
2318*5e7646d2SAndroid Build Coastguard Worker   {
2319*5e7646d2SAndroid Build Coastguard Worker    /*
2320*5e7646d2SAndroid Build Coastguard Worker     * Update the job-hold-until attribute...
2321*5e7646d2SAndroid Build Coastguard Worker     */
2322*5e7646d2SAndroid Build Coastguard Worker 
2323*5e7646d2SAndroid Build Coastguard Worker     ipp_attribute_t *attr;		/* job-hold-until attribute */
2324*5e7646d2SAndroid Build Coastguard Worker 
2325*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
2326*5e7646d2SAndroid Build Coastguard Worker 				 IPP_TAG_KEYWORD)) == NULL)
2327*5e7646d2SAndroid Build Coastguard Worker       attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
2328*5e7646d2SAndroid Build Coastguard Worker 
2329*5e7646d2SAndroid Build Coastguard Worker     if (attr)
2330*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &attr, 0, when);
2331*5e7646d2SAndroid Build Coastguard Worker     else
2332*5e7646d2SAndroid Build Coastguard Worker       attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
2333*5e7646d2SAndroid Build Coastguard Worker                           "job-hold-until", NULL, when);
2334*5e7646d2SAndroid Build Coastguard Worker 
2335*5e7646d2SAndroid Build Coastguard Worker     if (attr)
2336*5e7646d2SAndroid Build Coastguard Worker     {
2337*5e7646d2SAndroid Build Coastguard Worker       if (isdigit(when[0] & 255))
2338*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag = IPP_TAG_NAME;
2339*5e7646d2SAndroid Build Coastguard Worker       else
2340*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag = IPP_TAG_KEYWORD;
2341*5e7646d2SAndroid Build Coastguard Worker 
2342*5e7646d2SAndroid Build Coastguard Worker       job->dirty = 1;
2343*5e7646d2SAndroid Build Coastguard Worker       cupsdMarkDirty(CUPSD_DIRTY_JOBS);
2344*5e7646d2SAndroid Build Coastguard Worker     }
2345*5e7646d2SAndroid Build Coastguard Worker 
2346*5e7646d2SAndroid Build Coastguard Worker   }
2347*5e7646d2SAndroid Build Coastguard Worker 
2348*5e7646d2SAndroid Build Coastguard Worker   if (strcmp(when, "no-hold"))
2349*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "job-hold-until-specified");
2350*5e7646d2SAndroid Build Coastguard Worker   else
2351*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "none");
2352*5e7646d2SAndroid Build Coastguard Worker 
2353*5e7646d2SAndroid Build Coastguard Worker  /*
2354*5e7646d2SAndroid Build Coastguard Worker   * Update the hold time...
2355*5e7646d2SAndroid Build Coastguard Worker   */
2356*5e7646d2SAndroid Build Coastguard Worker 
2357*5e7646d2SAndroid Build Coastguard Worker   job->cancel_time = 0;
2358*5e7646d2SAndroid Build Coastguard Worker 
2359*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(when, "indefinite") || !strcmp(when, "auth-info-required"))
2360*5e7646d2SAndroid Build Coastguard Worker   {
2361*5e7646d2SAndroid Build Coastguard Worker    /*
2362*5e7646d2SAndroid Build Coastguard Worker     * Hold indefinitely...
2363*5e7646d2SAndroid Build Coastguard Worker     */
2364*5e7646d2SAndroid Build Coastguard Worker 
2365*5e7646d2SAndroid Build Coastguard Worker     job->hold_until = 0;
2366*5e7646d2SAndroid Build Coastguard Worker 
2367*5e7646d2SAndroid Build Coastguard Worker     if (MaxHoldTime > 0)
2368*5e7646d2SAndroid Build Coastguard Worker       job->cancel_time = time(NULL) + MaxHoldTime;
2369*5e7646d2SAndroid Build Coastguard Worker   }
2370*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(when, "day-time"))
2371*5e7646d2SAndroid Build Coastguard Worker   {
2372*5e7646d2SAndroid Build Coastguard Worker    /*
2373*5e7646d2SAndroid Build Coastguard Worker     * Hold to 6am the next morning unless local time is < 6pm.
2374*5e7646d2SAndroid Build Coastguard Worker     */
2375*5e7646d2SAndroid Build Coastguard Worker 
2376*5e7646d2SAndroid Build Coastguard Worker     time(&curtime);
2377*5e7646d2SAndroid Build Coastguard Worker     localtime_r(&curtime, &curdate);
2378*5e7646d2SAndroid Build Coastguard Worker 
2379*5e7646d2SAndroid Build Coastguard Worker     if (curdate.tm_hour < 18)
2380*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime;
2381*5e7646d2SAndroid Build Coastguard Worker     else
2382*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime +
2383*5e7646d2SAndroid Build Coastguard Worker                         ((29 - curdate.tm_hour) * 60 + 59 -
2384*5e7646d2SAndroid Build Coastguard Worker 			 curdate.tm_min) * 60 + 60 - curdate.tm_sec;
2385*5e7646d2SAndroid Build Coastguard Worker   }
2386*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(when, "evening") || !strcmp(when, "night"))
2387*5e7646d2SAndroid Build Coastguard Worker   {
2388*5e7646d2SAndroid Build Coastguard Worker    /*
2389*5e7646d2SAndroid Build Coastguard Worker     * Hold to 6pm unless local time is > 6pm or < 6am.
2390*5e7646d2SAndroid Build Coastguard Worker     */
2391*5e7646d2SAndroid Build Coastguard Worker 
2392*5e7646d2SAndroid Build Coastguard Worker     time(&curtime);
2393*5e7646d2SAndroid Build Coastguard Worker     localtime_r(&curtime, &curdate);
2394*5e7646d2SAndroid Build Coastguard Worker 
2395*5e7646d2SAndroid Build Coastguard Worker     if (curdate.tm_hour < 6 || curdate.tm_hour >= 18)
2396*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime;
2397*5e7646d2SAndroid Build Coastguard Worker     else
2398*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime +
2399*5e7646d2SAndroid Build Coastguard Worker                         ((17 - curdate.tm_hour) * 60 + 59 -
2400*5e7646d2SAndroid Build Coastguard Worker 			 curdate.tm_min) * 60 + 60 - curdate.tm_sec;
2401*5e7646d2SAndroid Build Coastguard Worker   }
2402*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(when, "second-shift"))
2403*5e7646d2SAndroid Build Coastguard Worker   {
2404*5e7646d2SAndroid Build Coastguard Worker    /*
2405*5e7646d2SAndroid Build Coastguard Worker     * Hold to 4pm unless local time is > 4pm.
2406*5e7646d2SAndroid Build Coastguard Worker     */
2407*5e7646d2SAndroid Build Coastguard Worker 
2408*5e7646d2SAndroid Build Coastguard Worker     time(&curtime);
2409*5e7646d2SAndroid Build Coastguard Worker     localtime_r(&curtime, &curdate);
2410*5e7646d2SAndroid Build Coastguard Worker 
2411*5e7646d2SAndroid Build Coastguard Worker     if (curdate.tm_hour >= 16)
2412*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime;
2413*5e7646d2SAndroid Build Coastguard Worker     else
2414*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime +
2415*5e7646d2SAndroid Build Coastguard Worker                         ((15 - curdate.tm_hour) * 60 + 59 -
2416*5e7646d2SAndroid Build Coastguard Worker 			 curdate.tm_min) * 60 + 60 - curdate.tm_sec;
2417*5e7646d2SAndroid Build Coastguard Worker   }
2418*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(when, "third-shift"))
2419*5e7646d2SAndroid Build Coastguard Worker   {
2420*5e7646d2SAndroid Build Coastguard Worker    /*
2421*5e7646d2SAndroid Build Coastguard Worker     * Hold to 12am unless local time is < 8am.
2422*5e7646d2SAndroid Build Coastguard Worker     */
2423*5e7646d2SAndroid Build Coastguard Worker 
2424*5e7646d2SAndroid Build Coastguard Worker     time(&curtime);
2425*5e7646d2SAndroid Build Coastguard Worker     localtime_r(&curtime, &curdate);
2426*5e7646d2SAndroid Build Coastguard Worker 
2427*5e7646d2SAndroid Build Coastguard Worker     if (curdate.tm_hour < 8)
2428*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime;
2429*5e7646d2SAndroid Build Coastguard Worker     else
2430*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime +
2431*5e7646d2SAndroid Build Coastguard Worker                         ((23 - curdate.tm_hour) * 60 + 59 -
2432*5e7646d2SAndroid Build Coastguard Worker 			 curdate.tm_min) * 60 + 60 - curdate.tm_sec;
2433*5e7646d2SAndroid Build Coastguard Worker   }
2434*5e7646d2SAndroid Build Coastguard Worker   else if (!strcmp(when, "weekend"))
2435*5e7646d2SAndroid Build Coastguard Worker   {
2436*5e7646d2SAndroid Build Coastguard Worker    /*
2437*5e7646d2SAndroid Build Coastguard Worker     * Hold to weekend unless we are in the weekend.
2438*5e7646d2SAndroid Build Coastguard Worker     */
2439*5e7646d2SAndroid Build Coastguard Worker 
2440*5e7646d2SAndroid Build Coastguard Worker     time(&curtime);
2441*5e7646d2SAndroid Build Coastguard Worker     localtime_r(&curtime, &curdate);
2442*5e7646d2SAndroid Build Coastguard Worker 
2443*5e7646d2SAndroid Build Coastguard Worker     if (curdate.tm_wday == 0 || curdate.tm_wday == 6)
2444*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime;
2445*5e7646d2SAndroid Build Coastguard Worker     else
2446*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = curtime +
2447*5e7646d2SAndroid Build Coastguard Worker                         (((5 - curdate.tm_wday) * 24 +
2448*5e7646d2SAndroid Build Coastguard Worker                           (17 - curdate.tm_hour)) * 60 + 59 -
2449*5e7646d2SAndroid Build Coastguard Worker 			   curdate.tm_min) * 60 + 60 - curdate.tm_sec;
2450*5e7646d2SAndroid Build Coastguard Worker   }
2451*5e7646d2SAndroid Build Coastguard Worker   else if (sscanf(when, "%d:%d:%d", &hour, &minute, &second) >= 2)
2452*5e7646d2SAndroid Build Coastguard Worker   {
2453*5e7646d2SAndroid Build Coastguard Worker    /*
2454*5e7646d2SAndroid Build Coastguard Worker     * Hold to specified GMT time (HH:MM or HH:MM:SS)...
2455*5e7646d2SAndroid Build Coastguard Worker     */
2456*5e7646d2SAndroid Build Coastguard Worker 
2457*5e7646d2SAndroid Build Coastguard Worker     time(&curtime);
2458*5e7646d2SAndroid Build Coastguard Worker     gmtime_r(&curtime, &curdate);
2459*5e7646d2SAndroid Build Coastguard Worker 
2460*5e7646d2SAndroid Build Coastguard Worker     job->hold_until = curtime +
2461*5e7646d2SAndroid Build Coastguard Worker                       ((hour - curdate.tm_hour) * 60 + minute -
2462*5e7646d2SAndroid Build Coastguard Worker 		       curdate.tm_min) * 60 + second - curdate.tm_sec;
2463*5e7646d2SAndroid Build Coastguard Worker 
2464*5e7646d2SAndroid Build Coastguard Worker    /*
2465*5e7646d2SAndroid Build Coastguard Worker     * Hold until next day as needed...
2466*5e7646d2SAndroid Build Coastguard Worker     */
2467*5e7646d2SAndroid Build Coastguard Worker 
2468*5e7646d2SAndroid Build Coastguard Worker     if (job->hold_until < curtime)
2469*5e7646d2SAndroid Build Coastguard Worker       job->hold_until += 24 * 60 * 60;
2470*5e7646d2SAndroid Build Coastguard Worker   }
2471*5e7646d2SAndroid Build Coastguard Worker 
2472*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSetJobHoldUntil: hold_until=%d",
2473*5e7646d2SAndroid Build Coastguard Worker                   (int)job->hold_until);
2474*5e7646d2SAndroid Build Coastguard Worker }
2475*5e7646d2SAndroid Build Coastguard Worker 
2476*5e7646d2SAndroid Build Coastguard Worker 
2477*5e7646d2SAndroid Build Coastguard Worker /*
2478*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSetJobPriority()' - Set the priority of a job, moving it up/down in
2479*5e7646d2SAndroid Build Coastguard Worker  *                           the list as needed.
2480*5e7646d2SAndroid Build Coastguard Worker  */
2481*5e7646d2SAndroid Build Coastguard Worker 
2482*5e7646d2SAndroid Build Coastguard Worker void
cupsdSetJobPriority(cupsd_job_t * job,int priority)2483*5e7646d2SAndroid Build Coastguard Worker cupsdSetJobPriority(
2484*5e7646d2SAndroid Build Coastguard Worker     cupsd_job_t *job,			/* I - Job ID */
2485*5e7646d2SAndroid Build Coastguard Worker     int         priority)		/* I - New priority (0 to 100) */
2486*5e7646d2SAndroid Build Coastguard Worker {
2487*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Job attribute */
2488*5e7646d2SAndroid Build Coastguard Worker 
2489*5e7646d2SAndroid Build Coastguard Worker 
2490*5e7646d2SAndroid Build Coastguard Worker  /*
2491*5e7646d2SAndroid Build Coastguard Worker   * Don't change completed jobs...
2492*5e7646d2SAndroid Build Coastguard Worker   */
2493*5e7646d2SAndroid Build Coastguard Worker 
2494*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value >= IPP_JOB_PROCESSING)
2495*5e7646d2SAndroid Build Coastguard Worker     return;
2496*5e7646d2SAndroid Build Coastguard Worker 
2497*5e7646d2SAndroid Build Coastguard Worker  /*
2498*5e7646d2SAndroid Build Coastguard Worker   * Set the new priority and re-add the job into the active list...
2499*5e7646d2SAndroid Build Coastguard Worker   */
2500*5e7646d2SAndroid Build Coastguard Worker 
2501*5e7646d2SAndroid Build Coastguard Worker   cupsArrayRemove(ActiveJobs, job);
2502*5e7646d2SAndroid Build Coastguard Worker 
2503*5e7646d2SAndroid Build Coastguard Worker   job->priority = priority;
2504*5e7646d2SAndroid Build Coastguard Worker 
2505*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "job-priority",
2506*5e7646d2SAndroid Build Coastguard Worker                                IPP_TAG_INTEGER)) != NULL)
2507*5e7646d2SAndroid Build Coastguard Worker     attr->values[0].integer = priority;
2508*5e7646d2SAndroid Build Coastguard Worker   else
2509*5e7646d2SAndroid Build Coastguard Worker     ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
2510*5e7646d2SAndroid Build Coastguard Worker                   priority);
2511*5e7646d2SAndroid Build Coastguard Worker 
2512*5e7646d2SAndroid Build Coastguard Worker   cupsArrayAdd(ActiveJobs, job);
2513*5e7646d2SAndroid Build Coastguard Worker 
2514*5e7646d2SAndroid Build Coastguard Worker   job->dirty = 1;
2515*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
2516*5e7646d2SAndroid Build Coastguard Worker }
2517*5e7646d2SAndroid Build Coastguard Worker 
2518*5e7646d2SAndroid Build Coastguard Worker 
2519*5e7646d2SAndroid Build Coastguard Worker /*
2520*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdSetJobState()' - Set the state of the specified print job.
2521*5e7646d2SAndroid Build Coastguard Worker  */
2522*5e7646d2SAndroid Build Coastguard Worker 
2523*5e7646d2SAndroid Build Coastguard Worker void
cupsdSetJobState(cupsd_job_t * job,ipp_jstate_t newstate,cupsd_jobaction_t action,const char * message,...)2524*5e7646d2SAndroid Build Coastguard Worker cupsdSetJobState(
2525*5e7646d2SAndroid Build Coastguard Worker     cupsd_job_t       *job,		/* I - Job to cancel */
2526*5e7646d2SAndroid Build Coastguard Worker     ipp_jstate_t      newstate,		/* I - New job state */
2527*5e7646d2SAndroid Build Coastguard Worker     cupsd_jobaction_t action,		/* I - Action to take */
2528*5e7646d2SAndroid Build Coastguard Worker     const char        *message,		/* I - Message to log */
2529*5e7646d2SAndroid Build Coastguard Worker     ...)				/* I - Additional arguments as needed */
2530*5e7646d2SAndroid Build Coastguard Worker {
2531*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
2532*5e7646d2SAndroid Build Coastguard Worker   ipp_jstate_t		oldstate;	/* Old state */
2533*5e7646d2SAndroid Build Coastguard Worker   char			filename[1024];	/* Job filename */
2534*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Job attribute */
2535*5e7646d2SAndroid Build Coastguard Worker 
2536*5e7646d2SAndroid Build Coastguard Worker 
2537*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2,
2538*5e7646d2SAndroid Build Coastguard Worker                   "cupsdSetJobState(job=%p(%d), state=%d, newstate=%d, "
2539*5e7646d2SAndroid Build Coastguard Worker 		  "action=%d, message=\"%s\")", job, job->id, job->state_value,
2540*5e7646d2SAndroid Build Coastguard Worker 		  newstate, action, message ? message : "(null)");
2541*5e7646d2SAndroid Build Coastguard Worker 
2542*5e7646d2SAndroid Build Coastguard Worker 
2543*5e7646d2SAndroid Build Coastguard Worker  /*
2544*5e7646d2SAndroid Build Coastguard Worker   * Make sure we have the job attributes...
2545*5e7646d2SAndroid Build Coastguard Worker   */
2546*5e7646d2SAndroid Build Coastguard Worker 
2547*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdLoadJob(job))
2548*5e7646d2SAndroid Build Coastguard Worker     return;
2549*5e7646d2SAndroid Build Coastguard Worker 
2550*5e7646d2SAndroid Build Coastguard Worker  /*
2551*5e7646d2SAndroid Build Coastguard Worker   * Don't do anything if the state is unchanged and we aren't purging the
2552*5e7646d2SAndroid Build Coastguard Worker   * job...
2553*5e7646d2SAndroid Build Coastguard Worker   */
2554*5e7646d2SAndroid Build Coastguard Worker 
2555*5e7646d2SAndroid Build Coastguard Worker   oldstate = job->state_value;
2556*5e7646d2SAndroid Build Coastguard Worker   if (newstate == oldstate && action != CUPSD_JOB_PURGE)
2557*5e7646d2SAndroid Build Coastguard Worker     return;
2558*5e7646d2SAndroid Build Coastguard Worker 
2559*5e7646d2SAndroid Build Coastguard Worker  /*
2560*5e7646d2SAndroid Build Coastguard Worker   * Stop any processes that are working on the current job...
2561*5e7646d2SAndroid Build Coastguard Worker   */
2562*5e7646d2SAndroid Build Coastguard Worker 
2563*5e7646d2SAndroid Build Coastguard Worker   if (oldstate == IPP_JOB_PROCESSING)
2564*5e7646d2SAndroid Build Coastguard Worker     stop_job(job, action);
2565*5e7646d2SAndroid Build Coastguard Worker 
2566*5e7646d2SAndroid Build Coastguard Worker  /*
2567*5e7646d2SAndroid Build Coastguard Worker   * Set the new job state...
2568*5e7646d2SAndroid Build Coastguard Worker   */
2569*5e7646d2SAndroid Build Coastguard Worker 
2570*5e7646d2SAndroid Build Coastguard Worker   job->state_value = newstate;
2571*5e7646d2SAndroid Build Coastguard Worker 
2572*5e7646d2SAndroid Build Coastguard Worker   if (job->state)
2573*5e7646d2SAndroid Build Coastguard Worker     job->state->values[0].integer = (int)newstate;
2574*5e7646d2SAndroid Build Coastguard Worker 
2575*5e7646d2SAndroid Build Coastguard Worker   switch (newstate)
2576*5e7646d2SAndroid Build Coastguard Worker   {
2577*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_PENDING :
2578*5e7646d2SAndroid Build Coastguard Worker        /*
2579*5e7646d2SAndroid Build Coastguard Worker 	* Update job-hold-until as needed...
2580*5e7646d2SAndroid Build Coastguard Worker 	*/
2581*5e7646d2SAndroid Build Coastguard Worker 
2582*5e7646d2SAndroid Build Coastguard Worker 	if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
2583*5e7646d2SAndroid Build Coastguard Worker 				     IPP_TAG_KEYWORD)) == NULL)
2584*5e7646d2SAndroid Build Coastguard Worker 	  attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
2585*5e7646d2SAndroid Build Coastguard Worker 
2586*5e7646d2SAndroid Build Coastguard Worker 	if (attr)
2587*5e7646d2SAndroid Build Coastguard Worker 	{
2588*5e7646d2SAndroid Build Coastguard Worker 	  ippSetValueTag(job->attrs, &attr, IPP_TAG_KEYWORD);
2589*5e7646d2SAndroid Build Coastguard Worker 	  ippSetString(job->attrs, &attr, 0, "no-hold");
2590*5e7646d2SAndroid Build Coastguard Worker 	}
2591*5e7646d2SAndroid Build Coastguard Worker 
2592*5e7646d2SAndroid Build Coastguard Worker     default :
2593*5e7646d2SAndroid Build Coastguard Worker 	break;
2594*5e7646d2SAndroid Build Coastguard Worker 
2595*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_ABORTED :
2596*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_CANCELED :
2597*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_COMPLETED :
2598*5e7646d2SAndroid Build Coastguard Worker 	set_time(job, "time-at-completed");
2599*5e7646d2SAndroid Build Coastguard Worker 	ippSetString(job->attrs, &job->reasons, 0, "processing-to-stop-point");
2600*5e7646d2SAndroid Build Coastguard Worker         break;
2601*5e7646d2SAndroid Build Coastguard Worker   }
2602*5e7646d2SAndroid Build Coastguard Worker 
2603*5e7646d2SAndroid Build Coastguard Worker  /*
2604*5e7646d2SAndroid Build Coastguard Worker   * Log message as needed...
2605*5e7646d2SAndroid Build Coastguard Worker   */
2606*5e7646d2SAndroid Build Coastguard Worker 
2607*5e7646d2SAndroid Build Coastguard Worker   if (message)
2608*5e7646d2SAndroid Build Coastguard Worker   {
2609*5e7646d2SAndroid Build Coastguard Worker     char	buffer[2048];		/* Message buffer */
2610*5e7646d2SAndroid Build Coastguard Worker     va_list	ap;			/* Pointer to additional arguments */
2611*5e7646d2SAndroid Build Coastguard Worker 
2612*5e7646d2SAndroid Build Coastguard Worker     va_start(ap, message);
2613*5e7646d2SAndroid Build Coastguard Worker     vsnprintf(buffer, sizeof(buffer), message, ap);
2614*5e7646d2SAndroid Build Coastguard Worker     va_end(ap);
2615*5e7646d2SAndroid Build Coastguard Worker 
2616*5e7646d2SAndroid Build Coastguard Worker     if (newstate > IPP_JOB_STOPPED)
2617*5e7646d2SAndroid Build Coastguard Worker       cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, "%s", buffer);
2618*5e7646d2SAndroid Build Coastguard Worker     else
2619*5e7646d2SAndroid Build Coastguard Worker       cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "%s", buffer);
2620*5e7646d2SAndroid Build Coastguard Worker 
2621*5e7646d2SAndroid Build Coastguard Worker     if (newstate == IPP_JOB_STOPPED || newstate == IPP_JOB_ABORTED)
2622*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_ERROR, "%s", buffer);
2623*5e7646d2SAndroid Build Coastguard Worker     else
2624*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_INFO, "%s", buffer);
2625*5e7646d2SAndroid Build Coastguard Worker   }
2626*5e7646d2SAndroid Build Coastguard Worker 
2627*5e7646d2SAndroid Build Coastguard Worker  /*
2628*5e7646d2SAndroid Build Coastguard Worker   * Handle post-state-change actions...
2629*5e7646d2SAndroid Build Coastguard Worker   */
2630*5e7646d2SAndroid Build Coastguard Worker 
2631*5e7646d2SAndroid Build Coastguard Worker   switch (newstate)
2632*5e7646d2SAndroid Build Coastguard Worker   {
2633*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_PROCESSING :
2634*5e7646d2SAndroid Build Coastguard Worker        /*
2635*5e7646d2SAndroid Build Coastguard Worker         * Add the job to the "printing" list...
2636*5e7646d2SAndroid Build Coastguard Worker 	*/
2637*5e7646d2SAndroid Build Coastguard Worker 
2638*5e7646d2SAndroid Build Coastguard Worker         if (!cupsArrayFind(PrintingJobs, job))
2639*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayAdd(PrintingJobs, job);
2640*5e7646d2SAndroid Build Coastguard Worker 
2641*5e7646d2SAndroid Build Coastguard Worker        /*
2642*5e7646d2SAndroid Build Coastguard Worker 	* Set the processing time...
2643*5e7646d2SAndroid Build Coastguard Worker 	*/
2644*5e7646d2SAndroid Build Coastguard Worker 
2645*5e7646d2SAndroid Build Coastguard Worker 	set_time(job, "time-at-processing");
2646*5e7646d2SAndroid Build Coastguard Worker 
2647*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_PENDING :
2648*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_HELD :
2649*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_STOPPED :
2650*5e7646d2SAndroid Build Coastguard Worker        /*
2651*5e7646d2SAndroid Build Coastguard Worker         * Make sure the job is in the active list...
2652*5e7646d2SAndroid Build Coastguard Worker 	*/
2653*5e7646d2SAndroid Build Coastguard Worker 
2654*5e7646d2SAndroid Build Coastguard Worker         if (!cupsArrayFind(ActiveJobs, job))
2655*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayAdd(ActiveJobs, job);
2656*5e7646d2SAndroid Build Coastguard Worker 
2657*5e7646d2SAndroid Build Coastguard Worker        /*
2658*5e7646d2SAndroid Build Coastguard Worker 	* Save the job state to disk...
2659*5e7646d2SAndroid Build Coastguard Worker 	*/
2660*5e7646d2SAndroid Build Coastguard Worker 
2661*5e7646d2SAndroid Build Coastguard Worker 	job->dirty = 1;
2662*5e7646d2SAndroid Build Coastguard Worker 	cupsdMarkDirty(CUPSD_DIRTY_JOBS);
2663*5e7646d2SAndroid Build Coastguard Worker         break;
2664*5e7646d2SAndroid Build Coastguard Worker 
2665*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_ABORTED :
2666*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_CANCELED :
2667*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_COMPLETED :
2668*5e7646d2SAndroid Build Coastguard Worker         if (newstate == IPP_JOB_CANCELED)
2669*5e7646d2SAndroid Build Coastguard Worker 	{
2670*5e7646d2SAndroid Build Coastguard Worker 	 /*
2671*5e7646d2SAndroid Build Coastguard Worker 	  * Remove the job from the active list if there are no processes still
2672*5e7646d2SAndroid Build Coastguard Worker 	  * running for it...
2673*5e7646d2SAndroid Build Coastguard Worker 	  */
2674*5e7646d2SAndroid Build Coastguard Worker 
2675*5e7646d2SAndroid Build Coastguard Worker 	  for (i = 0; job->filters[i] < 0; i++);
2676*5e7646d2SAndroid Build Coastguard Worker 
2677*5e7646d2SAndroid Build Coastguard Worker 	  if (!job->filters[i] && job->backend <= 0)
2678*5e7646d2SAndroid Build Coastguard Worker 	    cupsArrayRemove(ActiveJobs, job);
2679*5e7646d2SAndroid Build Coastguard Worker 	}
2680*5e7646d2SAndroid Build Coastguard Worker 	else
2681*5e7646d2SAndroid Build Coastguard Worker 	{
2682*5e7646d2SAndroid Build Coastguard Worker 	 /*
2683*5e7646d2SAndroid Build Coastguard Worker 	  * Otherwise just remove the job from the active list immediately...
2684*5e7646d2SAndroid Build Coastguard Worker 	  */
2685*5e7646d2SAndroid Build Coastguard Worker 
2686*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayRemove(ActiveJobs, job);
2687*5e7646d2SAndroid Build Coastguard Worker 	}
2688*5e7646d2SAndroid Build Coastguard Worker 
2689*5e7646d2SAndroid Build Coastguard Worker        /*
2690*5e7646d2SAndroid Build Coastguard Worker         * Expire job subscriptions since the job is now "completed"...
2691*5e7646d2SAndroid Build Coastguard Worker 	*/
2692*5e7646d2SAndroid Build Coastguard Worker 
2693*5e7646d2SAndroid Build Coastguard Worker         cupsdExpireSubscriptions(NULL, job);
2694*5e7646d2SAndroid Build Coastguard Worker 
2695*5e7646d2SAndroid Build Coastguard Worker #ifdef __APPLE__
2696*5e7646d2SAndroid Build Coastguard Worker        /*
2697*5e7646d2SAndroid Build Coastguard Worker 	* If we are going to sleep and the PrintingJobs count is now 0, allow the
2698*5e7646d2SAndroid Build Coastguard Worker 	* sleep to happen immediately...
2699*5e7646d2SAndroid Build Coastguard Worker 	*/
2700*5e7646d2SAndroid Build Coastguard Worker 
2701*5e7646d2SAndroid Build Coastguard Worker 	if (Sleeping && cupsArrayCount(PrintingJobs) == 0)
2702*5e7646d2SAndroid Build Coastguard Worker 	  cupsdAllowSleep();
2703*5e7646d2SAndroid Build Coastguard Worker #endif /* __APPLE__ */
2704*5e7646d2SAndroid Build Coastguard Worker 
2705*5e7646d2SAndroid Build Coastguard Worker        /*
2706*5e7646d2SAndroid Build Coastguard Worker 	* Remove any authentication data...
2707*5e7646d2SAndroid Build Coastguard Worker 	*/
2708*5e7646d2SAndroid Build Coastguard Worker 
2709*5e7646d2SAndroid Build Coastguard Worker 	snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id);
2710*5e7646d2SAndroid Build Coastguard Worker 	if (cupsdRemoveFile(filename) && errno != ENOENT)
2711*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_ERROR,
2712*5e7646d2SAndroid Build Coastguard Worker 			  "Unable to remove authentication cache: %s",
2713*5e7646d2SAndroid Build Coastguard Worker 			  strerror(errno));
2714*5e7646d2SAndroid Build Coastguard Worker 
2715*5e7646d2SAndroid Build Coastguard Worker 	for (i = 0;
2716*5e7646d2SAndroid Build Coastguard Worker 	     i < (int)(sizeof(job->auth_env) / sizeof(job->auth_env[0]));
2717*5e7646d2SAndroid Build Coastguard Worker 	     i ++)
2718*5e7646d2SAndroid Build Coastguard Worker 	  cupsdClearString(job->auth_env + i);
2719*5e7646d2SAndroid Build Coastguard Worker 
2720*5e7646d2SAndroid Build Coastguard Worker 	cupsdClearString(&job->auth_uid);
2721*5e7646d2SAndroid Build Coastguard Worker 
2722*5e7646d2SAndroid Build Coastguard Worker        /*
2723*5e7646d2SAndroid Build Coastguard Worker 	* Remove the print file for good if we aren't preserving jobs or
2724*5e7646d2SAndroid Build Coastguard Worker 	* files...
2725*5e7646d2SAndroid Build Coastguard Worker 	*/
2726*5e7646d2SAndroid Build Coastguard Worker 
2727*5e7646d2SAndroid Build Coastguard Worker 	if (!JobHistory || !JobFiles || action == CUPSD_JOB_PURGE)
2728*5e7646d2SAndroid Build Coastguard Worker 	  remove_job_files(job);
2729*5e7646d2SAndroid Build Coastguard Worker 
2730*5e7646d2SAndroid Build Coastguard Worker 	if (JobHistory && action != CUPSD_JOB_PURGE)
2731*5e7646d2SAndroid Build Coastguard Worker 	{
2732*5e7646d2SAndroid Build Coastguard Worker 	 /*
2733*5e7646d2SAndroid Build Coastguard Worker 	  * Save job state info...
2734*5e7646d2SAndroid Build Coastguard Worker 	  */
2735*5e7646d2SAndroid Build Coastguard Worker 
2736*5e7646d2SAndroid Build Coastguard Worker 	  job->dirty = 1;
2737*5e7646d2SAndroid Build Coastguard Worker 	  cupsdMarkDirty(CUPSD_DIRTY_JOBS);
2738*5e7646d2SAndroid Build Coastguard Worker 	}
2739*5e7646d2SAndroid Build Coastguard Worker 	else if (!job->printer)
2740*5e7646d2SAndroid Build Coastguard Worker 	{
2741*5e7646d2SAndroid Build Coastguard Worker 	 /*
2742*5e7646d2SAndroid Build Coastguard Worker 	  * Delete the job immediately if not actively printing...
2743*5e7646d2SAndroid Build Coastguard Worker 	  */
2744*5e7646d2SAndroid Build Coastguard Worker 
2745*5e7646d2SAndroid Build Coastguard Worker 	  cupsdDeleteJob(job, CUPSD_JOB_PURGE);
2746*5e7646d2SAndroid Build Coastguard Worker 	  job = NULL;
2747*5e7646d2SAndroid Build Coastguard Worker 	}
2748*5e7646d2SAndroid Build Coastguard Worker 	break;
2749*5e7646d2SAndroid Build Coastguard Worker   }
2750*5e7646d2SAndroid Build Coastguard Worker 
2751*5e7646d2SAndroid Build Coastguard Worker  /*
2752*5e7646d2SAndroid Build Coastguard Worker   * Finalize the job immediately if we forced things...
2753*5e7646d2SAndroid Build Coastguard Worker   */
2754*5e7646d2SAndroid Build Coastguard Worker 
2755*5e7646d2SAndroid Build Coastguard Worker   if (action >= CUPSD_JOB_FORCE && job && job->printer)
2756*5e7646d2SAndroid Build Coastguard Worker     finalize_job(job, 0);
2757*5e7646d2SAndroid Build Coastguard Worker 
2758*5e7646d2SAndroid Build Coastguard Worker  /*
2759*5e7646d2SAndroid Build Coastguard Worker   * Update the server "busy" state...
2760*5e7646d2SAndroid Build Coastguard Worker   */
2761*5e7646d2SAndroid Build Coastguard Worker 
2762*5e7646d2SAndroid Build Coastguard Worker   cupsdSetBusyState(0);
2763*5e7646d2SAndroid Build Coastguard Worker }
2764*5e7646d2SAndroid Build Coastguard Worker 
2765*5e7646d2SAndroid Build Coastguard Worker 
2766*5e7646d2SAndroid Build Coastguard Worker /*
2767*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdStopAllJobs()' - Stop all print jobs.
2768*5e7646d2SAndroid Build Coastguard Worker  */
2769*5e7646d2SAndroid Build Coastguard Worker 
2770*5e7646d2SAndroid Build Coastguard Worker void
cupsdStopAllJobs(cupsd_jobaction_t action,int kill_delay)2771*5e7646d2SAndroid Build Coastguard Worker cupsdStopAllJobs(
2772*5e7646d2SAndroid Build Coastguard Worker     cupsd_jobaction_t action,		/* I - Action */
2773*5e7646d2SAndroid Build Coastguard Worker     int               kill_delay)	/* I - Number of seconds before we kill */
2774*5e7646d2SAndroid Build Coastguard Worker {
2775*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
2776*5e7646d2SAndroid Build Coastguard Worker 
2777*5e7646d2SAndroid Build Coastguard Worker 
2778*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(PrintingJobs);
2779*5e7646d2SAndroid Build Coastguard Worker        job;
2780*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(PrintingJobs))
2781*5e7646d2SAndroid Build Coastguard Worker   {
2782*5e7646d2SAndroid Build Coastguard Worker     if (job->completed)
2783*5e7646d2SAndroid Build Coastguard Worker     {
2784*5e7646d2SAndroid Build Coastguard Worker       cupsdSetJobState(job, IPP_JOB_COMPLETED, CUPSD_JOB_FORCE, NULL);
2785*5e7646d2SAndroid Build Coastguard Worker     }
2786*5e7646d2SAndroid Build Coastguard Worker     else
2787*5e7646d2SAndroid Build Coastguard Worker     {
2788*5e7646d2SAndroid Build Coastguard Worker       if (kill_delay)
2789*5e7646d2SAndroid Build Coastguard Worker         job->kill_time = time(NULL) + kill_delay;
2790*5e7646d2SAndroid Build Coastguard Worker 
2791*5e7646d2SAndroid Build Coastguard Worker       cupsdSetJobState(job, IPP_JOB_PENDING, action, NULL);
2792*5e7646d2SAndroid Build Coastguard Worker     }
2793*5e7646d2SAndroid Build Coastguard Worker   }
2794*5e7646d2SAndroid Build Coastguard Worker }
2795*5e7646d2SAndroid Build Coastguard Worker 
2796*5e7646d2SAndroid Build Coastguard Worker 
2797*5e7646d2SAndroid Build Coastguard Worker /*
2798*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdUnloadCompletedJobs()' - Flush completed job history from memory.
2799*5e7646d2SAndroid Build Coastguard Worker  */
2800*5e7646d2SAndroid Build Coastguard Worker 
2801*5e7646d2SAndroid Build Coastguard Worker void
cupsdUnloadCompletedJobs(void)2802*5e7646d2SAndroid Build Coastguard Worker cupsdUnloadCompletedJobs(void)
2803*5e7646d2SAndroid Build Coastguard Worker {
2804*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
2805*5e7646d2SAndroid Build Coastguard Worker   time_t	expire;			/* Expiration time */
2806*5e7646d2SAndroid Build Coastguard Worker 
2807*5e7646d2SAndroid Build Coastguard Worker 
2808*5e7646d2SAndroid Build Coastguard Worker   expire = time(NULL) - 60;
2809*5e7646d2SAndroid Build Coastguard Worker 
2810*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
2811*5e7646d2SAndroid Build Coastguard Worker        job;
2812*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(Jobs))
2813*5e7646d2SAndroid Build Coastguard Worker     if (job->attrs && job->state_value >= IPP_JOB_STOPPED && !job->printer &&
2814*5e7646d2SAndroid Build Coastguard Worker         job->access_time < expire)
2815*5e7646d2SAndroid Build Coastguard Worker     {
2816*5e7646d2SAndroid Build Coastguard Worker       if (job->dirty)
2817*5e7646d2SAndroid Build Coastguard Worker         cupsdSaveJob(job);
2818*5e7646d2SAndroid Build Coastguard Worker 
2819*5e7646d2SAndroid Build Coastguard Worker       if (!job->dirty)
2820*5e7646d2SAndroid Build Coastguard Worker         unload_job(job);
2821*5e7646d2SAndroid Build Coastguard Worker     }
2822*5e7646d2SAndroid Build Coastguard Worker }
2823*5e7646d2SAndroid Build Coastguard Worker 
2824*5e7646d2SAndroid Build Coastguard Worker 
2825*5e7646d2SAndroid Build Coastguard Worker /*
2826*5e7646d2SAndroid Build Coastguard Worker  * 'cupsdUpdateJobs()' - Update the history/file files for all jobs.
2827*5e7646d2SAndroid Build Coastguard Worker  */
2828*5e7646d2SAndroid Build Coastguard Worker 
2829*5e7646d2SAndroid Build Coastguard Worker void
cupsdUpdateJobs(void)2830*5e7646d2SAndroid Build Coastguard Worker cupsdUpdateJobs(void)
2831*5e7646d2SAndroid Build Coastguard Worker {
2832*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* Current job */
2833*5e7646d2SAndroid Build Coastguard Worker   time_t		curtime;	/* Current time */
2834*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* time-at-completed attribute */
2835*5e7646d2SAndroid Build Coastguard Worker 
2836*5e7646d2SAndroid Build Coastguard Worker 
2837*5e7646d2SAndroid Build Coastguard Worker   curtime          = time(NULL);
2838*5e7646d2SAndroid Build Coastguard Worker   JobHistoryUpdate = 0;
2839*5e7646d2SAndroid Build Coastguard Worker 
2840*5e7646d2SAndroid Build Coastguard Worker   for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
2841*5e7646d2SAndroid Build Coastguard Worker        job;
2842*5e7646d2SAndroid Build Coastguard Worker        job = (cupsd_job_t *)cupsArrayNext(Jobs))
2843*5e7646d2SAndroid Build Coastguard Worker   {
2844*5e7646d2SAndroid Build Coastguard Worker     if (job->state_value >= IPP_JOB_CANCELED &&
2845*5e7646d2SAndroid Build Coastguard Worker         (attr = ippFindAttribute(job->attrs, "time-at-completed",
2846*5e7646d2SAndroid Build Coastguard Worker                                  IPP_TAG_INTEGER)) != NULL)
2847*5e7646d2SAndroid Build Coastguard Worker     {
2848*5e7646d2SAndroid Build Coastguard Worker      /*
2849*5e7646d2SAndroid Build Coastguard Worker       * Update history/file expiration times...
2850*5e7646d2SAndroid Build Coastguard Worker       */
2851*5e7646d2SAndroid Build Coastguard Worker 
2852*5e7646d2SAndroid Build Coastguard Worker       job->completed_time = attr->values[0].integer;
2853*5e7646d2SAndroid Build Coastguard Worker 
2854*5e7646d2SAndroid Build Coastguard Worker       if (JobHistory < INT_MAX)
2855*5e7646d2SAndroid Build Coastguard Worker 	job->history_time = job->completed_time + JobHistory;
2856*5e7646d2SAndroid Build Coastguard Worker       else
2857*5e7646d2SAndroid Build Coastguard Worker 	job->history_time = INT_MAX;
2858*5e7646d2SAndroid Build Coastguard Worker 
2859*5e7646d2SAndroid Build Coastguard Worker       if (job->history_time < curtime)
2860*5e7646d2SAndroid Build Coastguard Worker       {
2861*5e7646d2SAndroid Build Coastguard Worker         cupsdDeleteJob(job, CUPSD_JOB_PURGE);
2862*5e7646d2SAndroid Build Coastguard Worker         continue;
2863*5e7646d2SAndroid Build Coastguard Worker       }
2864*5e7646d2SAndroid Build Coastguard Worker 
2865*5e7646d2SAndroid Build Coastguard Worker       if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
2866*5e7646d2SAndroid Build Coastguard Worker 	JobHistoryUpdate = job->history_time;
2867*5e7646d2SAndroid Build Coastguard Worker 
2868*5e7646d2SAndroid Build Coastguard Worker       if (JobFiles < INT_MAX)
2869*5e7646d2SAndroid Build Coastguard Worker 	job->file_time = job->completed_time + JobFiles;
2870*5e7646d2SAndroid Build Coastguard Worker       else
2871*5e7646d2SAndroid Build Coastguard Worker 	job->file_time = INT_MAX;
2872*5e7646d2SAndroid Build Coastguard Worker 
2873*5e7646d2SAndroid Build Coastguard Worker       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);
2874*5e7646d2SAndroid Build Coastguard Worker 
2875*5e7646d2SAndroid Build Coastguard Worker       if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
2876*5e7646d2SAndroid Build Coastguard Worker 	JobHistoryUpdate = job->file_time;
2877*5e7646d2SAndroid Build Coastguard Worker     }
2878*5e7646d2SAndroid Build Coastguard Worker   }
2879*5e7646d2SAndroid Build Coastguard Worker 
2880*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdUpdateJobs: JobHistoryUpdate=%ld",
2881*5e7646d2SAndroid Build Coastguard Worker                   (long)JobHistoryUpdate);
2882*5e7646d2SAndroid Build Coastguard Worker }
2883*5e7646d2SAndroid Build Coastguard Worker 
2884*5e7646d2SAndroid Build Coastguard Worker 
2885*5e7646d2SAndroid Build Coastguard Worker /*
2886*5e7646d2SAndroid Build Coastguard Worker  * 'compare_active_jobs()' - Compare the job IDs and priorities of two jobs.
2887*5e7646d2SAndroid Build Coastguard Worker  */
2888*5e7646d2SAndroid Build Coastguard Worker 
2889*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Difference */
compare_active_jobs(void * first,void * second,void * data)2890*5e7646d2SAndroid Build Coastguard Worker compare_active_jobs(void *first,	/* I - First job */
2891*5e7646d2SAndroid Build Coastguard Worker                     void *second,	/* I - Second job */
2892*5e7646d2SAndroid Build Coastguard Worker 		    void *data)		/* I - App data (not used) */
2893*5e7646d2SAndroid Build Coastguard Worker {
2894*5e7646d2SAndroid Build Coastguard Worker   int	diff;				/* Difference */
2895*5e7646d2SAndroid Build Coastguard Worker 
2896*5e7646d2SAndroid Build Coastguard Worker 
2897*5e7646d2SAndroid Build Coastguard Worker   (void)data;
2898*5e7646d2SAndroid Build Coastguard Worker 
2899*5e7646d2SAndroid Build Coastguard Worker   if ((diff = ((cupsd_job_t *)second)->priority -
2900*5e7646d2SAndroid Build Coastguard Worker               ((cupsd_job_t *)first)->priority) != 0)
2901*5e7646d2SAndroid Build Coastguard Worker     return (diff);
2902*5e7646d2SAndroid Build Coastguard Worker   else
2903*5e7646d2SAndroid Build Coastguard Worker     return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
2904*5e7646d2SAndroid Build Coastguard Worker }
2905*5e7646d2SAndroid Build Coastguard Worker 
2906*5e7646d2SAndroid Build Coastguard Worker 
2907*5e7646d2SAndroid Build Coastguard Worker /*
2908*5e7646d2SAndroid Build Coastguard Worker  * 'compare_completed_jobs()' - Compare the job IDs and completion times of two jobs.
2909*5e7646d2SAndroid Build Coastguard Worker  */
2910*5e7646d2SAndroid Build Coastguard Worker 
2911*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Difference */
compare_completed_jobs(void * first,void * second,void * data)2912*5e7646d2SAndroid Build Coastguard Worker compare_completed_jobs(void *first,	/* I - First job */
2913*5e7646d2SAndroid Build Coastguard Worker                        void *second,	/* I - Second job */
2914*5e7646d2SAndroid Build Coastguard Worker 		       void *data)	/* I - App data (not used) */
2915*5e7646d2SAndroid Build Coastguard Worker {
2916*5e7646d2SAndroid Build Coastguard Worker   int	diff;				/* Difference */
2917*5e7646d2SAndroid Build Coastguard Worker 
2918*5e7646d2SAndroid Build Coastguard Worker 
2919*5e7646d2SAndroid Build Coastguard Worker   (void)data;
2920*5e7646d2SAndroid Build Coastguard Worker 
2921*5e7646d2SAndroid Build Coastguard Worker   if ((diff = ((cupsd_job_t *)second)->completed_time -
2922*5e7646d2SAndroid Build Coastguard Worker               ((cupsd_job_t *)first)->completed_time) != 0)
2923*5e7646d2SAndroid Build Coastguard Worker     return (diff);
2924*5e7646d2SAndroid Build Coastguard Worker   else
2925*5e7646d2SAndroid Build Coastguard Worker     return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
2926*5e7646d2SAndroid Build Coastguard Worker }
2927*5e7646d2SAndroid Build Coastguard Worker 
2928*5e7646d2SAndroid Build Coastguard Worker 
2929*5e7646d2SAndroid Build Coastguard Worker /*
2930*5e7646d2SAndroid Build Coastguard Worker  * 'compare_jobs()' - Compare the job IDs of two jobs.
2931*5e7646d2SAndroid Build Coastguard Worker  */
2932*5e7646d2SAndroid Build Coastguard Worker 
2933*5e7646d2SAndroid Build Coastguard Worker static int				/* O - Difference */
compare_jobs(void * first,void * second,void * data)2934*5e7646d2SAndroid Build Coastguard Worker compare_jobs(void *first,		/* I - First job */
2935*5e7646d2SAndroid Build Coastguard Worker              void *second,		/* I - Second job */
2936*5e7646d2SAndroid Build Coastguard Worker 	     void *data)		/* I - App data (not used) */
2937*5e7646d2SAndroid Build Coastguard Worker {
2938*5e7646d2SAndroid Build Coastguard Worker   (void)data;
2939*5e7646d2SAndroid Build Coastguard Worker 
2940*5e7646d2SAndroid Build Coastguard Worker   return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
2941*5e7646d2SAndroid Build Coastguard Worker }
2942*5e7646d2SAndroid Build Coastguard Worker 
2943*5e7646d2SAndroid Build Coastguard Worker 
2944*5e7646d2SAndroid Build Coastguard Worker /*
2945*5e7646d2SAndroid Build Coastguard Worker  * 'dump_job_history()' - Dump any debug messages for a job.
2946*5e7646d2SAndroid Build Coastguard Worker  */
2947*5e7646d2SAndroid Build Coastguard Worker 
2948*5e7646d2SAndroid Build Coastguard Worker static void
dump_job_history(cupsd_job_t * job)2949*5e7646d2SAndroid Build Coastguard Worker dump_job_history(cupsd_job_t *job)	/* I - Job */
2950*5e7646d2SAndroid Build Coastguard Worker {
2951*5e7646d2SAndroid Build Coastguard Worker   int			i,		/* Looping var */
2952*5e7646d2SAndroid Build Coastguard Worker 			oldsize;	/* Current MaxLogSize */
2953*5e7646d2SAndroid Build Coastguard Worker   struct tm		date;		/* Date/time value */
2954*5e7646d2SAndroid Build Coastguard Worker   cupsd_joblog_t	*message;	/* Current message */
2955*5e7646d2SAndroid Build Coastguard Worker   char			temp[2048],	/* Log message */
2956*5e7646d2SAndroid Build Coastguard Worker 			*ptr,		/* Pointer into log message */
2957*5e7646d2SAndroid Build Coastguard Worker 			start[256],	/* Start time */
2958*5e7646d2SAndroid Build Coastguard Worker 			end[256];	/* End time */
2959*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t	*printer;	/* Printer for job */
2960*5e7646d2SAndroid Build Coastguard Worker 
2961*5e7646d2SAndroid Build Coastguard Worker 
2962*5e7646d2SAndroid Build Coastguard Worker  /*
2963*5e7646d2SAndroid Build Coastguard Worker   * See if we have anything to dump...
2964*5e7646d2SAndroid Build Coastguard Worker   */
2965*5e7646d2SAndroid Build Coastguard Worker 
2966*5e7646d2SAndroid Build Coastguard Worker   if (!job->history)
2967*5e7646d2SAndroid Build Coastguard Worker     return;
2968*5e7646d2SAndroid Build Coastguard Worker 
2969*5e7646d2SAndroid Build Coastguard Worker  /*
2970*5e7646d2SAndroid Build Coastguard Worker   * Disable log rotation temporarily...
2971*5e7646d2SAndroid Build Coastguard Worker   */
2972*5e7646d2SAndroid Build Coastguard Worker 
2973*5e7646d2SAndroid Build Coastguard Worker   oldsize    = MaxLogSize;
2974*5e7646d2SAndroid Build Coastguard Worker   MaxLogSize = 0;
2975*5e7646d2SAndroid Build Coastguard Worker 
2976*5e7646d2SAndroid Build Coastguard Worker  /*
2977*5e7646d2SAndroid Build Coastguard Worker   * Copy the debug messages to the log...
2978*5e7646d2SAndroid Build Coastguard Worker   */
2979*5e7646d2SAndroid Build Coastguard Worker 
2980*5e7646d2SAndroid Build Coastguard Worker   message = (cupsd_joblog_t *)cupsArrayFirst(job->history);
2981*5e7646d2SAndroid Build Coastguard Worker   localtime_r(&(message->time), &date);
2982*5e7646d2SAndroid Build Coastguard Worker   strftime(start, sizeof(start), "%X", &date);
2983*5e7646d2SAndroid Build Coastguard Worker 
2984*5e7646d2SAndroid Build Coastguard Worker   message = (cupsd_joblog_t *)cupsArrayLast(job->history);
2985*5e7646d2SAndroid Build Coastguard Worker   localtime_r(&(message->time), &date);
2986*5e7646d2SAndroid Build Coastguard Worker   strftime(end, sizeof(end), "%X", &date);
2987*5e7646d2SAndroid Build Coastguard Worker 
2988*5e7646d2SAndroid Build Coastguard Worker   snprintf(temp, sizeof(temp),
2989*5e7646d2SAndroid Build Coastguard Worker            "[Job %d] The following messages were recorded from %s to %s",
2990*5e7646d2SAndroid Build Coastguard Worker            job->id, start, end);
2991*5e7646d2SAndroid Build Coastguard Worker   cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
2992*5e7646d2SAndroid Build Coastguard Worker 
2993*5e7646d2SAndroid Build Coastguard Worker   for (message = (cupsd_joblog_t *)cupsArrayFirst(job->history);
2994*5e7646d2SAndroid Build Coastguard Worker        message;
2995*5e7646d2SAndroid Build Coastguard Worker        message = (cupsd_joblog_t *)cupsArrayNext(job->history))
2996*5e7646d2SAndroid Build Coastguard Worker     cupsdWriteErrorLog(CUPSD_LOG_DEBUG, message->message);
2997*5e7646d2SAndroid Build Coastguard Worker 
2998*5e7646d2SAndroid Build Coastguard Worker   snprintf(temp, sizeof(temp), "[Job %d] End of messages", job->id);
2999*5e7646d2SAndroid Build Coastguard Worker   cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
3000*5e7646d2SAndroid Build Coastguard Worker 
3001*5e7646d2SAndroid Build Coastguard Worker  /*
3002*5e7646d2SAndroid Build Coastguard Worker   * Log the printer state values...
3003*5e7646d2SAndroid Build Coastguard Worker   */
3004*5e7646d2SAndroid Build Coastguard Worker 
3005*5e7646d2SAndroid Build Coastguard Worker   if ((printer = job->printer) == NULL)
3006*5e7646d2SAndroid Build Coastguard Worker     printer = cupsdFindDest(job->dest);
3007*5e7646d2SAndroid Build Coastguard Worker 
3008*5e7646d2SAndroid Build Coastguard Worker   if (printer)
3009*5e7646d2SAndroid Build Coastguard Worker   {
3010*5e7646d2SAndroid Build Coastguard Worker     snprintf(temp, sizeof(temp), "[Job %d] printer-state=%d(%s)", job->id,
3011*5e7646d2SAndroid Build Coastguard Worker              printer->state,
3012*5e7646d2SAndroid Build Coastguard Worker 	     printer->state == IPP_PRINTER_IDLE ? "idle" :
3013*5e7646d2SAndroid Build Coastguard Worker 	         printer->state == IPP_PRINTER_PROCESSING ? "processing" :
3014*5e7646d2SAndroid Build Coastguard Worker 		 "stopped");
3015*5e7646d2SAndroid Build Coastguard Worker     cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
3016*5e7646d2SAndroid Build Coastguard Worker 
3017*5e7646d2SAndroid Build Coastguard Worker     snprintf(temp, sizeof(temp), "[Job %d] printer-state-message=\"%s\"",
3018*5e7646d2SAndroid Build Coastguard Worker              job->id, printer->state_message);
3019*5e7646d2SAndroid Build Coastguard Worker     cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
3020*5e7646d2SAndroid Build Coastguard Worker 
3021*5e7646d2SAndroid Build Coastguard Worker     snprintf(temp, sizeof(temp), "[Job %d] printer-state-reasons=", job->id);
3022*5e7646d2SAndroid Build Coastguard Worker     ptr = temp + strlen(temp);
3023*5e7646d2SAndroid Build Coastguard Worker     if (printer->num_reasons == 0)
3024*5e7646d2SAndroid Build Coastguard Worker       strlcpy(ptr, "none", sizeof(temp) - (size_t)(ptr - temp));
3025*5e7646d2SAndroid Build Coastguard Worker     else
3026*5e7646d2SAndroid Build Coastguard Worker     {
3027*5e7646d2SAndroid Build Coastguard Worker       for (i = 0;
3028*5e7646d2SAndroid Build Coastguard Worker            i < printer->num_reasons && ptr < (temp + sizeof(temp) - 2);
3029*5e7646d2SAndroid Build Coastguard Worker            i ++)
3030*5e7646d2SAndroid Build Coastguard Worker       {
3031*5e7646d2SAndroid Build Coastguard Worker         if (i)
3032*5e7646d2SAndroid Build Coastguard Worker 	  *ptr++ = ',';
3033*5e7646d2SAndroid Build Coastguard Worker 
3034*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(ptr, printer->reasons[i], sizeof(temp) - (size_t)(ptr - temp));
3035*5e7646d2SAndroid Build Coastguard Worker 	ptr += strlen(ptr);
3036*5e7646d2SAndroid Build Coastguard Worker       }
3037*5e7646d2SAndroid Build Coastguard Worker     }
3038*5e7646d2SAndroid Build Coastguard Worker     cupsdWriteErrorLog(CUPSD_LOG_DEBUG, temp);
3039*5e7646d2SAndroid Build Coastguard Worker   }
3040*5e7646d2SAndroid Build Coastguard Worker 
3041*5e7646d2SAndroid Build Coastguard Worker  /*
3042*5e7646d2SAndroid Build Coastguard Worker   * Restore log file rotation...
3043*5e7646d2SAndroid Build Coastguard Worker   */
3044*5e7646d2SAndroid Build Coastguard Worker 
3045*5e7646d2SAndroid Build Coastguard Worker   MaxLogSize = oldsize;
3046*5e7646d2SAndroid Build Coastguard Worker 
3047*5e7646d2SAndroid Build Coastguard Worker  /*
3048*5e7646d2SAndroid Build Coastguard Worker   * Free all messages...
3049*5e7646d2SAndroid Build Coastguard Worker   */
3050*5e7646d2SAndroid Build Coastguard Worker 
3051*5e7646d2SAndroid Build Coastguard Worker   free_job_history(job);
3052*5e7646d2SAndroid Build Coastguard Worker }
3053*5e7646d2SAndroid Build Coastguard Worker 
3054*5e7646d2SAndroid Build Coastguard Worker 
3055*5e7646d2SAndroid Build Coastguard Worker /*
3056*5e7646d2SAndroid Build Coastguard Worker  * 'free_job_history()' - Free any log history.
3057*5e7646d2SAndroid Build Coastguard Worker  */
3058*5e7646d2SAndroid Build Coastguard Worker 
3059*5e7646d2SAndroid Build Coastguard Worker static void
free_job_history(cupsd_job_t * job)3060*5e7646d2SAndroid Build Coastguard Worker free_job_history(cupsd_job_t *job)	/* I - Job */
3061*5e7646d2SAndroid Build Coastguard Worker {
3062*5e7646d2SAndroid Build Coastguard Worker   char	*message;			/* Current message */
3063*5e7646d2SAndroid Build Coastguard Worker 
3064*5e7646d2SAndroid Build Coastguard Worker 
3065*5e7646d2SAndroid Build Coastguard Worker   if (!job->history)
3066*5e7646d2SAndroid Build Coastguard Worker     return;
3067*5e7646d2SAndroid Build Coastguard Worker 
3068*5e7646d2SAndroid Build Coastguard Worker   for (message = (char *)cupsArrayFirst(job->history);
3069*5e7646d2SAndroid Build Coastguard Worker        message;
3070*5e7646d2SAndroid Build Coastguard Worker        message = (char *)cupsArrayNext(job->history))
3071*5e7646d2SAndroid Build Coastguard Worker     free(message);
3072*5e7646d2SAndroid Build Coastguard Worker 
3073*5e7646d2SAndroid Build Coastguard Worker   cupsArrayDelete(job->history);
3074*5e7646d2SAndroid Build Coastguard Worker   job->history = NULL;
3075*5e7646d2SAndroid Build Coastguard Worker }
3076*5e7646d2SAndroid Build Coastguard Worker 
3077*5e7646d2SAndroid Build Coastguard Worker 
3078*5e7646d2SAndroid Build Coastguard Worker /*
3079*5e7646d2SAndroid Build Coastguard Worker  * 'finalize_job()' - Cleanup after job filter processes and support data.
3080*5e7646d2SAndroid Build Coastguard Worker  */
3081*5e7646d2SAndroid Build Coastguard Worker 
3082*5e7646d2SAndroid Build Coastguard Worker static void
finalize_job(cupsd_job_t * job,int set_job_state)3083*5e7646d2SAndroid Build Coastguard Worker finalize_job(cupsd_job_t *job,		/* I - Job */
3084*5e7646d2SAndroid Build Coastguard Worker              int         set_job_state)	/* I - 1 = set the job state */
3085*5e7646d2SAndroid Build Coastguard Worker {
3086*5e7646d2SAndroid Build Coastguard Worker   ipp_pstate_t		printer_state;	/* New printer state value */
3087*5e7646d2SAndroid Build Coastguard Worker   ipp_jstate_t		job_state;	/* New job state value */
3088*5e7646d2SAndroid Build Coastguard Worker   const char		*message;	/* Message for job state */
3089*5e7646d2SAndroid Build Coastguard Worker   char			buffer[1024];	/* Buffer for formatted messages */
3090*5e7646d2SAndroid Build Coastguard Worker 
3091*5e7646d2SAndroid Build Coastguard Worker 
3092*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "finalize_job(job=%p(%d))", job, job->id);
3093*5e7646d2SAndroid Build Coastguard Worker 
3094*5e7646d2SAndroid Build Coastguard Worker  /*
3095*5e7646d2SAndroid Build Coastguard Worker   * Clear the "connecting-to-device" and "cups-waiting-for-job-completed"
3096*5e7646d2SAndroid Build Coastguard Worker   * reasons, which are only valid when a printer is processing, along with any
3097*5e7646d2SAndroid Build Coastguard Worker   * remote printing job state...
3098*5e7646d2SAndroid Build Coastguard Worker   */
3099*5e7646d2SAndroid Build Coastguard Worker 
3100*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterReasons(job->printer, "-connecting-to-device,"
3101*5e7646d2SAndroid Build Coastguard Worker                                        "cups-waiting-for-job-completed,"
3102*5e7646d2SAndroid Build Coastguard Worker 				       "cups-remote-pending,"
3103*5e7646d2SAndroid Build Coastguard Worker 				       "cups-remote-pending-held,"
3104*5e7646d2SAndroid Build Coastguard Worker 				       "cups-remote-processing,"
3105*5e7646d2SAndroid Build Coastguard Worker 				       "cups-remote-stopped,"
3106*5e7646d2SAndroid Build Coastguard Worker 				       "cups-remote-canceled,"
3107*5e7646d2SAndroid Build Coastguard Worker 				       "cups-remote-aborted,"
3108*5e7646d2SAndroid Build Coastguard Worker 				       "cups-remote-completed");
3109*5e7646d2SAndroid Build Coastguard Worker 
3110*5e7646d2SAndroid Build Coastguard Worker  /*
3111*5e7646d2SAndroid Build Coastguard Worker   * Similarly, clear the "offline-report" reason for non-USB devices since we
3112*5e7646d2SAndroid Build Coastguard Worker   * rarely have current information for network devices...
3113*5e7646d2SAndroid Build Coastguard Worker   */
3114*5e7646d2SAndroid Build Coastguard Worker 
3115*5e7646d2SAndroid Build Coastguard Worker   if (!strstr(job->printer->device_uri, "usb:"))
3116*5e7646d2SAndroid Build Coastguard Worker     cupsdSetPrinterReasons(job->printer, "-offline-report");
3117*5e7646d2SAndroid Build Coastguard Worker 
3118*5e7646d2SAndroid Build Coastguard Worker  /*
3119*5e7646d2SAndroid Build Coastguard Worker   * Free the security profile...
3120*5e7646d2SAndroid Build Coastguard Worker   */
3121*5e7646d2SAndroid Build Coastguard Worker 
3122*5e7646d2SAndroid Build Coastguard Worker   cupsdDestroyProfile(job->profile);
3123*5e7646d2SAndroid Build Coastguard Worker   job->profile = NULL;
3124*5e7646d2SAndroid Build Coastguard Worker   cupsdDestroyProfile(job->bprofile);
3125*5e7646d2SAndroid Build Coastguard Worker   job->bprofile = NULL;
3126*5e7646d2SAndroid Build Coastguard Worker 
3127*5e7646d2SAndroid Build Coastguard Worker  /*
3128*5e7646d2SAndroid Build Coastguard Worker   * Clear the unresponsive job watchdog timers...
3129*5e7646d2SAndroid Build Coastguard Worker   */
3130*5e7646d2SAndroid Build Coastguard Worker 
3131*5e7646d2SAndroid Build Coastguard Worker   job->cancel_time = 0;
3132*5e7646d2SAndroid Build Coastguard Worker   job->kill_time   = 0;
3133*5e7646d2SAndroid Build Coastguard Worker 
3134*5e7646d2SAndroid Build Coastguard Worker  /*
3135*5e7646d2SAndroid Build Coastguard Worker   * Close pipes and status buffer...
3136*5e7646d2SAndroid Build Coastguard Worker   */
3137*5e7646d2SAndroid Build Coastguard Worker 
3138*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->print_pipes);
3139*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->back_pipes);
3140*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->side_pipes);
3141*5e7646d2SAndroid Build Coastguard Worker 
3142*5e7646d2SAndroid Build Coastguard Worker   cupsdRemoveSelect(job->status_pipes[0]);
3143*5e7646d2SAndroid Build Coastguard Worker   cupsdClosePipe(job->status_pipes);
3144*5e7646d2SAndroid Build Coastguard Worker   cupsdStatBufDelete(job->status_buffer);
3145*5e7646d2SAndroid Build Coastguard Worker   job->status_buffer = NULL;
3146*5e7646d2SAndroid Build Coastguard Worker 
3147*5e7646d2SAndroid Build Coastguard Worker  /*
3148*5e7646d2SAndroid Build Coastguard Worker   * Log the final impression (page) count...
3149*5e7646d2SAndroid Build Coastguard Worker   */
3150*5e7646d2SAndroid Build Coastguard Worker 
3151*5e7646d2SAndroid Build Coastguard Worker   snprintf(buffer, sizeof(buffer), "total %d", ippGetInteger(job->impressions, 0));
3152*5e7646d2SAndroid Build Coastguard Worker   cupsdLogPage(job, buffer);
3153*5e7646d2SAndroid Build Coastguard Worker 
3154*5e7646d2SAndroid Build Coastguard Worker  /*
3155*5e7646d2SAndroid Build Coastguard Worker   * Process the exit status...
3156*5e7646d2SAndroid Build Coastguard Worker   */
3157*5e7646d2SAndroid Build Coastguard Worker 
3158*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->state == IPP_PRINTER_PROCESSING)
3159*5e7646d2SAndroid Build Coastguard Worker     printer_state = IPP_PRINTER_IDLE;
3160*5e7646d2SAndroid Build Coastguard Worker   else
3161*5e7646d2SAndroid Build Coastguard Worker     printer_state = job->printer->state;
3162*5e7646d2SAndroid Build Coastguard Worker 
3163*5e7646d2SAndroid Build Coastguard Worker   switch (job_state = job->state_value)
3164*5e7646d2SAndroid Build Coastguard Worker   {
3165*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_PENDING :
3166*5e7646d2SAndroid Build Coastguard Worker         message = "Job paused.";
3167*5e7646d2SAndroid Build Coastguard Worker 	break;
3168*5e7646d2SAndroid Build Coastguard Worker 
3169*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_HELD :
3170*5e7646d2SAndroid Build Coastguard Worker         message = "Job held.";
3171*5e7646d2SAndroid Build Coastguard Worker 	break;
3172*5e7646d2SAndroid Build Coastguard Worker 
3173*5e7646d2SAndroid Build Coastguard Worker     default :
3174*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_PROCESSING :
3175*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_COMPLETED :
3176*5e7646d2SAndroid Build Coastguard Worker 	job_state = IPP_JOB_COMPLETED;
3177*5e7646d2SAndroid Build Coastguard Worker 	message   = "Job completed.";
3178*5e7646d2SAndroid Build Coastguard Worker 
3179*5e7646d2SAndroid Build Coastguard Worker         if (!job->status)
3180*5e7646d2SAndroid Build Coastguard Worker 	  ippSetString(job->attrs, &job->reasons, 0,
3181*5e7646d2SAndroid Build Coastguard Worker 		       "job-completed-successfully");
3182*5e7646d2SAndroid Build Coastguard Worker         break;
3183*5e7646d2SAndroid Build Coastguard Worker 
3184*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_STOPPED :
3185*5e7646d2SAndroid Build Coastguard Worker         message = "Job stopped.";
3186*5e7646d2SAndroid Build Coastguard Worker 
3187*5e7646d2SAndroid Build Coastguard Worker 	ippSetString(job->attrs, &job->reasons, 0, "job-stopped");
3188*5e7646d2SAndroid Build Coastguard Worker 	break;
3189*5e7646d2SAndroid Build Coastguard Worker 
3190*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_CANCELED :
3191*5e7646d2SAndroid Build Coastguard Worker         message = "Job canceled.";
3192*5e7646d2SAndroid Build Coastguard Worker 
3193*5e7646d2SAndroid Build Coastguard Worker 	ippSetString(job->attrs, &job->reasons, 0, "job-canceled-by-user");
3194*5e7646d2SAndroid Build Coastguard Worker 	break;
3195*5e7646d2SAndroid Build Coastguard Worker 
3196*5e7646d2SAndroid Build Coastguard Worker     case IPP_JOB_ABORTED :
3197*5e7646d2SAndroid Build Coastguard Worker         message = "Job aborted.";
3198*5e7646d2SAndroid Build Coastguard Worker 	break;
3199*5e7646d2SAndroid Build Coastguard Worker   }
3200*5e7646d2SAndroid Build Coastguard Worker 
3201*5e7646d2SAndroid Build Coastguard Worker   if (job->status < 0)
3202*5e7646d2SAndroid Build Coastguard Worker   {
3203*5e7646d2SAndroid Build Coastguard Worker    /*
3204*5e7646d2SAndroid Build Coastguard Worker     * Backend had errors...
3205*5e7646d2SAndroid Build Coastguard Worker     */
3206*5e7646d2SAndroid Build Coastguard Worker 
3207*5e7646d2SAndroid Build Coastguard Worker     int exit_code;			/* Exit code from backend */
3208*5e7646d2SAndroid Build Coastguard Worker 
3209*5e7646d2SAndroid Build Coastguard Worker    /*
3210*5e7646d2SAndroid Build Coastguard Worker     * Convert the status to an exit code.  Due to the way the W* macros are
3211*5e7646d2SAndroid Build Coastguard Worker     * implemented on macOS (bug?), we have to store the exit status in a
3212*5e7646d2SAndroid Build Coastguard Worker     * variable first and then convert...
3213*5e7646d2SAndroid Build Coastguard Worker     */
3214*5e7646d2SAndroid Build Coastguard Worker 
3215*5e7646d2SAndroid Build Coastguard Worker     exit_code = -job->status;
3216*5e7646d2SAndroid Build Coastguard Worker     if (WIFEXITED(exit_code))
3217*5e7646d2SAndroid Build Coastguard Worker       exit_code = WEXITSTATUS(exit_code);
3218*5e7646d2SAndroid Build Coastguard Worker     else
3219*5e7646d2SAndroid Build Coastguard Worker     {
3220*5e7646d2SAndroid Build Coastguard Worker       ippSetString(job->attrs, &job->reasons, 0, "cups-backend-crashed");
3221*5e7646d2SAndroid Build Coastguard Worker       exit_code = job->status;
3222*5e7646d2SAndroid Build Coastguard Worker     }
3223*5e7646d2SAndroid Build Coastguard Worker 
3224*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_WARN, "Backend returned status %d (%s)",
3225*5e7646d2SAndroid Build Coastguard Worker 		exit_code,
3226*5e7646d2SAndroid Build Coastguard Worker 		exit_code == CUPS_BACKEND_FAILED ? "failed" :
3227*5e7646d2SAndroid Build Coastguard Worker 		    exit_code == CUPS_BACKEND_AUTH_REQUIRED ?
3228*5e7646d2SAndroid Build Coastguard Worker 			"authentication required" :
3229*5e7646d2SAndroid Build Coastguard Worker 		    exit_code == CUPS_BACKEND_HOLD ? "hold job" :
3230*5e7646d2SAndroid Build Coastguard Worker 		    exit_code == CUPS_BACKEND_STOP ? "stop printer" :
3231*5e7646d2SAndroid Build Coastguard Worker 		    exit_code == CUPS_BACKEND_CANCEL ? "cancel job" :
3232*5e7646d2SAndroid Build Coastguard Worker 		    exit_code == CUPS_BACKEND_RETRY ? "retry job later" :
3233*5e7646d2SAndroid Build Coastguard Worker 		    exit_code == CUPS_BACKEND_RETRY_CURRENT ? "retry job immediately" :
3234*5e7646d2SAndroid Build Coastguard Worker 		    exit_code < 0 ? "crashed" : "unknown");
3235*5e7646d2SAndroid Build Coastguard Worker 
3236*5e7646d2SAndroid Build Coastguard Worker    /*
3237*5e7646d2SAndroid Build Coastguard Worker     * Do what needs to be done...
3238*5e7646d2SAndroid Build Coastguard Worker     */
3239*5e7646d2SAndroid Build Coastguard Worker 
3240*5e7646d2SAndroid Build Coastguard Worker     switch (exit_code)
3241*5e7646d2SAndroid Build Coastguard Worker     {
3242*5e7646d2SAndroid Build Coastguard Worker       default :
3243*5e7646d2SAndroid Build Coastguard Worker       case CUPS_BACKEND_FAILED :
3244*5e7646d2SAndroid Build Coastguard Worker          /*
3245*5e7646d2SAndroid Build Coastguard Worker 	  * Backend failure, use the error-policy to determine how to
3246*5e7646d2SAndroid Build Coastguard Worker 	  * act...
3247*5e7646d2SAndroid Build Coastguard Worker 	  */
3248*5e7646d2SAndroid Build Coastguard Worker 
3249*5e7646d2SAndroid Build Coastguard Worker           if (job->dtype & CUPS_PRINTER_CLASS)
3250*5e7646d2SAndroid Build Coastguard Worker 	  {
3251*5e7646d2SAndroid Build Coastguard Worker 	   /*
3252*5e7646d2SAndroid Build Coastguard Worker 	    * Queued on a class - mark the job as pending and we'll retry on
3253*5e7646d2SAndroid Build Coastguard Worker 	    * another printer...
3254*5e7646d2SAndroid Build Coastguard Worker 	    */
3255*5e7646d2SAndroid Build Coastguard Worker 
3256*5e7646d2SAndroid Build Coastguard Worker             if (job_state == IPP_JOB_COMPLETED)
3257*5e7646d2SAndroid Build Coastguard Worker 	    {
3258*5e7646d2SAndroid Build Coastguard Worker 	      job_state = IPP_JOB_PENDING;
3259*5e7646d2SAndroid Build Coastguard Worker 	      message   = "Retrying job on another printer.";
3260*5e7646d2SAndroid Build Coastguard Worker 
3261*5e7646d2SAndroid Build Coastguard Worker 	      ippSetString(job->attrs, &job->reasons, 0,
3262*5e7646d2SAndroid Build Coastguard Worker 	                   "resources-are-not-ready");
3263*5e7646d2SAndroid Build Coastguard Worker 	    }
3264*5e7646d2SAndroid Build Coastguard Worker           }
3265*5e7646d2SAndroid Build Coastguard Worker 	  else if (!strcmp(job->printer->error_policy, "retry-current-job"))
3266*5e7646d2SAndroid Build Coastguard Worker 	  {
3267*5e7646d2SAndroid Build Coastguard Worker 	   /*
3268*5e7646d2SAndroid Build Coastguard Worker 	    * The error policy is "retry-current-job" - mark the job as pending
3269*5e7646d2SAndroid Build Coastguard Worker 	    * and we'll retry on the same printer...
3270*5e7646d2SAndroid Build Coastguard Worker 	    */
3271*5e7646d2SAndroid Build Coastguard Worker 
3272*5e7646d2SAndroid Build Coastguard Worker             if (job_state == IPP_JOB_COMPLETED)
3273*5e7646d2SAndroid Build Coastguard Worker 	    {
3274*5e7646d2SAndroid Build Coastguard Worker 	      job_state = IPP_JOB_PENDING;
3275*5e7646d2SAndroid Build Coastguard Worker 	      message   = "Retrying job on same printer.";
3276*5e7646d2SAndroid Build Coastguard Worker 
3277*5e7646d2SAndroid Build Coastguard Worker 	      ippSetString(job->attrs, &job->reasons, 0, "none");
3278*5e7646d2SAndroid Build Coastguard Worker 	    }
3279*5e7646d2SAndroid Build Coastguard Worker           }
3280*5e7646d2SAndroid Build Coastguard Worker 	  else if ((job->printer->type & CUPS_PRINTER_FAX) ||
3281*5e7646d2SAndroid Build Coastguard Worker         	   !strcmp(job->printer->error_policy, "retry-job"))
3282*5e7646d2SAndroid Build Coastguard Worker 	  {
3283*5e7646d2SAndroid Build Coastguard Worker             if (job_state == IPP_JOB_COMPLETED)
3284*5e7646d2SAndroid Build Coastguard Worker 	    {
3285*5e7646d2SAndroid Build Coastguard Worker 	     /*
3286*5e7646d2SAndroid Build Coastguard Worker 	      * The job was queued on a fax or the error policy is "retry-job" -
3287*5e7646d2SAndroid Build Coastguard Worker 	      * hold the job if the number of retries is less than the
3288*5e7646d2SAndroid Build Coastguard Worker 	      * JobRetryLimit, otherwise abort the job.
3289*5e7646d2SAndroid Build Coastguard Worker 	      */
3290*5e7646d2SAndroid Build Coastguard Worker 
3291*5e7646d2SAndroid Build Coastguard Worker 	      job->tries ++;
3292*5e7646d2SAndroid Build Coastguard Worker 
3293*5e7646d2SAndroid Build Coastguard Worker 	      if (job->tries > JobRetryLimit && JobRetryLimit > 0)
3294*5e7646d2SAndroid Build Coastguard Worker 	      {
3295*5e7646d2SAndroid Build Coastguard Worker 	       /*
3296*5e7646d2SAndroid Build Coastguard Worker 		* Too many tries...
3297*5e7646d2SAndroid Build Coastguard Worker 		*/
3298*5e7646d2SAndroid Build Coastguard Worker 
3299*5e7646d2SAndroid Build Coastguard Worker 		snprintf(buffer, sizeof(buffer),
3300*5e7646d2SAndroid Build Coastguard Worker 			 "Job aborted after %d unsuccessful attempts.",
3301*5e7646d2SAndroid Build Coastguard Worker 			 JobRetryLimit);
3302*5e7646d2SAndroid Build Coastguard Worker 		job_state = IPP_JOB_ABORTED;
3303*5e7646d2SAndroid Build Coastguard Worker 		message   = buffer;
3304*5e7646d2SAndroid Build Coastguard Worker 
3305*5e7646d2SAndroid Build Coastguard Worker 		ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system");
3306*5e7646d2SAndroid Build Coastguard Worker 	      }
3307*5e7646d2SAndroid Build Coastguard Worker 	      else
3308*5e7646d2SAndroid Build Coastguard Worker 	      {
3309*5e7646d2SAndroid Build Coastguard Worker 	       /*
3310*5e7646d2SAndroid Build Coastguard Worker 		* Try again in N seconds...
3311*5e7646d2SAndroid Build Coastguard Worker 		*/
3312*5e7646d2SAndroid Build Coastguard Worker 
3313*5e7646d2SAndroid Build Coastguard Worker 		snprintf(buffer, sizeof(buffer),
3314*5e7646d2SAndroid Build Coastguard Worker 			 "Job held for %d seconds since it could not be sent.",
3315*5e7646d2SAndroid Build Coastguard Worker 			 JobRetryInterval);
3316*5e7646d2SAndroid Build Coastguard Worker 
3317*5e7646d2SAndroid Build Coastguard Worker 		job->hold_until = time(NULL) + JobRetryInterval;
3318*5e7646d2SAndroid Build Coastguard Worker 		job_state       = IPP_JOB_HELD;
3319*5e7646d2SAndroid Build Coastguard Worker 		message         = buffer;
3320*5e7646d2SAndroid Build Coastguard Worker 
3321*5e7646d2SAndroid Build Coastguard Worker 		ippSetString(job->attrs, &job->reasons, 0,
3322*5e7646d2SAndroid Build Coastguard Worker 		             "resources-are-not-ready");
3323*5e7646d2SAndroid Build Coastguard Worker 	      }
3324*5e7646d2SAndroid Build Coastguard Worker             }
3325*5e7646d2SAndroid Build Coastguard Worker 	  }
3326*5e7646d2SAndroid Build Coastguard Worker 	  else if (!strcmp(job->printer->error_policy, "abort-job") &&
3327*5e7646d2SAndroid Build Coastguard Worker 	           job_state == IPP_JOB_COMPLETED)
3328*5e7646d2SAndroid Build Coastguard Worker 	  {
3329*5e7646d2SAndroid Build Coastguard Worker 	    job_state = IPP_JOB_ABORTED;
3330*5e7646d2SAndroid Build Coastguard Worker 
3331*5e7646d2SAndroid Build Coastguard Worker 	    if (ErrorLog)
3332*5e7646d2SAndroid Build Coastguard Worker 	    {
3333*5e7646d2SAndroid Build Coastguard Worker 	      snprintf(buffer, sizeof(buffer), "Job aborted due to backend errors; please consult the %s file for details.", ErrorLog);
3334*5e7646d2SAndroid Build Coastguard Worker 	      message = buffer;
3335*5e7646d2SAndroid Build Coastguard Worker             }
3336*5e7646d2SAndroid Build Coastguard Worker             else
3337*5e7646d2SAndroid Build Coastguard Worker 	      message = "Job aborted due to backend errors.";
3338*5e7646d2SAndroid Build Coastguard Worker 
3339*5e7646d2SAndroid Build Coastguard Worker 	    ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system");
3340*5e7646d2SAndroid Build Coastguard Worker 	  }
3341*5e7646d2SAndroid Build Coastguard Worker 	  else if (job->state_value == IPP_JOB_PROCESSING)
3342*5e7646d2SAndroid Build Coastguard Worker           {
3343*5e7646d2SAndroid Build Coastguard Worker             job_state     = IPP_JOB_PENDING;
3344*5e7646d2SAndroid Build Coastguard Worker 	    printer_state = IPP_PRINTER_STOPPED;
3345*5e7646d2SAndroid Build Coastguard Worker 
3346*5e7646d2SAndroid Build Coastguard Worker 	    if (ErrorLog)
3347*5e7646d2SAndroid Build Coastguard Worker 	    {
3348*5e7646d2SAndroid Build Coastguard Worker 	      snprintf(buffer, sizeof(buffer), "Printer stopped due to backend errors; please consult the %s file for details.", ErrorLog);
3349*5e7646d2SAndroid Build Coastguard Worker 	      message = buffer;
3350*5e7646d2SAndroid Build Coastguard Worker             }
3351*5e7646d2SAndroid Build Coastguard Worker             else
3352*5e7646d2SAndroid Build Coastguard Worker 	      message = "Printer stopped due to backend errors.";
3353*5e7646d2SAndroid Build Coastguard Worker 
3354*5e7646d2SAndroid Build Coastguard Worker 	    ippSetString(job->attrs, &job->reasons, 0, "none");
3355*5e7646d2SAndroid Build Coastguard Worker 	  }
3356*5e7646d2SAndroid Build Coastguard Worker           break;
3357*5e7646d2SAndroid Build Coastguard Worker 
3358*5e7646d2SAndroid Build Coastguard Worker       case CUPS_BACKEND_CANCEL :
3359*5e7646d2SAndroid Build Coastguard Worker          /*
3360*5e7646d2SAndroid Build Coastguard Worker 	  * Cancel the job...
3361*5e7646d2SAndroid Build Coastguard Worker 	  */
3362*5e7646d2SAndroid Build Coastguard Worker 
3363*5e7646d2SAndroid Build Coastguard Worker 	  if (job_state == IPP_JOB_COMPLETED)
3364*5e7646d2SAndroid Build Coastguard Worker 	  {
3365*5e7646d2SAndroid Build Coastguard Worker 	    job_state = IPP_JOB_CANCELED;
3366*5e7646d2SAndroid Build Coastguard Worker 	    message   = "Job canceled at printer.";
3367*5e7646d2SAndroid Build Coastguard Worker 
3368*5e7646d2SAndroid Build Coastguard Worker 	    ippSetString(job->attrs, &job->reasons, 0, "canceled-at-device");
3369*5e7646d2SAndroid Build Coastguard Worker 	  }
3370*5e7646d2SAndroid Build Coastguard Worker           break;
3371*5e7646d2SAndroid Build Coastguard Worker 
3372*5e7646d2SAndroid Build Coastguard Worker       case CUPS_BACKEND_HOLD :
3373*5e7646d2SAndroid Build Coastguard Worker 	  if (job_state == IPP_JOB_COMPLETED)
3374*5e7646d2SAndroid Build Coastguard Worker 	  {
3375*5e7646d2SAndroid Build Coastguard Worker 	   /*
3376*5e7646d2SAndroid Build Coastguard Worker 	    * Hold the job...
3377*5e7646d2SAndroid Build Coastguard Worker 	    */
3378*5e7646d2SAndroid Build Coastguard Worker 
3379*5e7646d2SAndroid Build Coastguard Worker 	    const char *reason = ippGetString(job->reasons, 0, NULL);
3380*5e7646d2SAndroid Build Coastguard Worker 
3381*5e7646d2SAndroid Build Coastguard Worker 	    cupsdLogJob(job, CUPSD_LOG_DEBUG, "job-state-reasons=\"%s\"",
3382*5e7646d2SAndroid Build Coastguard Worker 	                reason);
3383*5e7646d2SAndroid Build Coastguard Worker 
3384*5e7646d2SAndroid Build Coastguard Worker 	    if (!reason || strncmp(reason, "account-", 8))
3385*5e7646d2SAndroid Build Coastguard Worker 	    {
3386*5e7646d2SAndroid Build Coastguard Worker 	      cupsdSetJobHoldUntil(job, "indefinite", 1);
3387*5e7646d2SAndroid Build Coastguard Worker 
3388*5e7646d2SAndroid Build Coastguard Worker 	      ippSetString(job->attrs, &job->reasons, 0,
3389*5e7646d2SAndroid Build Coastguard Worker 			   "job-hold-until-specified");
3390*5e7646d2SAndroid Build Coastguard Worker 
3391*5e7646d2SAndroid Build Coastguard Worker 	      if (ErrorLog)
3392*5e7646d2SAndroid Build Coastguard Worker 	      {
3393*5e7646d2SAndroid Build Coastguard Worker 		snprintf(buffer, sizeof(buffer), "Job held indefinitely due to backend errors; please consult the %s file for details.", ErrorLog);
3394*5e7646d2SAndroid Build Coastguard Worker 		message = buffer;
3395*5e7646d2SAndroid Build Coastguard Worker 	      }
3396*5e7646d2SAndroid Build Coastguard Worker 	      else
3397*5e7646d2SAndroid Build Coastguard Worker 		message = "Job held indefinitely due to backend errors.";
3398*5e7646d2SAndroid Build Coastguard Worker             }
3399*5e7646d2SAndroid Build Coastguard Worker             else if (!strcmp(reason, "account-info-needed"))
3400*5e7646d2SAndroid Build Coastguard Worker             {
3401*5e7646d2SAndroid Build Coastguard Worker 	      cupsdSetJobHoldUntil(job, "indefinite", 0);
3402*5e7646d2SAndroid Build Coastguard Worker 
3403*5e7646d2SAndroid Build Coastguard Worker 	      message = "Job held indefinitely - account information is required.";
3404*5e7646d2SAndroid Build Coastguard Worker             }
3405*5e7646d2SAndroid Build Coastguard Worker             else if (!strcmp(reason, "account-closed"))
3406*5e7646d2SAndroid Build Coastguard Worker             {
3407*5e7646d2SAndroid Build Coastguard Worker 	      cupsdSetJobHoldUntil(job, "indefinite", 0);
3408*5e7646d2SAndroid Build Coastguard Worker 
3409*5e7646d2SAndroid Build Coastguard Worker 	      message = "Job held indefinitely - account has been closed.";
3410*5e7646d2SAndroid Build Coastguard Worker 	    }
3411*5e7646d2SAndroid Build Coastguard Worker             else if (!strcmp(reason, "account-limit-reached"))
3412*5e7646d2SAndroid Build Coastguard Worker             {
3413*5e7646d2SAndroid Build Coastguard Worker 	      cupsdSetJobHoldUntil(job, "indefinite", 0);
3414*5e7646d2SAndroid Build Coastguard Worker 
3415*5e7646d2SAndroid Build Coastguard Worker 	      message = "Job held indefinitely - account limit has been reached.";
3416*5e7646d2SAndroid Build Coastguard Worker 	    }
3417*5e7646d2SAndroid Build Coastguard Worker             else
3418*5e7646d2SAndroid Build Coastguard Worker             {
3419*5e7646d2SAndroid Build Coastguard Worker 	      cupsdSetJobHoldUntil(job, "indefinite", 0);
3420*5e7646d2SAndroid Build Coastguard Worker 
3421*5e7646d2SAndroid Build Coastguard Worker 	      message = "Job held indefinitely - account authorization failed.";
3422*5e7646d2SAndroid Build Coastguard Worker 	    }
3423*5e7646d2SAndroid Build Coastguard Worker 
3424*5e7646d2SAndroid Build Coastguard Worker 	    job_state = IPP_JOB_HELD;
3425*5e7646d2SAndroid Build Coastguard Worker           }
3426*5e7646d2SAndroid Build Coastguard Worker           break;
3427*5e7646d2SAndroid Build Coastguard Worker 
3428*5e7646d2SAndroid Build Coastguard Worker       case CUPS_BACKEND_STOP :
3429*5e7646d2SAndroid Build Coastguard Worker          /*
3430*5e7646d2SAndroid Build Coastguard Worker 	  * Stop the printer...
3431*5e7646d2SAndroid Build Coastguard Worker 	  */
3432*5e7646d2SAndroid Build Coastguard Worker 
3433*5e7646d2SAndroid Build Coastguard Worker           if (job_state == IPP_JSTATE_CANCELED || job_state == IPP_JSTATE_ABORTED)
3434*5e7646d2SAndroid Build Coastguard Worker           {
3435*5e7646d2SAndroid Build Coastguard Worker             cupsdLogJob(job, CUPSD_LOG_INFO, "Ignored STOP from backend since the job is %s.", job_state == IPP_JSTATE_CANCELED ? "canceled" : "aborted");
3436*5e7646d2SAndroid Build Coastguard Worker             break;
3437*5e7646d2SAndroid Build Coastguard Worker 	  }
3438*5e7646d2SAndroid Build Coastguard Worker 
3439*5e7646d2SAndroid Build Coastguard Worker 	  printer_state = IPP_PRINTER_STOPPED;
3440*5e7646d2SAndroid Build Coastguard Worker 
3441*5e7646d2SAndroid Build Coastguard Worker 	  if (ErrorLog)
3442*5e7646d2SAndroid Build Coastguard Worker 	  {
3443*5e7646d2SAndroid Build Coastguard Worker 	    snprintf(buffer, sizeof(buffer), "Printer stopped due to backend errors; please consult the %s file for details.", ErrorLog);
3444*5e7646d2SAndroid Build Coastguard Worker 	    message = buffer;
3445*5e7646d2SAndroid Build Coastguard Worker 	  }
3446*5e7646d2SAndroid Build Coastguard Worker 	  else
3447*5e7646d2SAndroid Build Coastguard Worker 	    message = "Printer stopped due to backend errors.";
3448*5e7646d2SAndroid Build Coastguard Worker 
3449*5e7646d2SAndroid Build Coastguard Worker 	  if (job_state == IPP_JOB_COMPLETED)
3450*5e7646d2SAndroid Build Coastguard Worker 	  {
3451*5e7646d2SAndroid Build Coastguard Worker 	    job_state = IPP_JOB_PENDING;
3452*5e7646d2SAndroid Build Coastguard Worker 
3453*5e7646d2SAndroid Build Coastguard Worker 	    ippSetString(job->attrs, &job->reasons, 0, "resources-are-not-ready");
3454*5e7646d2SAndroid Build Coastguard Worker 	  }
3455*5e7646d2SAndroid Build Coastguard Worker           break;
3456*5e7646d2SAndroid Build Coastguard Worker 
3457*5e7646d2SAndroid Build Coastguard Worker       case CUPS_BACKEND_AUTH_REQUIRED :
3458*5e7646d2SAndroid Build Coastguard Worker          /*
3459*5e7646d2SAndroid Build Coastguard Worker 	  * Hold the job for authentication...
3460*5e7646d2SAndroid Build Coastguard Worker 	  */
3461*5e7646d2SAndroid Build Coastguard Worker 
3462*5e7646d2SAndroid Build Coastguard Worker 	  if (job_state == IPP_JOB_COMPLETED)
3463*5e7646d2SAndroid Build Coastguard Worker 	  {
3464*5e7646d2SAndroid Build Coastguard Worker 	    cupsdSetJobHoldUntil(job, "auth-info-required", 1);
3465*5e7646d2SAndroid Build Coastguard Worker 
3466*5e7646d2SAndroid Build Coastguard Worker 	    job_state = IPP_JOB_HELD;
3467*5e7646d2SAndroid Build Coastguard Worker 	    message   = "Job held for authentication.";
3468*5e7646d2SAndroid Build Coastguard Worker 
3469*5e7646d2SAndroid Build Coastguard Worker             if (strncmp(job->reasons->values[0].string.text, "account-", 8))
3470*5e7646d2SAndroid Build Coastguard Worker 	      ippSetString(job->attrs, &job->reasons, 0,
3471*5e7646d2SAndroid Build Coastguard Worker 			   "cups-held-for-authentication");
3472*5e7646d2SAndroid Build Coastguard Worker           }
3473*5e7646d2SAndroid Build Coastguard Worker           break;
3474*5e7646d2SAndroid Build Coastguard Worker 
3475*5e7646d2SAndroid Build Coastguard Worker       case CUPS_BACKEND_RETRY :
3476*5e7646d2SAndroid Build Coastguard Worker 	  if (job_state == IPP_JOB_COMPLETED)
3477*5e7646d2SAndroid Build Coastguard Worker 	  {
3478*5e7646d2SAndroid Build Coastguard Worker 	   /*
3479*5e7646d2SAndroid Build Coastguard Worker 	    * Hold the job if the number of retries is less than the
3480*5e7646d2SAndroid Build Coastguard Worker 	    * JobRetryLimit, otherwise abort the job.
3481*5e7646d2SAndroid Build Coastguard Worker 	    */
3482*5e7646d2SAndroid Build Coastguard Worker 
3483*5e7646d2SAndroid Build Coastguard Worker 	    job->tries ++;
3484*5e7646d2SAndroid Build Coastguard Worker 
3485*5e7646d2SAndroid Build Coastguard Worker 	    if (job->tries > JobRetryLimit && JobRetryLimit > 0)
3486*5e7646d2SAndroid Build Coastguard Worker 	    {
3487*5e7646d2SAndroid Build Coastguard Worker 	     /*
3488*5e7646d2SAndroid Build Coastguard Worker 	      * Too many tries...
3489*5e7646d2SAndroid Build Coastguard Worker 	      */
3490*5e7646d2SAndroid Build Coastguard Worker 
3491*5e7646d2SAndroid Build Coastguard Worker 	      snprintf(buffer, sizeof(buffer),
3492*5e7646d2SAndroid Build Coastguard Worker 		       "Job aborted after %d unsuccessful attempts.",
3493*5e7646d2SAndroid Build Coastguard Worker 		       JobRetryLimit);
3494*5e7646d2SAndroid Build Coastguard Worker 	      job_state = IPP_JOB_ABORTED;
3495*5e7646d2SAndroid Build Coastguard Worker 	      message   = buffer;
3496*5e7646d2SAndroid Build Coastguard Worker 
3497*5e7646d2SAndroid Build Coastguard Worker 	      ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system");
3498*5e7646d2SAndroid Build Coastguard Worker 	    }
3499*5e7646d2SAndroid Build Coastguard Worker 	    else
3500*5e7646d2SAndroid Build Coastguard Worker 	    {
3501*5e7646d2SAndroid Build Coastguard Worker 	     /*
3502*5e7646d2SAndroid Build Coastguard Worker 	      * Try again in N seconds...
3503*5e7646d2SAndroid Build Coastguard Worker 	      */
3504*5e7646d2SAndroid Build Coastguard Worker 
3505*5e7646d2SAndroid Build Coastguard Worker 	      snprintf(buffer, sizeof(buffer),
3506*5e7646d2SAndroid Build Coastguard Worker 		       "Job held for %d seconds since it could not be sent.",
3507*5e7646d2SAndroid Build Coastguard Worker 		       JobRetryInterval);
3508*5e7646d2SAndroid Build Coastguard Worker 
3509*5e7646d2SAndroid Build Coastguard Worker 	      job->hold_until = time(NULL) + JobRetryInterval;
3510*5e7646d2SAndroid Build Coastguard Worker 	      job_state       = IPP_JOB_HELD;
3511*5e7646d2SAndroid Build Coastguard Worker 	      message         = buffer;
3512*5e7646d2SAndroid Build Coastguard Worker 
3513*5e7646d2SAndroid Build Coastguard Worker 	      ippSetString(job->attrs, &job->reasons, 0,
3514*5e7646d2SAndroid Build Coastguard Worker 	                   "resources-are-not-ready");
3515*5e7646d2SAndroid Build Coastguard Worker 	    }
3516*5e7646d2SAndroid Build Coastguard Worker 	  }
3517*5e7646d2SAndroid Build Coastguard Worker           break;
3518*5e7646d2SAndroid Build Coastguard Worker 
3519*5e7646d2SAndroid Build Coastguard Worker       case CUPS_BACKEND_RETRY_CURRENT :
3520*5e7646d2SAndroid Build Coastguard Worker 	 /*
3521*5e7646d2SAndroid Build Coastguard Worker 	  * Mark the job as pending and retry on the same printer...
3522*5e7646d2SAndroid Build Coastguard Worker 	  */
3523*5e7646d2SAndroid Build Coastguard Worker 
3524*5e7646d2SAndroid Build Coastguard Worker 	  if (job_state == IPP_JOB_COMPLETED)
3525*5e7646d2SAndroid Build Coastguard Worker 	  {
3526*5e7646d2SAndroid Build Coastguard Worker 	    job_state = IPP_JOB_PENDING;
3527*5e7646d2SAndroid Build Coastguard Worker 	    message   = "Retrying job on same printer.";
3528*5e7646d2SAndroid Build Coastguard Worker 
3529*5e7646d2SAndroid Build Coastguard Worker 	    ippSetString(job->attrs, &job->reasons, 0, "none");
3530*5e7646d2SAndroid Build Coastguard Worker 	  }
3531*5e7646d2SAndroid Build Coastguard Worker           break;
3532*5e7646d2SAndroid Build Coastguard Worker     }
3533*5e7646d2SAndroid Build Coastguard Worker   }
3534*5e7646d2SAndroid Build Coastguard Worker   else if (job->status > 0)
3535*5e7646d2SAndroid Build Coastguard Worker   {
3536*5e7646d2SAndroid Build Coastguard Worker    /*
3537*5e7646d2SAndroid Build Coastguard Worker     * Filter had errors; stop job...
3538*5e7646d2SAndroid Build Coastguard Worker     */
3539*5e7646d2SAndroid Build Coastguard Worker 
3540*5e7646d2SAndroid Build Coastguard Worker     if (job_state == IPP_JOB_COMPLETED)
3541*5e7646d2SAndroid Build Coastguard Worker     {
3542*5e7646d2SAndroid Build Coastguard Worker       job_state = IPP_JOB_STOPPED;
3543*5e7646d2SAndroid Build Coastguard Worker 
3544*5e7646d2SAndroid Build Coastguard Worker       if (ErrorLog)
3545*5e7646d2SAndroid Build Coastguard Worker       {
3546*5e7646d2SAndroid Build Coastguard Worker 	snprintf(buffer, sizeof(buffer), "Job stopped due to filter errors; please consult the %s file for details.", ErrorLog);
3547*5e7646d2SAndroid Build Coastguard Worker 	message = buffer;
3548*5e7646d2SAndroid Build Coastguard Worker       }
3549*5e7646d2SAndroid Build Coastguard Worker       else
3550*5e7646d2SAndroid Build Coastguard Worker 	message = "Job stopped due to filter errors.";
3551*5e7646d2SAndroid Build Coastguard Worker 
3552*5e7646d2SAndroid Build Coastguard Worker       if (WIFSIGNALED(job->status))
3553*5e7646d2SAndroid Build Coastguard Worker 	ippSetString(job->attrs, &job->reasons, 0, "cups-filter-crashed");
3554*5e7646d2SAndroid Build Coastguard Worker       else
3555*5e7646d2SAndroid Build Coastguard Worker 	ippSetString(job->attrs, &job->reasons, 0, "job-completed-with-errors");
3556*5e7646d2SAndroid Build Coastguard Worker     }
3557*5e7646d2SAndroid Build Coastguard Worker   }
3558*5e7646d2SAndroid Build Coastguard Worker 
3559*5e7646d2SAndroid Build Coastguard Worker  /*
3560*5e7646d2SAndroid Build Coastguard Worker   * Update the printer and job state.
3561*5e7646d2SAndroid Build Coastguard Worker   */
3562*5e7646d2SAndroid Build Coastguard Worker 
3563*5e7646d2SAndroid Build Coastguard Worker   if (set_job_state && job_state != job->state_value)
3564*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, job_state, CUPSD_JOB_DEFAULT, "%s", message);
3565*5e7646d2SAndroid Build Coastguard Worker 
3566*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterState(job->printer, printer_state,
3567*5e7646d2SAndroid Build Coastguard Worker                        printer_state == IPP_PRINTER_STOPPED);
3568*5e7646d2SAndroid Build Coastguard Worker   update_job_attrs(job, 0);
3569*5e7646d2SAndroid Build Coastguard Worker 
3570*5e7646d2SAndroid Build Coastguard Worker   if (job->history)
3571*5e7646d2SAndroid Build Coastguard Worker   {
3572*5e7646d2SAndroid Build Coastguard Worker     if (job->status &&
3573*5e7646d2SAndroid Build Coastguard Worker         (job->state_value == IPP_JOB_ABORTED ||
3574*5e7646d2SAndroid Build Coastguard Worker          job->state_value == IPP_JOB_STOPPED))
3575*5e7646d2SAndroid Build Coastguard Worker       dump_job_history(job);
3576*5e7646d2SAndroid Build Coastguard Worker     else
3577*5e7646d2SAndroid Build Coastguard Worker       free_job_history(job);
3578*5e7646d2SAndroid Build Coastguard Worker   }
3579*5e7646d2SAndroid Build Coastguard Worker 
3580*5e7646d2SAndroid Build Coastguard Worker   cupsArrayRemove(PrintingJobs, job);
3581*5e7646d2SAndroid Build Coastguard Worker 
3582*5e7646d2SAndroid Build Coastguard Worker  /*
3583*5e7646d2SAndroid Build Coastguard Worker   * Clear informational messages...
3584*5e7646d2SAndroid Build Coastguard Worker   */
3585*5e7646d2SAndroid Build Coastguard Worker 
3586*5e7646d2SAndroid Build Coastguard Worker   if (job->status_level > CUPSD_LOG_ERROR)
3587*5e7646d2SAndroid Build Coastguard Worker     job->printer->state_message[0] = '\0';
3588*5e7646d2SAndroid Build Coastguard Worker 
3589*5e7646d2SAndroid Build Coastguard Worker  /*
3590*5e7646d2SAndroid Build Coastguard Worker   * Apply any PPD updates...
3591*5e7646d2SAndroid Build Coastguard Worker   */
3592*5e7646d2SAndroid Build Coastguard Worker 
3593*5e7646d2SAndroid Build Coastguard Worker   if (job->num_keywords)
3594*5e7646d2SAndroid Build Coastguard Worker   {
3595*5e7646d2SAndroid Build Coastguard Worker     if (cupsdUpdatePrinterPPD(job->printer, job->num_keywords, job->keywords))
3596*5e7646d2SAndroid Build Coastguard Worker       cupsdSetPrinterAttrs(job->printer);
3597*5e7646d2SAndroid Build Coastguard Worker 
3598*5e7646d2SAndroid Build Coastguard Worker     cupsFreeOptions(job->num_keywords, job->keywords);
3599*5e7646d2SAndroid Build Coastguard Worker 
3600*5e7646d2SAndroid Build Coastguard Worker     job->num_keywords = 0;
3601*5e7646d2SAndroid Build Coastguard Worker     job->keywords     = NULL;
3602*5e7646d2SAndroid Build Coastguard Worker   }
3603*5e7646d2SAndroid Build Coastguard Worker 
3604*5e7646d2SAndroid Build Coastguard Worker  /*
3605*5e7646d2SAndroid Build Coastguard Worker   * Clear the printer <-> job association...
3606*5e7646d2SAndroid Build Coastguard Worker   */
3607*5e7646d2SAndroid Build Coastguard Worker 
3608*5e7646d2SAndroid Build Coastguard Worker   job->printer->job = NULL;
3609*5e7646d2SAndroid Build Coastguard Worker   job->printer      = NULL;
3610*5e7646d2SAndroid Build Coastguard Worker }
3611*5e7646d2SAndroid Build Coastguard Worker 
3612*5e7646d2SAndroid Build Coastguard Worker 
3613*5e7646d2SAndroid Build Coastguard Worker /*
3614*5e7646d2SAndroid Build Coastguard Worker  * 'get_options()' - Get a string containing the job options.
3615*5e7646d2SAndroid Build Coastguard Worker  */
3616*5e7646d2SAndroid Build Coastguard Worker 
3617*5e7646d2SAndroid Build Coastguard Worker static char *				/* O - Options string */
get_options(cupsd_job_t * job,int banner_page,char * copies,size_t copies_size,char * title,size_t title_size)3618*5e7646d2SAndroid Build Coastguard Worker get_options(cupsd_job_t *job,		/* I - Job */
3619*5e7646d2SAndroid Build Coastguard Worker             int         banner_page,	/* I - Printing a banner page? */
3620*5e7646d2SAndroid Build Coastguard Worker 	    char        *copies,	/* I - Copies buffer */
3621*5e7646d2SAndroid Build Coastguard Worker 	    size_t      copies_size,	/* I - Size of copies buffer */
3622*5e7646d2SAndroid Build Coastguard Worker 	    char        *title,		/* I - Title buffer */
3623*5e7646d2SAndroid Build Coastguard Worker 	    size_t      title_size)	/* I - Size of title buffer */
3624*5e7646d2SAndroid Build Coastguard Worker {
3625*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
3626*5e7646d2SAndroid Build Coastguard Worker   size_t		newlength;	/* New option buffer length */
3627*5e7646d2SAndroid Build Coastguard Worker   char			*optptr,	/* Pointer to options */
3628*5e7646d2SAndroid Build Coastguard Worker 			*valptr;	/* Pointer in value string */
3629*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
3630*5e7646d2SAndroid Build Coastguard Worker   _ppd_cache_t		*pc;		/* PPD cache and mapping data */
3631*5e7646d2SAndroid Build Coastguard Worker   int			num_pwgppds;	/* Number of PWG->PPD options */
3632*5e7646d2SAndroid Build Coastguard Worker   cups_option_t		*pwgppds,	/* PWG->PPD options */
3633*5e7646d2SAndroid Build Coastguard Worker 			*pwgppd,	/* Current PWG->PPD option */
3634*5e7646d2SAndroid Build Coastguard Worker 			*preset;	/* Current preset option */
3635*5e7646d2SAndroid Build Coastguard Worker   int			print_color_mode,
3636*5e7646d2SAndroid Build Coastguard Worker 					/* Output mode (if any) */
3637*5e7646d2SAndroid Build Coastguard Worker 			print_quality;	/* Print quality (if any) */
3638*5e7646d2SAndroid Build Coastguard Worker   const char		*ppd;		/* PPD option choice */
3639*5e7646d2SAndroid Build Coastguard Worker   int			exact;		/* Did we get an exact match? */
3640*5e7646d2SAndroid Build Coastguard Worker   static char		*options = NULL;/* Full list of options */
3641*5e7646d2SAndroid Build Coastguard Worker   static size_t		optlength = 0;	/* Length of option buffer */
3642*5e7646d2SAndroid Build Coastguard Worker 
3643*5e7646d2SAndroid Build Coastguard Worker 
3644*5e7646d2SAndroid Build Coastguard Worker  /*
3645*5e7646d2SAndroid Build Coastguard Worker   * Building the options string is harder than it needs to be, but for the
3646*5e7646d2SAndroid Build Coastguard Worker   * moment we need to pass strings for command-line args and not IPP attribute
3647*5e7646d2SAndroid Build Coastguard Worker   * pointers... :)
3648*5e7646d2SAndroid Build Coastguard Worker   *
3649*5e7646d2SAndroid Build Coastguard Worker   * First build an options array for any PWG->PPD mapped option/choice pairs.
3650*5e7646d2SAndroid Build Coastguard Worker   */
3651*5e7646d2SAndroid Build Coastguard Worker 
3652*5e7646d2SAndroid Build Coastguard Worker   pc          = job->printer->pc;
3653*5e7646d2SAndroid Build Coastguard Worker   num_pwgppds = 0;
3654*5e7646d2SAndroid Build Coastguard Worker   pwgppds     = NULL;
3655*5e7646d2SAndroid Build Coastguard Worker 
3656*5e7646d2SAndroid Build Coastguard Worker   if (pc &&
3657*5e7646d2SAndroid Build Coastguard Worker       !ippFindAttribute(job->attrs, "com.apple.print.DocumentTicket.PMSpoolFormat", IPP_TAG_ZERO) &&
3658*5e7646d2SAndroid Build Coastguard Worker       !ippFindAttribute(job->attrs, "APPrinterPreset", IPP_TAG_ZERO) &&
3659*5e7646d2SAndroid Build Coastguard Worker       (ippFindAttribute(job->attrs, "print-color-mode", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ZERO) || ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_ZERO)))
3660*5e7646d2SAndroid Build Coastguard Worker   {
3661*5e7646d2SAndroid Build Coastguard Worker    /*
3662*5e7646d2SAndroid Build Coastguard Worker     * Map print-color-mode and print-quality to a preset...
3663*5e7646d2SAndroid Build Coastguard Worker     */
3664*5e7646d2SAndroid Build Coastguard Worker 
3665*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "print-color-mode",
3666*5e7646d2SAndroid Build Coastguard Worker 				 IPP_TAG_KEYWORD)) != NULL &&
3667*5e7646d2SAndroid Build Coastguard Worker         !strcmp(attr->values[0].string.text, "monochrome"))
3668*5e7646d2SAndroid Build Coastguard Worker       print_color_mode = _PWG_PRINT_COLOR_MODE_MONOCHROME;
3669*5e7646d2SAndroid Build Coastguard Worker     else
3670*5e7646d2SAndroid Build Coastguard Worker       print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
3671*5e7646d2SAndroid Build Coastguard Worker 
3672*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM)) != NULL)
3673*5e7646d2SAndroid Build Coastguard Worker     {
3674*5e7646d2SAndroid Build Coastguard Worker       ipp_quality_t pq = (ipp_quality_t)ippGetInteger(attr, 0);
3675*5e7646d2SAndroid Build Coastguard Worker 
3676*5e7646d2SAndroid Build Coastguard Worker       if (pq >= IPP_QUALITY_DRAFT && pq <= IPP_QUALITY_HIGH)
3677*5e7646d2SAndroid Build Coastguard Worker         print_quality = attr->values[0].integer - IPP_QUALITY_DRAFT;
3678*5e7646d2SAndroid Build Coastguard Worker       else
3679*5e7646d2SAndroid Build Coastguard Worker         print_quality = _PWG_PRINT_QUALITY_NORMAL;
3680*5e7646d2SAndroid Build Coastguard Worker     }
3681*5e7646d2SAndroid Build Coastguard Worker     else if ((attr = ippFindAttribute(job->attrs, "cupsPrintQuality", IPP_TAG_NAME)) != NULL)
3682*5e7646d2SAndroid Build Coastguard Worker     {
3683*5e7646d2SAndroid Build Coastguard Worker       const char *pq = ippGetString(attr, 0, NULL);
3684*5e7646d2SAndroid Build Coastguard Worker 
3685*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strcasecmp(pq, "draft"))
3686*5e7646d2SAndroid Build Coastguard Worker         print_quality = _PWG_PRINT_QUALITY_DRAFT;
3687*5e7646d2SAndroid Build Coastguard Worker       else if (!_cups_strcasecmp(pq, "high"))
3688*5e7646d2SAndroid Build Coastguard Worker         print_quality = _PWG_PRINT_QUALITY_HIGH;
3689*5e7646d2SAndroid Build Coastguard Worker       else
3690*5e7646d2SAndroid Build Coastguard Worker         print_quality = _PWG_PRINT_QUALITY_NORMAL;
3691*5e7646d2SAndroid Build Coastguard Worker 
3692*5e7646d2SAndroid Build Coastguard Worker       if (!ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM))
3693*5e7646d2SAndroid Build Coastguard Worker       {
3694*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping cupsPrintQuality=%s to print-quality=%d", pq, print_quality + IPP_QUALITY_DRAFT);
3695*5e7646d2SAndroid Build Coastguard Worker         num_pwgppds = cupsAddIntegerOption("print-quality", print_quality + IPP_QUALITY_DRAFT, num_pwgppds, &pwgppds);
3696*5e7646d2SAndroid Build Coastguard Worker       }
3697*5e7646d2SAndroid Build Coastguard Worker     }
3698*5e7646d2SAndroid Build Coastguard Worker     else
3699*5e7646d2SAndroid Build Coastguard Worker     {
3700*5e7646d2SAndroid Build Coastguard Worker       print_quality = _PWG_PRINT_QUALITY_NORMAL;
3701*5e7646d2SAndroid Build Coastguard Worker     }
3702*5e7646d2SAndroid Build Coastguard Worker 
3703*5e7646d2SAndroid Build Coastguard Worker     if (pc->num_presets[print_color_mode][print_quality] == 0)
3704*5e7646d2SAndroid Build Coastguard Worker     {
3705*5e7646d2SAndroid Build Coastguard Worker      /*
3706*5e7646d2SAndroid Build Coastguard Worker       * Try to find a preset that works so that we maximize the chances of us
3707*5e7646d2SAndroid Build Coastguard Worker       * getting a good print using IPP attributes.
3708*5e7646d2SAndroid Build Coastguard Worker       */
3709*5e7646d2SAndroid Build Coastguard Worker 
3710*5e7646d2SAndroid Build Coastguard Worker       if (pc->num_presets[print_color_mode][_PWG_PRINT_QUALITY_NORMAL] > 0)
3711*5e7646d2SAndroid Build Coastguard Worker         print_quality = _PWG_PRINT_QUALITY_NORMAL;
3712*5e7646d2SAndroid Build Coastguard Worker       else if (pc->num_presets[_PWG_PRINT_COLOR_MODE_COLOR][print_quality] > 0)
3713*5e7646d2SAndroid Build Coastguard Worker         print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
3714*5e7646d2SAndroid Build Coastguard Worker       else
3715*5e7646d2SAndroid Build Coastguard Worker       {
3716*5e7646d2SAndroid Build Coastguard Worker         print_quality    = _PWG_PRINT_QUALITY_NORMAL;
3717*5e7646d2SAndroid Build Coastguard Worker         print_color_mode = _PWG_PRINT_COLOR_MODE_COLOR;
3718*5e7646d2SAndroid Build Coastguard Worker       }
3719*5e7646d2SAndroid Build Coastguard Worker     }
3720*5e7646d2SAndroid Build Coastguard Worker 
3721*5e7646d2SAndroid Build Coastguard Worker     if (pc->num_presets[print_color_mode][print_quality] > 0)
3722*5e7646d2SAndroid Build Coastguard Worker     {
3723*5e7646d2SAndroid Build Coastguard Worker      /*
3724*5e7646d2SAndroid Build Coastguard Worker       * Copy the preset options as long as the corresponding names are not
3725*5e7646d2SAndroid Build Coastguard Worker       * already defined in the IPP request...
3726*5e7646d2SAndroid Build Coastguard Worker       */
3727*5e7646d2SAndroid Build Coastguard Worker 
3728*5e7646d2SAndroid Build Coastguard Worker       for (i = pc->num_presets[print_color_mode][print_quality],
3729*5e7646d2SAndroid Build Coastguard Worker 	       preset = pc->presets[print_color_mode][print_quality];
3730*5e7646d2SAndroid Build Coastguard Worker 	   i > 0;
3731*5e7646d2SAndroid Build Coastguard Worker 	   i --, preset ++)
3732*5e7646d2SAndroid Build Coastguard Worker       {
3733*5e7646d2SAndroid Build Coastguard Worker         if (!ippFindAttribute(job->attrs, preset->name, IPP_TAG_ZERO))
3734*5e7646d2SAndroid Build Coastguard Worker         {
3735*5e7646d2SAndroid Build Coastguard Worker           cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding preset option %s=%s", preset->name, preset->value);
3736*5e7646d2SAndroid Build Coastguard Worker 
3737*5e7646d2SAndroid Build Coastguard Worker 	  num_pwgppds = cupsAddOption(preset->name, preset->value, num_pwgppds, &pwgppds);
3738*5e7646d2SAndroid Build Coastguard Worker         }
3739*5e7646d2SAndroid Build Coastguard Worker       }
3740*5e7646d2SAndroid Build Coastguard Worker     }
3741*5e7646d2SAndroid Build Coastguard Worker   }
3742*5e7646d2SAndroid Build Coastguard Worker 
3743*5e7646d2SAndroid Build Coastguard Worker   if (pc)
3744*5e7646d2SAndroid Build Coastguard Worker   {
3745*5e7646d2SAndroid Build Coastguard Worker     if ((attr = ippFindAttribute(job->attrs, "print-quality", IPP_TAG_ENUM)) != NULL)
3746*5e7646d2SAndroid Build Coastguard Worker     {
3747*5e7646d2SAndroid Build Coastguard Worker       int pq = ippGetInteger(attr, 0);
3748*5e7646d2SAndroid Build Coastguard Worker       static const char * const pqs[] = { "Draft", "Normal", "High" };
3749*5e7646d2SAndroid Build Coastguard Worker 
3750*5e7646d2SAndroid Build Coastguard Worker       if (pq >= IPP_QUALITY_DRAFT && pq <= IPP_QUALITY_HIGH)
3751*5e7646d2SAndroid Build Coastguard Worker       {
3752*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping print-quality=%d to cupsPrintQuality=%s", pq, pqs[pq - IPP_QUALITY_DRAFT]);
3753*5e7646d2SAndroid Build Coastguard Worker 
3754*5e7646d2SAndroid Build Coastguard Worker         num_pwgppds = cupsAddOption("cupsPrintQuality", pqs[pq - IPP_QUALITY_DRAFT], num_pwgppds, &pwgppds);
3755*5e7646d2SAndroid Build Coastguard Worker       }
3756*5e7646d2SAndroid Build Coastguard Worker     }
3757*5e7646d2SAndroid Build Coastguard Worker 
3758*5e7646d2SAndroid Build Coastguard Worker     if (!ippFindAttribute(job->attrs, "InputSlot", IPP_TAG_ZERO) &&
3759*5e7646d2SAndroid Build Coastguard Worker 	!ippFindAttribute(job->attrs, "HPPaperSource", IPP_TAG_ZERO))
3760*5e7646d2SAndroid Build Coastguard Worker     {
3761*5e7646d2SAndroid Build Coastguard Worker       if ((ppd = _ppdCacheGetInputSlot(pc, job->attrs, NULL)) != NULL)
3762*5e7646d2SAndroid Build Coastguard Worker 	num_pwgppds = cupsAddOption(pc->source_option, ppd, num_pwgppds,
3763*5e7646d2SAndroid Build Coastguard Worker 				    &pwgppds);
3764*5e7646d2SAndroid Build Coastguard Worker     }
3765*5e7646d2SAndroid Build Coastguard Worker     if (!ippFindAttribute(job->attrs, "MediaType", IPP_TAG_ZERO) &&
3766*5e7646d2SAndroid Build Coastguard Worker 	(ppd = _ppdCacheGetMediaType(pc, job->attrs, NULL)) != NULL)
3767*5e7646d2SAndroid Build Coastguard Worker     {
3768*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping media to MediaType=%s", ppd);
3769*5e7646d2SAndroid Build Coastguard Worker 
3770*5e7646d2SAndroid Build Coastguard Worker       num_pwgppds = cupsAddOption("MediaType", ppd, num_pwgppds, &pwgppds);
3771*5e7646d2SAndroid Build Coastguard Worker     }
3772*5e7646d2SAndroid Build Coastguard Worker 
3773*5e7646d2SAndroid Build Coastguard Worker     if (!ippFindAttribute(job->attrs, "PageRegion", IPP_TAG_ZERO) &&
3774*5e7646d2SAndroid Build Coastguard Worker 	!ippFindAttribute(job->attrs, "PageSize", IPP_TAG_ZERO) &&
3775*5e7646d2SAndroid Build Coastguard Worker 	(ppd = _ppdCacheGetPageSize(pc, job->attrs, NULL, &exact)) != NULL)
3776*5e7646d2SAndroid Build Coastguard Worker     {
3777*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping media to Pagesize=%s", ppd);
3778*5e7646d2SAndroid Build Coastguard Worker 
3779*5e7646d2SAndroid Build Coastguard Worker       num_pwgppds = cupsAddOption("PageSize", ppd, num_pwgppds, &pwgppds);
3780*5e7646d2SAndroid Build Coastguard Worker 
3781*5e7646d2SAndroid Build Coastguard Worker       if (!ippFindAttribute(job->attrs, "media", IPP_TAG_ZERO))
3782*5e7646d2SAndroid Build Coastguard Worker       {
3783*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Adding media=%s", ppd);
3784*5e7646d2SAndroid Build Coastguard Worker 
3785*5e7646d2SAndroid Build Coastguard Worker         num_pwgppds = cupsAddOption("media", ppd, num_pwgppds, &pwgppds);
3786*5e7646d2SAndroid Build Coastguard Worker       }
3787*5e7646d2SAndroid Build Coastguard Worker     }
3788*5e7646d2SAndroid Build Coastguard Worker 
3789*5e7646d2SAndroid Build Coastguard Worker     if (!ippFindAttribute(job->attrs, "OutputBin", IPP_TAG_ZERO) &&
3790*5e7646d2SAndroid Build Coastguard Worker 	(attr = ippFindAttribute(job->attrs, "output-bin",
3791*5e7646d2SAndroid Build Coastguard Worker 				 IPP_TAG_ZERO)) != NULL &&
3792*5e7646d2SAndroid Build Coastguard Worker 	(attr->value_tag == IPP_TAG_KEYWORD ||
3793*5e7646d2SAndroid Build Coastguard Worker 	 attr->value_tag == IPP_TAG_NAME) &&
3794*5e7646d2SAndroid Build Coastguard Worker 	(ppd = _ppdCacheGetOutputBin(pc, attr->values[0].string.text)) != NULL)
3795*5e7646d2SAndroid Build Coastguard Worker     {
3796*5e7646d2SAndroid Build Coastguard Worker      /*
3797*5e7646d2SAndroid Build Coastguard Worker       * Map output-bin to OutputBin option...
3798*5e7646d2SAndroid Build Coastguard Worker       */
3799*5e7646d2SAndroid Build Coastguard Worker 
3800*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping output-bin to OutputBin=%s", ppd);
3801*5e7646d2SAndroid Build Coastguard Worker 
3802*5e7646d2SAndroid Build Coastguard Worker       num_pwgppds = cupsAddOption("OutputBin", ppd, num_pwgppds, &pwgppds);
3803*5e7646d2SAndroid Build Coastguard Worker     }
3804*5e7646d2SAndroid Build Coastguard Worker 
3805*5e7646d2SAndroid Build Coastguard Worker     if (pc->sides_option &&
3806*5e7646d2SAndroid Build Coastguard Worker         !ippFindAttribute(job->attrs, pc->sides_option, IPP_TAG_ZERO) &&
3807*5e7646d2SAndroid Build Coastguard Worker 	(attr = ippFindAttribute(job->attrs, "sides", IPP_TAG_KEYWORD)) != NULL)
3808*5e7646d2SAndroid Build Coastguard Worker     {
3809*5e7646d2SAndroid Build Coastguard Worker      /*
3810*5e7646d2SAndroid Build Coastguard Worker       * Map sides to duplex option...
3811*5e7646d2SAndroid Build Coastguard Worker       */
3812*5e7646d2SAndroid Build Coastguard Worker 
3813*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(attr->values[0].string.text, "one-sided"))
3814*5e7646d2SAndroid Build Coastguard Worker       {
3815*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_1sided);
3816*5e7646d2SAndroid Build Coastguard Worker 
3817*5e7646d2SAndroid Build Coastguard Worker         num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_1sided, num_pwgppds, &pwgppds);
3818*5e7646d2SAndroid Build Coastguard Worker       }
3819*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->values[0].string.text, "two-sided-long-edge"))
3820*5e7646d2SAndroid Build Coastguard Worker       {
3821*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_2sided_long);
3822*5e7646d2SAndroid Build Coastguard Worker 
3823*5e7646d2SAndroid Build Coastguard Worker         num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_long, num_pwgppds, &pwgppds);
3824*5e7646d2SAndroid Build Coastguard Worker       }
3825*5e7646d2SAndroid Build Coastguard Worker       else if (!strcmp(attr->values[0].string.text, "two-sided-short-edge"))
3826*5e7646d2SAndroid Build Coastguard Worker       {
3827*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_DEBUG2, "Mapping sizes to Duplex=%s", pc->sides_2sided_short);
3828*5e7646d2SAndroid Build Coastguard Worker 
3829*5e7646d2SAndroid Build Coastguard Worker         num_pwgppds = cupsAddOption(pc->sides_option, pc->sides_2sided_short, num_pwgppds, &pwgppds);
3830*5e7646d2SAndroid Build Coastguard Worker       }
3831*5e7646d2SAndroid Build Coastguard Worker     }
3832*5e7646d2SAndroid Build Coastguard Worker 
3833*5e7646d2SAndroid Build Coastguard Worker    /*
3834*5e7646d2SAndroid Build Coastguard Worker     * Map finishings values...
3835*5e7646d2SAndroid Build Coastguard Worker     */
3836*5e7646d2SAndroid Build Coastguard Worker 
3837*5e7646d2SAndroid Build Coastguard Worker     num_pwgppds = _ppdCacheGetFinishingOptions(pc, job->attrs, IPP_FINISHINGS_NONE, num_pwgppds, &pwgppds);
3838*5e7646d2SAndroid Build Coastguard Worker 
3839*5e7646d2SAndroid Build Coastguard Worker     for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
3840*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG2, "After mapping finishings %s=%s", pwgppd->name, pwgppd->value);
3841*5e7646d2SAndroid Build Coastguard Worker   }
3842*5e7646d2SAndroid Build Coastguard Worker 
3843*5e7646d2SAndroid Build Coastguard Worker  /*
3844*5e7646d2SAndroid Build Coastguard Worker   * Map page-delivery values...
3845*5e7646d2SAndroid Build Coastguard Worker   */
3846*5e7646d2SAndroid Build Coastguard Worker 
3847*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, "page-delivery", IPP_TAG_KEYWORD)) != NULL && !ippFindAttribute(job->attrs, "outputorder", IPP_TAG_ZERO))
3848*5e7646d2SAndroid Build Coastguard Worker   {
3849*5e7646d2SAndroid Build Coastguard Worker     const char *page_delivery = ippGetString(attr, 0, NULL);
3850*5e7646d2SAndroid Build Coastguard Worker 
3851*5e7646d2SAndroid Build Coastguard Worker     if (!strncmp(page_delivery, "same-order", 10))
3852*5e7646d2SAndroid Build Coastguard Worker       num_pwgppds = cupsAddOption("OutputOrder", "Normal", num_pwgppds, &pwgppds);
3853*5e7646d2SAndroid Build Coastguard Worker     else if (!strncmp(page_delivery, "reverse-order", 13))
3854*5e7646d2SAndroid Build Coastguard Worker       num_pwgppds = cupsAddOption("OutputOrder", "Reverse", num_pwgppds, &pwgppds);
3855*5e7646d2SAndroid Build Coastguard Worker   }
3856*5e7646d2SAndroid Build Coastguard Worker 
3857*5e7646d2SAndroid Build Coastguard Worker  /*
3858*5e7646d2SAndroid Build Coastguard Worker   * Figure out how much room we need...
3859*5e7646d2SAndroid Build Coastguard Worker   */
3860*5e7646d2SAndroid Build Coastguard Worker 
3861*5e7646d2SAndroid Build Coastguard Worker   newlength = ipp_length(job->attrs);
3862*5e7646d2SAndroid Build Coastguard Worker 
3863*5e7646d2SAndroid Build Coastguard Worker   for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
3864*5e7646d2SAndroid Build Coastguard Worker     newlength += 1 + strlen(pwgppd->name) + 1 + strlen(pwgppd->value);
3865*5e7646d2SAndroid Build Coastguard Worker 
3866*5e7646d2SAndroid Build Coastguard Worker  /*
3867*5e7646d2SAndroid Build Coastguard Worker   * Then allocate/reallocate the option buffer as needed...
3868*5e7646d2SAndroid Build Coastguard Worker   */
3869*5e7646d2SAndroid Build Coastguard Worker 
3870*5e7646d2SAndroid Build Coastguard Worker   if (newlength == 0)			/* This can never happen, but Clang */
3871*5e7646d2SAndroid Build Coastguard Worker     newlength = 1;			/* thinks it can... */
3872*5e7646d2SAndroid Build Coastguard Worker 
3873*5e7646d2SAndroid Build Coastguard Worker   if (newlength > optlength || !options)
3874*5e7646d2SAndroid Build Coastguard Worker   {
3875*5e7646d2SAndroid Build Coastguard Worker     if (!options)
3876*5e7646d2SAndroid Build Coastguard Worker       optptr = malloc(newlength);
3877*5e7646d2SAndroid Build Coastguard Worker     else
3878*5e7646d2SAndroid Build Coastguard Worker       optptr = realloc(options, newlength);
3879*5e7646d2SAndroid Build Coastguard Worker 
3880*5e7646d2SAndroid Build Coastguard Worker     if (!optptr)
3881*5e7646d2SAndroid Build Coastguard Worker     {
3882*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_CRIT,
3883*5e7646d2SAndroid Build Coastguard Worker 		  "Unable to allocate " CUPS_LLFMT " bytes for option buffer.",
3884*5e7646d2SAndroid Build Coastguard Worker 		  CUPS_LLCAST newlength);
3885*5e7646d2SAndroid Build Coastguard Worker       return (NULL);
3886*5e7646d2SAndroid Build Coastguard Worker     }
3887*5e7646d2SAndroid Build Coastguard Worker 
3888*5e7646d2SAndroid Build Coastguard Worker     options   = optptr;
3889*5e7646d2SAndroid Build Coastguard Worker     optlength = newlength;
3890*5e7646d2SAndroid Build Coastguard Worker   }
3891*5e7646d2SAndroid Build Coastguard Worker 
3892*5e7646d2SAndroid Build Coastguard Worker  /*
3893*5e7646d2SAndroid Build Coastguard Worker   * Now loop through the attributes and convert them to the textual
3894*5e7646d2SAndroid Build Coastguard Worker   * representation used by the filters...
3895*5e7646d2SAndroid Build Coastguard Worker   */
3896*5e7646d2SAndroid Build Coastguard Worker 
3897*5e7646d2SAndroid Build Coastguard Worker   optptr  = options;
3898*5e7646d2SAndroid Build Coastguard Worker   *optptr = '\0';
3899*5e7646d2SAndroid Build Coastguard Worker 
3900*5e7646d2SAndroid Build Coastguard Worker   snprintf(title, title_size, "%s-%d", job->printer->name, job->id);
3901*5e7646d2SAndroid Build Coastguard Worker   strlcpy(copies, "1", copies_size);
3902*5e7646d2SAndroid Build Coastguard Worker 
3903*5e7646d2SAndroid Build Coastguard Worker   for (attr = job->attrs->attrs; attr != NULL; attr = attr->next)
3904*5e7646d2SAndroid Build Coastguard Worker   {
3905*5e7646d2SAndroid Build Coastguard Worker     if (!strcmp(attr->name, "copies") &&
3906*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag == IPP_TAG_INTEGER)
3907*5e7646d2SAndroid Build Coastguard Worker     {
3908*5e7646d2SAndroid Build Coastguard Worker      /*
3909*5e7646d2SAndroid Build Coastguard Worker       * Don't use the # copies attribute if we are printing the job sheets...
3910*5e7646d2SAndroid Build Coastguard Worker       */
3911*5e7646d2SAndroid Build Coastguard Worker 
3912*5e7646d2SAndroid Build Coastguard Worker       if (!banner_page)
3913*5e7646d2SAndroid Build Coastguard Worker         snprintf(copies, copies_size, "%d", attr->values[0].integer);
3914*5e7646d2SAndroid Build Coastguard Worker     }
3915*5e7646d2SAndroid Build Coastguard Worker     else if (!strcmp(attr->name, "job-name") &&
3916*5e7646d2SAndroid Build Coastguard Worker 	     (attr->value_tag == IPP_TAG_NAME ||
3917*5e7646d2SAndroid Build Coastguard Worker 	      attr->value_tag == IPP_TAG_NAMELANG))
3918*5e7646d2SAndroid Build Coastguard Worker       strlcpy(title, attr->values[0].string.text, title_size);
3919*5e7646d2SAndroid Build Coastguard Worker     else if (attr->group_tag == IPP_TAG_JOB)
3920*5e7646d2SAndroid Build Coastguard Worker     {
3921*5e7646d2SAndroid Build Coastguard Worker      /*
3922*5e7646d2SAndroid Build Coastguard Worker       * Filter out other unwanted attributes...
3923*5e7646d2SAndroid Build Coastguard Worker       */
3924*5e7646d2SAndroid Build Coastguard Worker 
3925*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag == IPP_TAG_NOVALUE ||
3926*5e7646d2SAndroid Build Coastguard Worker           attr->value_tag == IPP_TAG_MIMETYPE ||
3927*5e7646d2SAndroid Build Coastguard Worker 	  attr->value_tag == IPP_TAG_NAMELANG ||
3928*5e7646d2SAndroid Build Coastguard Worker 	  attr->value_tag == IPP_TAG_TEXTLANG ||
3929*5e7646d2SAndroid Build Coastguard Worker 	  (attr->value_tag == IPP_TAG_URI && strcmp(attr->name, "job-uuid") &&
3930*5e7646d2SAndroid Build Coastguard Worker 	   strcmp(attr->name, "job-authorization-uri")) ||
3931*5e7646d2SAndroid Build Coastguard Worker 	  attr->value_tag == IPP_TAG_URISCHEME ||
3932*5e7646d2SAndroid Build Coastguard Worker 	  attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */
3933*5e7646d2SAndroid Build Coastguard Worker 	continue;
3934*5e7646d2SAndroid Build Coastguard Worker 
3935*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(attr->name, "job-hold-until") ||
3936*5e7646d2SAndroid Build Coastguard Worker           !strcmp(attr->name, "job-id") ||
3937*5e7646d2SAndroid Build Coastguard Worker           !strcmp(attr->name, "job-k-octets") ||
3938*5e7646d2SAndroid Build Coastguard Worker           !strcmp(attr->name, "job-media-sheets") ||
3939*5e7646d2SAndroid Build Coastguard Worker           !strcmp(attr->name, "job-media-sheets-completed") ||
3940*5e7646d2SAndroid Build Coastguard Worker           !strcmp(attr->name, "job-state") ||
3941*5e7646d2SAndroid Build Coastguard Worker           !strcmp(attr->name, "job-state-reasons"))
3942*5e7646d2SAndroid Build Coastguard Worker 	continue;
3943*5e7646d2SAndroid Build Coastguard Worker 
3944*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(attr->name, "job-", 4) &&
3945*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-account-id") &&
3946*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-accounting-user-id") &&
3947*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-authorization-uri") &&
3948*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-billing") &&
3949*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-impressions") &&
3950*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-originating-host-name") &&
3951*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-password") &&
3952*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-password-encryption") &&
3953*5e7646d2SAndroid Build Coastguard Worker           strcmp(attr->name, "job-uuid") &&
3954*5e7646d2SAndroid Build Coastguard Worker           !(job->printer->type & CUPS_PRINTER_REMOTE))
3955*5e7646d2SAndroid Build Coastguard Worker 	continue;
3956*5e7646d2SAndroid Build Coastguard Worker 
3957*5e7646d2SAndroid Build Coastguard Worker       if ((!strcmp(attr->name, "job-impressions") ||
3958*5e7646d2SAndroid Build Coastguard Worker            !strcmp(attr->name, "page-label") ||
3959*5e7646d2SAndroid Build Coastguard Worker            !strcmp(attr->name, "page-border") ||
3960*5e7646d2SAndroid Build Coastguard Worker            !strncmp(attr->name, "number-up", 9) ||
3961*5e7646d2SAndroid Build Coastguard Worker 	   !strcmp(attr->name, "page-ranges") ||
3962*5e7646d2SAndroid Build Coastguard Worker 	   !strcmp(attr->name, "page-set") ||
3963*5e7646d2SAndroid Build Coastguard Worker 	   !_cups_strcasecmp(attr->name, "AP_FIRSTPAGE_InputSlot") ||
3964*5e7646d2SAndroid Build Coastguard Worker 	   !_cups_strcasecmp(attr->name, "AP_FIRSTPAGE_ManualFeed") ||
3965*5e7646d2SAndroid Build Coastguard Worker 	   !_cups_strcasecmp(attr->name, "com.apple.print.PrintSettings."
3966*5e7646d2SAndroid Build Coastguard Worker 	                           "PMTotalSidesImaged..n.") ||
3967*5e7646d2SAndroid Build Coastguard Worker 	   !_cups_strcasecmp(attr->name, "com.apple.print.PrintSettings."
3968*5e7646d2SAndroid Build Coastguard Worker 	                           "PMTotalBeginPages..n.")) &&
3969*5e7646d2SAndroid Build Coastguard Worker 	  banner_page)
3970*5e7646d2SAndroid Build Coastguard Worker         continue;
3971*5e7646d2SAndroid Build Coastguard Worker 
3972*5e7646d2SAndroid Build Coastguard Worker      /*
3973*5e7646d2SAndroid Build Coastguard Worker       * Otherwise add them to the list...
3974*5e7646d2SAndroid Build Coastguard Worker       */
3975*5e7646d2SAndroid Build Coastguard Worker 
3976*5e7646d2SAndroid Build Coastguard Worker       if (optptr > options)
3977*5e7646d2SAndroid Build Coastguard Worker 	strlcat(optptr, " ", optlength - (size_t)(optptr - options));
3978*5e7646d2SAndroid Build Coastguard Worker 
3979*5e7646d2SAndroid Build Coastguard Worker       if (attr->value_tag != IPP_TAG_BOOLEAN)
3980*5e7646d2SAndroid Build Coastguard Worker       {
3981*5e7646d2SAndroid Build Coastguard Worker 	strlcat(optptr, attr->name, optlength - (size_t)(optptr - options));
3982*5e7646d2SAndroid Build Coastguard Worker 	strlcat(optptr, "=", optlength - (size_t)(optptr - options));
3983*5e7646d2SAndroid Build Coastguard Worker       }
3984*5e7646d2SAndroid Build Coastguard Worker 
3985*5e7646d2SAndroid Build Coastguard Worker       for (i = 0; i < attr->num_values; i ++)
3986*5e7646d2SAndroid Build Coastguard Worker       {
3987*5e7646d2SAndroid Build Coastguard Worker 	if (i)
3988*5e7646d2SAndroid Build Coastguard Worker 	  strlcat(optptr, ",", optlength - (size_t)(optptr - options));
3989*5e7646d2SAndroid Build Coastguard Worker 
3990*5e7646d2SAndroid Build Coastguard Worker 	optptr += strlen(optptr);
3991*5e7646d2SAndroid Build Coastguard Worker 
3992*5e7646d2SAndroid Build Coastguard Worker 	switch (attr->value_tag)
3993*5e7646d2SAndroid Build Coastguard Worker 	{
3994*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_INTEGER :
3995*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_ENUM :
3996*5e7646d2SAndroid Build Coastguard Worker 	      snprintf(optptr, optlength - (size_t)(optptr - options),
3997*5e7646d2SAndroid Build Coastguard Worker 	               "%d", attr->values[i].integer);
3998*5e7646d2SAndroid Build Coastguard Worker 	      break;
3999*5e7646d2SAndroid Build Coastguard Worker 
4000*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_BOOLEAN :
4001*5e7646d2SAndroid Build Coastguard Worker 	      if (!attr->values[i].boolean)
4002*5e7646d2SAndroid Build Coastguard Worker 		strlcat(optptr, "no", optlength - (size_t)(optptr - options));
4003*5e7646d2SAndroid Build Coastguard Worker 
4004*5e7646d2SAndroid Build Coastguard Worker 	      strlcat(optptr, attr->name, optlength - (size_t)(optptr - options));
4005*5e7646d2SAndroid Build Coastguard Worker 	      break;
4006*5e7646d2SAndroid Build Coastguard Worker 
4007*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_RANGE :
4008*5e7646d2SAndroid Build Coastguard Worker 	      if (attr->values[i].range.lower == attr->values[i].range.upper)
4009*5e7646d2SAndroid Build Coastguard Worker 		snprintf(optptr, optlength - (size_t)(optptr - options) - 1,
4010*5e7646d2SAndroid Build Coastguard Worker 	        	 "%d", attr->values[i].range.lower);
4011*5e7646d2SAndroid Build Coastguard Worker               else
4012*5e7646d2SAndroid Build Coastguard Worker 		snprintf(optptr, optlength - (size_t)(optptr - options) - 1,
4013*5e7646d2SAndroid Build Coastguard Worker 	        	 "%d-%d", attr->values[i].range.lower,
4014*5e7646d2SAndroid Build Coastguard Worker 			 attr->values[i].range.upper);
4015*5e7646d2SAndroid Build Coastguard Worker 	      break;
4016*5e7646d2SAndroid Build Coastguard Worker 
4017*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_RESOLUTION :
4018*5e7646d2SAndroid Build Coastguard Worker 	      snprintf(optptr, optlength - (size_t)(optptr - options) - 1,
4019*5e7646d2SAndroid Build Coastguard Worker 	               "%dx%d%s", attr->values[i].resolution.xres,
4020*5e7646d2SAndroid Build Coastguard Worker 		       attr->values[i].resolution.yres,
4021*5e7646d2SAndroid Build Coastguard Worker 		       attr->values[i].resolution.units == IPP_RES_PER_INCH ?
4022*5e7646d2SAndroid Build Coastguard Worker 			   "dpi" : "dpcm");
4023*5e7646d2SAndroid Build Coastguard Worker 	      break;
4024*5e7646d2SAndroid Build Coastguard Worker 
4025*5e7646d2SAndroid Build Coastguard Worker           case IPP_TAG_STRING :
4026*5e7646d2SAndroid Build Coastguard Worker               {
4027*5e7646d2SAndroid Build Coastguard Worker                 int length = attr->values[i].unknown.length;
4028*5e7646d2SAndroid Build Coastguard Worker 
4029*5e7646d2SAndroid Build Coastguard Worker 		for (valptr = attr->values[i].unknown.data; length > 0; length --)
4030*5e7646d2SAndroid Build Coastguard Worker 		{
4031*5e7646d2SAndroid Build Coastguard Worker 		  if ((*valptr & 255) < 0x20 || *valptr == 0x7f)
4032*5e7646d2SAndroid Build Coastguard Worker 		    break;
4033*5e7646d2SAndroid Build Coastguard Worker 		}
4034*5e7646d2SAndroid Build Coastguard Worker 
4035*5e7646d2SAndroid Build Coastguard Worker 		if (length > 0)
4036*5e7646d2SAndroid Build Coastguard Worker 		{
4037*5e7646d2SAndroid Build Coastguard Worker 		 /*
4038*5e7646d2SAndroid Build Coastguard Worker 		  * Encode this string as hex characters...
4039*5e7646d2SAndroid Build Coastguard Worker 		  */
4040*5e7646d2SAndroid Build Coastguard Worker 
4041*5e7646d2SAndroid Build Coastguard Worker                   *optptr++ = '<';
4042*5e7646d2SAndroid Build Coastguard Worker 
4043*5e7646d2SAndroid Build Coastguard Worker 		  for (valptr = attr->values[i].unknown.data, length = attr->values[i].unknown.length; length > 0; length --)
4044*5e7646d2SAndroid Build Coastguard Worker 		  {
4045*5e7646d2SAndroid Build Coastguard Worker 		    snprintf(optptr, optlength - (size_t)(optptr - options) - 1, "%02X", *valptr & 255);
4046*5e7646d2SAndroid Build Coastguard Worker 		    optptr += 2;
4047*5e7646d2SAndroid Build Coastguard Worker 		  }
4048*5e7646d2SAndroid Build Coastguard Worker 
4049*5e7646d2SAndroid Build Coastguard Worker                   *optptr++ = '>';
4050*5e7646d2SAndroid Build Coastguard Worker 		}
4051*5e7646d2SAndroid Build Coastguard Worker 		else
4052*5e7646d2SAndroid Build Coastguard Worker 		{
4053*5e7646d2SAndroid Build Coastguard Worker 		  for (valptr = attr->values[i].unknown.data, length = attr->values[i].unknown.length; length > 0; length --)
4054*5e7646d2SAndroid Build Coastguard Worker 		  {
4055*5e7646d2SAndroid Build Coastguard Worker 		    if (strchr(" \t\n\\\'\"", *valptr))
4056*5e7646d2SAndroid Build Coastguard Worker 		      *optptr++ = '\\';
4057*5e7646d2SAndroid Build Coastguard Worker 		    *optptr++ = *valptr++;
4058*5e7646d2SAndroid Build Coastguard Worker 		  }
4059*5e7646d2SAndroid Build Coastguard Worker 		}
4060*5e7646d2SAndroid Build Coastguard Worker 	      }
4061*5e7646d2SAndroid Build Coastguard Worker 
4062*5e7646d2SAndroid Build Coastguard Worker 	      *optptr = '\0';
4063*5e7646d2SAndroid Build Coastguard Worker 	      break;
4064*5e7646d2SAndroid Build Coastguard Worker 
4065*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_TEXT :
4066*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_NAME :
4067*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_KEYWORD :
4068*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_CHARSET :
4069*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_LANGUAGE :
4070*5e7646d2SAndroid Build Coastguard Worker 	  case IPP_TAG_URI :
4071*5e7646d2SAndroid Build Coastguard Worker 	      for (valptr = attr->values[i].string.text; *valptr;)
4072*5e7646d2SAndroid Build Coastguard Worker 	      {
4073*5e7646d2SAndroid Build Coastguard Worker 	        if (strchr(" \t\n\\\'\"", *valptr))
4074*5e7646d2SAndroid Build Coastguard Worker 		  *optptr++ = '\\';
4075*5e7646d2SAndroid Build Coastguard Worker 		*optptr++ = *valptr++;
4076*5e7646d2SAndroid Build Coastguard Worker 	      }
4077*5e7646d2SAndroid Build Coastguard Worker 
4078*5e7646d2SAndroid Build Coastguard Worker 	      *optptr = '\0';
4079*5e7646d2SAndroid Build Coastguard Worker 	      break;
4080*5e7646d2SAndroid Build Coastguard Worker 
4081*5e7646d2SAndroid Build Coastguard Worker           default :
4082*5e7646d2SAndroid Build Coastguard Worker 	      break; /* anti-compiler-warning-code */
4083*5e7646d2SAndroid Build Coastguard Worker 	}
4084*5e7646d2SAndroid Build Coastguard Worker       }
4085*5e7646d2SAndroid Build Coastguard Worker 
4086*5e7646d2SAndroid Build Coastguard Worker       optptr += strlen(optptr);
4087*5e7646d2SAndroid Build Coastguard Worker     }
4088*5e7646d2SAndroid Build Coastguard Worker   }
4089*5e7646d2SAndroid Build Coastguard Worker 
4090*5e7646d2SAndroid Build Coastguard Worker  /*
4091*5e7646d2SAndroid Build Coastguard Worker   * Finally loop through the PWG->PPD mapped options and add them...
4092*5e7646d2SAndroid Build Coastguard Worker   */
4093*5e7646d2SAndroid Build Coastguard Worker 
4094*5e7646d2SAndroid Build Coastguard Worker   for (i = num_pwgppds, pwgppd = pwgppds; i > 0; i --, pwgppd ++)
4095*5e7646d2SAndroid Build Coastguard Worker   {
4096*5e7646d2SAndroid Build Coastguard Worker     *optptr++ = ' ';
4097*5e7646d2SAndroid Build Coastguard Worker     strlcpy(optptr, pwgppd->name, optlength - (size_t)(optptr - options));
4098*5e7646d2SAndroid Build Coastguard Worker     optptr += strlen(optptr);
4099*5e7646d2SAndroid Build Coastguard Worker     *optptr++ = '=';
4100*5e7646d2SAndroid Build Coastguard Worker     strlcpy(optptr, pwgppd->value, optlength - (size_t)(optptr - options));
4101*5e7646d2SAndroid Build Coastguard Worker     optptr += strlen(optptr);
4102*5e7646d2SAndroid Build Coastguard Worker   }
4103*5e7646d2SAndroid Build Coastguard Worker 
4104*5e7646d2SAndroid Build Coastguard Worker   cupsFreeOptions(num_pwgppds, pwgppds);
4105*5e7646d2SAndroid Build Coastguard Worker 
4106*5e7646d2SAndroid Build Coastguard Worker  /*
4107*5e7646d2SAndroid Build Coastguard Worker   * Return the options string...
4108*5e7646d2SAndroid Build Coastguard Worker   */
4109*5e7646d2SAndroid Build Coastguard Worker 
4110*5e7646d2SAndroid Build Coastguard Worker   return (options);
4111*5e7646d2SAndroid Build Coastguard Worker }
4112*5e7646d2SAndroid Build Coastguard Worker 
4113*5e7646d2SAndroid Build Coastguard Worker 
4114*5e7646d2SAndroid Build Coastguard Worker /*
4115*5e7646d2SAndroid Build Coastguard Worker  * 'ipp_length()' - Compute the size of the buffer needed to hold
4116*5e7646d2SAndroid Build Coastguard Worker  *		    the textual IPP attributes.
4117*5e7646d2SAndroid Build Coastguard Worker  */
4118*5e7646d2SAndroid Build Coastguard Worker 
4119*5e7646d2SAndroid Build Coastguard Worker static size_t				/* O - Size of attribute buffer */
ipp_length(ipp_t * ipp)4120*5e7646d2SAndroid Build Coastguard Worker ipp_length(ipp_t *ipp)			/* I - IPP request */
4121*5e7646d2SAndroid Build Coastguard Worker {
4122*5e7646d2SAndroid Build Coastguard Worker   size_t		bytes; 		/* Number of bytes */
4123*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
4124*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Current attribute */
4125*5e7646d2SAndroid Build Coastguard Worker 
4126*5e7646d2SAndroid Build Coastguard Worker 
4127*5e7646d2SAndroid Build Coastguard Worker  /*
4128*5e7646d2SAndroid Build Coastguard Worker   * Loop through all attributes...
4129*5e7646d2SAndroid Build Coastguard Worker   */
4130*5e7646d2SAndroid Build Coastguard Worker 
4131*5e7646d2SAndroid Build Coastguard Worker   bytes = 0;
4132*5e7646d2SAndroid Build Coastguard Worker 
4133*5e7646d2SAndroid Build Coastguard Worker   for (attr = ipp->attrs; attr != NULL; attr = attr->next)
4134*5e7646d2SAndroid Build Coastguard Worker   {
4135*5e7646d2SAndroid Build Coastguard Worker    /*
4136*5e7646d2SAndroid Build Coastguard Worker     * Skip attributes that won't be sent to filters...
4137*5e7646d2SAndroid Build Coastguard Worker     */
4138*5e7646d2SAndroid Build Coastguard Worker 
4139*5e7646d2SAndroid Build Coastguard Worker     if (attr->value_tag == IPP_TAG_NOVALUE ||
4140*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag == IPP_TAG_MIMETYPE ||
4141*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag == IPP_TAG_NAMELANG ||
4142*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag == IPP_TAG_TEXTLANG ||
4143*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag == IPP_TAG_URI ||
4144*5e7646d2SAndroid Build Coastguard Worker 	attr->value_tag == IPP_TAG_URISCHEME)
4145*5e7646d2SAndroid Build Coastguard Worker       continue;
4146*5e7646d2SAndroid Build Coastguard Worker 
4147*5e7646d2SAndroid Build Coastguard Worker    /*
4148*5e7646d2SAndroid Build Coastguard Worker     * Add space for a leading space and commas between each value.
4149*5e7646d2SAndroid Build Coastguard Worker     * For the first attribute, the leading space isn't used, so the
4150*5e7646d2SAndroid Build Coastguard Worker     * extra byte can be used as the nul terminator...
4151*5e7646d2SAndroid Build Coastguard Worker     */
4152*5e7646d2SAndroid Build Coastguard Worker 
4153*5e7646d2SAndroid Build Coastguard Worker     bytes ++;				/* " " separator */
4154*5e7646d2SAndroid Build Coastguard Worker     bytes += (size_t)attr->num_values;	/* "," separators */
4155*5e7646d2SAndroid Build Coastguard Worker 
4156*5e7646d2SAndroid Build Coastguard Worker    /*
4157*5e7646d2SAndroid Build Coastguard Worker     * Boolean attributes appear as "foo,nofoo,foo,nofoo", while
4158*5e7646d2SAndroid Build Coastguard Worker     * other attributes appear as "foo=value1,value2,...,valueN".
4159*5e7646d2SAndroid Build Coastguard Worker     */
4160*5e7646d2SAndroid Build Coastguard Worker 
4161*5e7646d2SAndroid Build Coastguard Worker     if (attr->value_tag != IPP_TAG_BOOLEAN)
4162*5e7646d2SAndroid Build Coastguard Worker       bytes += strlen(attr->name);
4163*5e7646d2SAndroid Build Coastguard Worker     else
4164*5e7646d2SAndroid Build Coastguard Worker       bytes += (size_t)attr->num_values * strlen(attr->name);
4165*5e7646d2SAndroid Build Coastguard Worker 
4166*5e7646d2SAndroid Build Coastguard Worker    /*
4167*5e7646d2SAndroid Build Coastguard Worker     * Now add the size required for each value in the attribute...
4168*5e7646d2SAndroid Build Coastguard Worker     */
4169*5e7646d2SAndroid Build Coastguard Worker 
4170*5e7646d2SAndroid Build Coastguard Worker     switch (attr->value_tag)
4171*5e7646d2SAndroid Build Coastguard Worker     {
4172*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_INTEGER :
4173*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_ENUM :
4174*5e7646d2SAndroid Build Coastguard Worker          /*
4175*5e7646d2SAndroid Build Coastguard Worker 	  * Minimum value of a signed integer is -2147483647, or 11 digits.
4176*5e7646d2SAndroid Build Coastguard Worker 	  */
4177*5e7646d2SAndroid Build Coastguard Worker 
4178*5e7646d2SAndroid Build Coastguard Worker 	  bytes += (size_t)attr->num_values * 11;
4179*5e7646d2SAndroid Build Coastguard Worker 	  break;
4180*5e7646d2SAndroid Build Coastguard Worker 
4181*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_BOOLEAN :
4182*5e7646d2SAndroid Build Coastguard Worker          /*
4183*5e7646d2SAndroid Build Coastguard Worker 	  * Add two bytes for each false ("no") value...
4184*5e7646d2SAndroid Build Coastguard Worker 	  */
4185*5e7646d2SAndroid Build Coastguard Worker 
4186*5e7646d2SAndroid Build Coastguard Worker           for (i = 0; i < attr->num_values; i ++)
4187*5e7646d2SAndroid Build Coastguard Worker 	    if (!attr->values[i].boolean)
4188*5e7646d2SAndroid Build Coastguard Worker 	      bytes += 2;
4189*5e7646d2SAndroid Build Coastguard Worker 	  break;
4190*5e7646d2SAndroid Build Coastguard Worker 
4191*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_RANGE :
4192*5e7646d2SAndroid Build Coastguard Worker          /*
4193*5e7646d2SAndroid Build Coastguard Worker 	  * A range is two signed integers separated by a hyphen, or
4194*5e7646d2SAndroid Build Coastguard Worker 	  * 23 characters max.
4195*5e7646d2SAndroid Build Coastguard Worker 	  */
4196*5e7646d2SAndroid Build Coastguard Worker 
4197*5e7646d2SAndroid Build Coastguard Worker 	  bytes += (size_t)attr->num_values * 23;
4198*5e7646d2SAndroid Build Coastguard Worker 	  break;
4199*5e7646d2SAndroid Build Coastguard Worker 
4200*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_RESOLUTION :
4201*5e7646d2SAndroid Build Coastguard Worker          /*
4202*5e7646d2SAndroid Build Coastguard Worker 	  * A resolution is two signed integers separated by an "x" and
4203*5e7646d2SAndroid Build Coastguard Worker 	  * suffixed by the units, or 26 characters max.
4204*5e7646d2SAndroid Build Coastguard Worker 	  */
4205*5e7646d2SAndroid Build Coastguard Worker 
4206*5e7646d2SAndroid Build Coastguard Worker 	  bytes += (size_t)attr->num_values * 26;
4207*5e7646d2SAndroid Build Coastguard Worker 	  break;
4208*5e7646d2SAndroid Build Coastguard Worker 
4209*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_STRING :
4210*5e7646d2SAndroid Build Coastguard Worker          /*
4211*5e7646d2SAndroid Build Coastguard Worker 	  * Octet strings can contain characters that need quoting.  We need
4212*5e7646d2SAndroid Build Coastguard Worker 	  * at least 2 * len + 2 characters to cover the quotes and any
4213*5e7646d2SAndroid Build Coastguard Worker 	  * backslashes in the string.
4214*5e7646d2SAndroid Build Coastguard Worker 	  */
4215*5e7646d2SAndroid Build Coastguard Worker 
4216*5e7646d2SAndroid Build Coastguard Worker           for (i = 0; i < attr->num_values; i ++)
4217*5e7646d2SAndroid Build Coastguard Worker 	    bytes += 2 * (size_t)attr->values[i].unknown.length + 2;
4218*5e7646d2SAndroid Build Coastguard Worker 	  break;
4219*5e7646d2SAndroid Build Coastguard Worker 
4220*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_TEXT :
4221*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_NAME :
4222*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_KEYWORD :
4223*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_CHARSET :
4224*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_LANGUAGE :
4225*5e7646d2SAndroid Build Coastguard Worker       case IPP_TAG_URI :
4226*5e7646d2SAndroid Build Coastguard Worker          /*
4227*5e7646d2SAndroid Build Coastguard Worker 	  * Strings can contain characters that need quoting.  We need
4228*5e7646d2SAndroid Build Coastguard Worker 	  * at least 2 * len + 2 characters to cover the quotes and
4229*5e7646d2SAndroid Build Coastguard Worker 	  * any backslashes in the string.
4230*5e7646d2SAndroid Build Coastguard Worker 	  */
4231*5e7646d2SAndroid Build Coastguard Worker 
4232*5e7646d2SAndroid Build Coastguard Worker           for (i = 0; i < attr->num_values; i ++)
4233*5e7646d2SAndroid Build Coastguard Worker 	    bytes += 2 * strlen(attr->values[i].string.text) + 2;
4234*5e7646d2SAndroid Build Coastguard Worker 	  break;
4235*5e7646d2SAndroid Build Coastguard Worker 
4236*5e7646d2SAndroid Build Coastguard Worker        default :
4237*5e7646d2SAndroid Build Coastguard Worker 	  break; /* anti-compiler-warning-code */
4238*5e7646d2SAndroid Build Coastguard Worker     }
4239*5e7646d2SAndroid Build Coastguard Worker   }
4240*5e7646d2SAndroid Build Coastguard Worker 
4241*5e7646d2SAndroid Build Coastguard Worker   return (bytes);
4242*5e7646d2SAndroid Build Coastguard Worker }
4243*5e7646d2SAndroid Build Coastguard Worker 
4244*5e7646d2SAndroid Build Coastguard Worker 
4245*5e7646d2SAndroid Build Coastguard Worker /*
4246*5e7646d2SAndroid Build Coastguard Worker  * 'load_job_cache()' - Load jobs from the job.cache file.
4247*5e7646d2SAndroid Build Coastguard Worker  */
4248*5e7646d2SAndroid Build Coastguard Worker 
4249*5e7646d2SAndroid Build Coastguard Worker static void
load_job_cache(const char * filename)4250*5e7646d2SAndroid Build Coastguard Worker load_job_cache(const char *filename)	/* I - job.cache filename */
4251*5e7646d2SAndroid Build Coastguard Worker {
4252*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*fp;			/* job.cache file */
4253*5e7646d2SAndroid Build Coastguard Worker   char		line[1024],		/* Line buffer */
4254*5e7646d2SAndroid Build Coastguard Worker 		*value;			/* Value on line */
4255*5e7646d2SAndroid Build Coastguard Worker   int		linenum;		/* Line number in file */
4256*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t	*job;			/* Current job */
4257*5e7646d2SAndroid Build Coastguard Worker   int		jobid;			/* Job ID */
4258*5e7646d2SAndroid Build Coastguard Worker   char		jobfile[1024];		/* Job filename */
4259*5e7646d2SAndroid Build Coastguard Worker 
4260*5e7646d2SAndroid Build Coastguard Worker 
4261*5e7646d2SAndroid Build Coastguard Worker  /*
4262*5e7646d2SAndroid Build Coastguard Worker   * Open the job.cache file...
4263*5e7646d2SAndroid Build Coastguard Worker   */
4264*5e7646d2SAndroid Build Coastguard Worker 
4265*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsdOpenConfFile(filename)) == NULL)
4266*5e7646d2SAndroid Build Coastguard Worker   {
4267*5e7646d2SAndroid Build Coastguard Worker     load_request_root();
4268*5e7646d2SAndroid Build Coastguard Worker     return;
4269*5e7646d2SAndroid Build Coastguard Worker   }
4270*5e7646d2SAndroid Build Coastguard Worker 
4271*5e7646d2SAndroid Build Coastguard Worker  /*
4272*5e7646d2SAndroid Build Coastguard Worker   * Read entries from the job cache file and create jobs as needed.
4273*5e7646d2SAndroid Build Coastguard Worker   */
4274*5e7646d2SAndroid Build Coastguard Worker 
4275*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_INFO, "Loading job cache file \"%s\"...",
4276*5e7646d2SAndroid Build Coastguard Worker                   filename);
4277*5e7646d2SAndroid Build Coastguard Worker 
4278*5e7646d2SAndroid Build Coastguard Worker   linenum = 0;
4279*5e7646d2SAndroid Build Coastguard Worker   job     = NULL;
4280*5e7646d2SAndroid Build Coastguard Worker 
4281*5e7646d2SAndroid Build Coastguard Worker   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
4282*5e7646d2SAndroid Build Coastguard Worker   {
4283*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strcasecmp(line, "NextJobId"))
4284*5e7646d2SAndroid Build Coastguard Worker     {
4285*5e7646d2SAndroid Build Coastguard Worker       if (value)
4286*5e7646d2SAndroid Build Coastguard Worker         NextJobId = atoi(value);
4287*5e7646d2SAndroid Build Coastguard Worker     }
4288*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "<Job"))
4289*5e7646d2SAndroid Build Coastguard Worker     {
4290*5e7646d2SAndroid Build Coastguard Worker       if (job)
4291*5e7646d2SAndroid Build Coastguard Worker       {
4292*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_ERROR, "Missing </Job> directive on line %d of %s.", linenum, filename);
4293*5e7646d2SAndroid Build Coastguard Worker         continue;
4294*5e7646d2SAndroid Build Coastguard Worker       }
4295*5e7646d2SAndroid Build Coastguard Worker 
4296*5e7646d2SAndroid Build Coastguard Worker       if (!value)
4297*5e7646d2SAndroid Build Coastguard Worker       {
4298*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_ERROR, "Missing job ID on line %d of %s.", linenum, filename);
4299*5e7646d2SAndroid Build Coastguard Worker 	continue;
4300*5e7646d2SAndroid Build Coastguard Worker       }
4301*5e7646d2SAndroid Build Coastguard Worker 
4302*5e7646d2SAndroid Build Coastguard Worker       jobid = atoi(value);
4303*5e7646d2SAndroid Build Coastguard Worker 
4304*5e7646d2SAndroid Build Coastguard Worker       if (jobid < 1)
4305*5e7646d2SAndroid Build Coastguard Worker       {
4306*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_ERROR, "Bad job ID %d on line %d of %s.", jobid, linenum, filename);
4307*5e7646d2SAndroid Build Coastguard Worker         continue;
4308*5e7646d2SAndroid Build Coastguard Worker       }
4309*5e7646d2SAndroid Build Coastguard Worker 
4310*5e7646d2SAndroid Build Coastguard Worker       snprintf(jobfile, sizeof(jobfile), "%s/c%05d", RequestRoot, jobid);
4311*5e7646d2SAndroid Build Coastguard Worker       if (access(jobfile, 0))
4312*5e7646d2SAndroid Build Coastguard Worker       {
4313*5e7646d2SAndroid Build Coastguard Worker 	snprintf(jobfile, sizeof(jobfile), "%s/c%05d.N", RequestRoot, jobid);
4314*5e7646d2SAndroid Build Coastguard Worker 	if (access(jobfile, 0))
4315*5e7646d2SAndroid Build Coastguard Worker 	{
4316*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogMessage(CUPSD_LOG_ERROR, "[Job %d] Files have gone away.",
4317*5e7646d2SAndroid Build Coastguard Worker 			  jobid);
4318*5e7646d2SAndroid Build Coastguard Worker 
4319*5e7646d2SAndroid Build Coastguard Worker          /*
4320*5e7646d2SAndroid Build Coastguard Worker           * job.cache file is out-of-date compared to spool directory; load
4321*5e7646d2SAndroid Build Coastguard Worker           * that instead...
4322*5e7646d2SAndroid Build Coastguard Worker           */
4323*5e7646d2SAndroid Build Coastguard Worker 
4324*5e7646d2SAndroid Build Coastguard Worker 	  cupsFileClose(fp);
4325*5e7646d2SAndroid Build Coastguard Worker           load_request_root();
4326*5e7646d2SAndroid Build Coastguard Worker           return;
4327*5e7646d2SAndroid Build Coastguard Worker 	}
4328*5e7646d2SAndroid Build Coastguard Worker       }
4329*5e7646d2SAndroid Build Coastguard Worker 
4330*5e7646d2SAndroid Build Coastguard Worker       job = calloc(1, sizeof(cupsd_job_t));
4331*5e7646d2SAndroid Build Coastguard Worker       if (!job)
4332*5e7646d2SAndroid Build Coastguard Worker       {
4333*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_EMERG,
4334*5e7646d2SAndroid Build Coastguard Worker 		        "[Job %d] Unable to allocate memory for job.", jobid);
4335*5e7646d2SAndroid Build Coastguard Worker         break;
4336*5e7646d2SAndroid Build Coastguard Worker       }
4337*5e7646d2SAndroid Build Coastguard Worker 
4338*5e7646d2SAndroid Build Coastguard Worker       job->id              = jobid;
4339*5e7646d2SAndroid Build Coastguard Worker       job->back_pipes[0]   = -1;
4340*5e7646d2SAndroid Build Coastguard Worker       job->back_pipes[1]   = -1;
4341*5e7646d2SAndroid Build Coastguard Worker       job->print_pipes[0]  = -1;
4342*5e7646d2SAndroid Build Coastguard Worker       job->print_pipes[1]  = -1;
4343*5e7646d2SAndroid Build Coastguard Worker       job->side_pipes[0]   = -1;
4344*5e7646d2SAndroid Build Coastguard Worker       job->side_pipes[1]   = -1;
4345*5e7646d2SAndroid Build Coastguard Worker       job->status_pipes[0] = -1;
4346*5e7646d2SAndroid Build Coastguard Worker       job->status_pipes[1] = -1;
4347*5e7646d2SAndroid Build Coastguard Worker 
4348*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "Loading from cache...");
4349*5e7646d2SAndroid Build Coastguard Worker     }
4350*5e7646d2SAndroid Build Coastguard Worker     else if (!job)
4351*5e7646d2SAndroid Build Coastguard Worker     {
4352*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR,
4353*5e7646d2SAndroid Build Coastguard Worker 	              "Missing <Job #> directive on line %d of %s.", linenum, filename);
4354*5e7646d2SAndroid Build Coastguard Worker       continue;
4355*5e7646d2SAndroid Build Coastguard Worker     }
4356*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "</Job>"))
4357*5e7646d2SAndroid Build Coastguard Worker     {
4358*5e7646d2SAndroid Build Coastguard Worker       cupsArrayAdd(Jobs, job);
4359*5e7646d2SAndroid Build Coastguard Worker 
4360*5e7646d2SAndroid Build Coastguard Worker       if (job->state_value <= IPP_JOB_STOPPED && cupsdLoadJob(job))
4361*5e7646d2SAndroid Build Coastguard Worker 	cupsArrayAdd(ActiveJobs, job);
4362*5e7646d2SAndroid Build Coastguard Worker       else if (job->state_value > IPP_JOB_STOPPED)
4363*5e7646d2SAndroid Build Coastguard Worker       {
4364*5e7646d2SAndroid Build Coastguard Worker         if (!job->completed_time || !job->creation_time || !job->name || !job->koctets)
4365*5e7646d2SAndroid Build Coastguard Worker 	{
4366*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLoadJob(job);
4367*5e7646d2SAndroid Build Coastguard Worker 	  unload_job(job);
4368*5e7646d2SAndroid Build Coastguard Worker 	}
4369*5e7646d2SAndroid Build Coastguard Worker       }
4370*5e7646d2SAndroid Build Coastguard Worker 
4371*5e7646d2SAndroid Build Coastguard Worker       job = NULL;
4372*5e7646d2SAndroid Build Coastguard Worker     }
4373*5e7646d2SAndroid Build Coastguard Worker     else if (!value)
4374*5e7646d2SAndroid Build Coastguard Worker     {
4375*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value on line %d of %s.", linenum, filename);
4376*5e7646d2SAndroid Build Coastguard Worker       continue;
4377*5e7646d2SAndroid Build Coastguard Worker     }
4378*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "State"))
4379*5e7646d2SAndroid Build Coastguard Worker     {
4380*5e7646d2SAndroid Build Coastguard Worker       job->state_value = (ipp_jstate_t)atoi(value);
4381*5e7646d2SAndroid Build Coastguard Worker 
4382*5e7646d2SAndroid Build Coastguard Worker       if (job->state_value < IPP_JOB_PENDING)
4383*5e7646d2SAndroid Build Coastguard Worker         job->state_value = IPP_JOB_PENDING;
4384*5e7646d2SAndroid Build Coastguard Worker       else if (job->state_value > IPP_JOB_COMPLETED)
4385*5e7646d2SAndroid Build Coastguard Worker         job->state_value = IPP_JOB_COMPLETED;
4386*5e7646d2SAndroid Build Coastguard Worker     }
4387*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "Name"))
4388*5e7646d2SAndroid Build Coastguard Worker     {
4389*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&(job->name), value);
4390*5e7646d2SAndroid Build Coastguard Worker     }
4391*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "Created"))
4392*5e7646d2SAndroid Build Coastguard Worker     {
4393*5e7646d2SAndroid Build Coastguard Worker       job->creation_time = strtol(value, NULL, 10);
4394*5e7646d2SAndroid Build Coastguard Worker     }
4395*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "Completed"))
4396*5e7646d2SAndroid Build Coastguard Worker     {
4397*5e7646d2SAndroid Build Coastguard Worker       job->completed_time = strtol(value, NULL, 10);
4398*5e7646d2SAndroid Build Coastguard Worker     }
4399*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "HoldUntil"))
4400*5e7646d2SAndroid Build Coastguard Worker     {
4401*5e7646d2SAndroid Build Coastguard Worker       job->hold_until = strtol(value, NULL, 10);
4402*5e7646d2SAndroid Build Coastguard Worker     }
4403*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "Priority"))
4404*5e7646d2SAndroid Build Coastguard Worker     {
4405*5e7646d2SAndroid Build Coastguard Worker       job->priority = atoi(value);
4406*5e7646d2SAndroid Build Coastguard Worker     }
4407*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "Username"))
4408*5e7646d2SAndroid Build Coastguard Worker     {
4409*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&job->username, value);
4410*5e7646d2SAndroid Build Coastguard Worker     }
4411*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "Destination"))
4412*5e7646d2SAndroid Build Coastguard Worker     {
4413*5e7646d2SAndroid Build Coastguard Worker       cupsdSetString(&job->dest, value);
4414*5e7646d2SAndroid Build Coastguard Worker     }
4415*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "DestType"))
4416*5e7646d2SAndroid Build Coastguard Worker     {
4417*5e7646d2SAndroid Build Coastguard Worker       job->dtype = (cups_ptype_t)atoi(value);
4418*5e7646d2SAndroid Build Coastguard Worker     }
4419*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "KOctets"))
4420*5e7646d2SAndroid Build Coastguard Worker     {
4421*5e7646d2SAndroid Build Coastguard Worker       job->koctets = atoi(value);
4422*5e7646d2SAndroid Build Coastguard Worker     }
4423*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "NumFiles"))
4424*5e7646d2SAndroid Build Coastguard Worker     {
4425*5e7646d2SAndroid Build Coastguard Worker       job->num_files = atoi(value);
4426*5e7646d2SAndroid Build Coastguard Worker 
4427*5e7646d2SAndroid Build Coastguard Worker       if (job->num_files < 0)
4428*5e7646d2SAndroid Build Coastguard Worker       {
4429*5e7646d2SAndroid Build Coastguard Worker 	cupsdLogMessage(CUPSD_LOG_ERROR, "Bad NumFiles value %d on line %d of %s.", job->num_files, linenum, filename);
4430*5e7646d2SAndroid Build Coastguard Worker         job->num_files = 0;
4431*5e7646d2SAndroid Build Coastguard Worker 	continue;
4432*5e7646d2SAndroid Build Coastguard Worker       }
4433*5e7646d2SAndroid Build Coastguard Worker 
4434*5e7646d2SAndroid Build Coastguard Worker       if (job->num_files > 0)
4435*5e7646d2SAndroid Build Coastguard Worker       {
4436*5e7646d2SAndroid Build Coastguard Worker         snprintf(jobfile, sizeof(jobfile), "%s/d%05d-001", RequestRoot,
4437*5e7646d2SAndroid Build Coastguard Worker 	         job->id);
4438*5e7646d2SAndroid Build Coastguard Worker         if (access(jobfile, 0))
4439*5e7646d2SAndroid Build Coastguard Worker 	{
4440*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogJob(job, CUPSD_LOG_INFO, "Data files have gone away.");
4441*5e7646d2SAndroid Build Coastguard Worker           job->num_files = 0;
4442*5e7646d2SAndroid Build Coastguard Worker 	  continue;
4443*5e7646d2SAndroid Build Coastguard Worker 	}
4444*5e7646d2SAndroid Build Coastguard Worker 
4445*5e7646d2SAndroid Build Coastguard Worker         job->filetypes    = calloc((size_t)job->num_files, sizeof(mime_type_t *));
4446*5e7646d2SAndroid Build Coastguard Worker 	job->compressions = calloc((size_t)job->num_files, sizeof(int));
4447*5e7646d2SAndroid Build Coastguard Worker 
4448*5e7646d2SAndroid Build Coastguard Worker         if (!job->filetypes || !job->compressions)
4449*5e7646d2SAndroid Build Coastguard Worker 	{
4450*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogJob(job, CUPSD_LOG_EMERG,
4451*5e7646d2SAndroid Build Coastguard Worker 		      "Unable to allocate memory for %d files.",
4452*5e7646d2SAndroid Build Coastguard Worker 		      job->num_files);
4453*5e7646d2SAndroid Build Coastguard Worker           break;
4454*5e7646d2SAndroid Build Coastguard Worker 	}
4455*5e7646d2SAndroid Build Coastguard Worker       }
4456*5e7646d2SAndroid Build Coastguard Worker     }
4457*5e7646d2SAndroid Build Coastguard Worker     else if (!_cups_strcasecmp(line, "File"))
4458*5e7646d2SAndroid Build Coastguard Worker     {
4459*5e7646d2SAndroid Build Coastguard Worker       int	number,			/* File number */
4460*5e7646d2SAndroid Build Coastguard Worker 		compression;		/* Compression value */
4461*5e7646d2SAndroid Build Coastguard Worker       char	super[MIME_MAX_SUPER],	/* MIME super type */
4462*5e7646d2SAndroid Build Coastguard Worker 		type[MIME_MAX_TYPE];	/* MIME type */
4463*5e7646d2SAndroid Build Coastguard Worker 
4464*5e7646d2SAndroid Build Coastguard Worker 
4465*5e7646d2SAndroid Build Coastguard Worker       if (sscanf(value, "%d%*[ \t]%15[^/]/%255s%d", &number, super, type,
4466*5e7646d2SAndroid Build Coastguard Worker                  &compression) != 4)
4467*5e7646d2SAndroid Build Coastguard Worker       {
4468*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File on line %d of %s.", linenum, filename);
4469*5e7646d2SAndroid Build Coastguard Worker 	continue;
4470*5e7646d2SAndroid Build Coastguard Worker       }
4471*5e7646d2SAndroid Build Coastguard Worker 
4472*5e7646d2SAndroid Build Coastguard Worker       if (number < 1 || number > job->num_files)
4473*5e7646d2SAndroid Build Coastguard Worker       {
4474*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_ERROR, "Bad File number %d on line %d of %s.", number, linenum, filename);
4475*5e7646d2SAndroid Build Coastguard Worker         continue;
4476*5e7646d2SAndroid Build Coastguard Worker       }
4477*5e7646d2SAndroid Build Coastguard Worker 
4478*5e7646d2SAndroid Build Coastguard Worker       number --;
4479*5e7646d2SAndroid Build Coastguard Worker 
4480*5e7646d2SAndroid Build Coastguard Worker       job->compressions[number] = compression;
4481*5e7646d2SAndroid Build Coastguard Worker       job->filetypes[number]    = mimeType(MimeDatabase, super, type);
4482*5e7646d2SAndroid Build Coastguard Worker 
4483*5e7646d2SAndroid Build Coastguard Worker       if (!job->filetypes[number])
4484*5e7646d2SAndroid Build Coastguard Worker       {
4485*5e7646d2SAndroid Build Coastguard Worker        /*
4486*5e7646d2SAndroid Build Coastguard Worker         * If the original MIME type is unknown, auto-type it!
4487*5e7646d2SAndroid Build Coastguard Worker 	*/
4488*5e7646d2SAndroid Build Coastguard Worker 
4489*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, CUPSD_LOG_ERROR,
4490*5e7646d2SAndroid Build Coastguard Worker 		    "Unknown MIME type %s/%s for file %d.",
4491*5e7646d2SAndroid Build Coastguard Worker 		    super, type, number + 1);
4492*5e7646d2SAndroid Build Coastguard Worker 
4493*5e7646d2SAndroid Build Coastguard Worker         snprintf(jobfile, sizeof(jobfile), "%s/d%05d-%03d", RequestRoot,
4494*5e7646d2SAndroid Build Coastguard Worker 	         job->id, number + 1);
4495*5e7646d2SAndroid Build Coastguard Worker         job->filetypes[number] = mimeFileType(MimeDatabase, jobfile, NULL,
4496*5e7646d2SAndroid Build Coastguard Worker 	                                      job->compressions + number);
4497*5e7646d2SAndroid Build Coastguard Worker 
4498*5e7646d2SAndroid Build Coastguard Worker        /*
4499*5e7646d2SAndroid Build Coastguard Worker         * If that didn't work, assume it is raw...
4500*5e7646d2SAndroid Build Coastguard Worker 	*/
4501*5e7646d2SAndroid Build Coastguard Worker 
4502*5e7646d2SAndroid Build Coastguard Worker         if (!job->filetypes[number])
4503*5e7646d2SAndroid Build Coastguard Worker 	  job->filetypes[number] = mimeType(MimeDatabase, "application",
4504*5e7646d2SAndroid Build Coastguard Worker 	                                    "vnd.cups-raw");
4505*5e7646d2SAndroid Build Coastguard Worker       }
4506*5e7646d2SAndroid Build Coastguard Worker     }
4507*5e7646d2SAndroid Build Coastguard Worker     else
4508*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown %s directive on line %d of %s.", line, linenum, filename);
4509*5e7646d2SAndroid Build Coastguard Worker   }
4510*5e7646d2SAndroid Build Coastguard Worker 
4511*5e7646d2SAndroid Build Coastguard Worker   if (job)
4512*5e7646d2SAndroid Build Coastguard Worker   {
4513*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
4514*5e7646d2SAndroid Build Coastguard Worker 		    "Missing </Job> directive on line %d of %s.", linenum, filename);
4515*5e7646d2SAndroid Build Coastguard Worker     cupsdDeleteJob(job, CUPSD_JOB_PURGE);
4516*5e7646d2SAndroid Build Coastguard Worker   }
4517*5e7646d2SAndroid Build Coastguard Worker 
4518*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
4519*5e7646d2SAndroid Build Coastguard Worker }
4520*5e7646d2SAndroid Build Coastguard Worker 
4521*5e7646d2SAndroid Build Coastguard Worker 
4522*5e7646d2SAndroid Build Coastguard Worker /*
4523*5e7646d2SAndroid Build Coastguard Worker  * 'load_next_job_id()' - Load the NextJobId value from the job.cache file.
4524*5e7646d2SAndroid Build Coastguard Worker  */
4525*5e7646d2SAndroid Build Coastguard Worker 
4526*5e7646d2SAndroid Build Coastguard Worker static void
load_next_job_id(const char * filename)4527*5e7646d2SAndroid Build Coastguard Worker load_next_job_id(const char *filename)	/* I - job.cache filename */
4528*5e7646d2SAndroid Build Coastguard Worker {
4529*5e7646d2SAndroid Build Coastguard Worker   cups_file_t	*fp;			/* job.cache file */
4530*5e7646d2SAndroid Build Coastguard Worker   char		line[1024],		/* Line buffer */
4531*5e7646d2SAndroid Build Coastguard Worker 		*value;			/* Value on line */
4532*5e7646d2SAndroid Build Coastguard Worker   int		linenum;		/* Line number in file */
4533*5e7646d2SAndroid Build Coastguard Worker   int		next_job_id;		/* NextJobId value from line */
4534*5e7646d2SAndroid Build Coastguard Worker 
4535*5e7646d2SAndroid Build Coastguard Worker 
4536*5e7646d2SAndroid Build Coastguard Worker  /*
4537*5e7646d2SAndroid Build Coastguard Worker   * Read the NextJobId directive from the job.cache file and use
4538*5e7646d2SAndroid Build Coastguard Worker   * the value (if any).
4539*5e7646d2SAndroid Build Coastguard Worker   */
4540*5e7646d2SAndroid Build Coastguard Worker 
4541*5e7646d2SAndroid Build Coastguard Worker   if ((fp = cupsFileOpen(filename, "r")) == NULL)
4542*5e7646d2SAndroid Build Coastguard Worker   {
4543*5e7646d2SAndroid Build Coastguard Worker     if (errno != ENOENT)
4544*5e7646d2SAndroid Build Coastguard Worker       cupsdLogMessage(CUPSD_LOG_ERROR,
4545*5e7646d2SAndroid Build Coastguard Worker                       "Unable to open job cache file \"%s\": %s",
4546*5e7646d2SAndroid Build Coastguard Worker                       filename, strerror(errno));
4547*5e7646d2SAndroid Build Coastguard Worker 
4548*5e7646d2SAndroid Build Coastguard Worker     return;
4549*5e7646d2SAndroid Build Coastguard Worker   }
4550*5e7646d2SAndroid Build Coastguard Worker 
4551*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_INFO,
4552*5e7646d2SAndroid Build Coastguard Worker                   "Loading NextJobId from job cache file \"%s\"...", filename);
4553*5e7646d2SAndroid Build Coastguard Worker 
4554*5e7646d2SAndroid Build Coastguard Worker   linenum = 0;
4555*5e7646d2SAndroid Build Coastguard Worker 
4556*5e7646d2SAndroid Build Coastguard Worker   while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
4557*5e7646d2SAndroid Build Coastguard Worker   {
4558*5e7646d2SAndroid Build Coastguard Worker     if (!_cups_strcasecmp(line, "NextJobId"))
4559*5e7646d2SAndroid Build Coastguard Worker     {
4560*5e7646d2SAndroid Build Coastguard Worker       if (value)
4561*5e7646d2SAndroid Build Coastguard Worker       {
4562*5e7646d2SAndroid Build Coastguard Worker         next_job_id = atoi(value);
4563*5e7646d2SAndroid Build Coastguard Worker 
4564*5e7646d2SAndroid Build Coastguard Worker         if (next_job_id > NextJobId)
4565*5e7646d2SAndroid Build Coastguard Worker 	  NextJobId = next_job_id;
4566*5e7646d2SAndroid Build Coastguard Worker       }
4567*5e7646d2SAndroid Build Coastguard Worker       break;
4568*5e7646d2SAndroid Build Coastguard Worker     }
4569*5e7646d2SAndroid Build Coastguard Worker   }
4570*5e7646d2SAndroid Build Coastguard Worker 
4571*5e7646d2SAndroid Build Coastguard Worker   cupsFileClose(fp);
4572*5e7646d2SAndroid Build Coastguard Worker }
4573*5e7646d2SAndroid Build Coastguard Worker 
4574*5e7646d2SAndroid Build Coastguard Worker 
4575*5e7646d2SAndroid Build Coastguard Worker /*
4576*5e7646d2SAndroid Build Coastguard Worker  * 'load_request_root()' - Load jobs from the RequestRoot directory.
4577*5e7646d2SAndroid Build Coastguard Worker  */
4578*5e7646d2SAndroid Build Coastguard Worker 
4579*5e7646d2SAndroid Build Coastguard Worker static void
load_request_root(void)4580*5e7646d2SAndroid Build Coastguard Worker load_request_root(void)
4581*5e7646d2SAndroid Build Coastguard Worker {
4582*5e7646d2SAndroid Build Coastguard Worker   cups_dir_t		*dir;		/* Directory */
4583*5e7646d2SAndroid Build Coastguard Worker   cups_dentry_t		*dent;		/* Directory entry */
4584*5e7646d2SAndroid Build Coastguard Worker   cupsd_job_t		*job;		/* New job */
4585*5e7646d2SAndroid Build Coastguard Worker 
4586*5e7646d2SAndroid Build Coastguard Worker 
4587*5e7646d2SAndroid Build Coastguard Worker  /*
4588*5e7646d2SAndroid Build Coastguard Worker   * Open the requests directory...
4589*5e7646d2SAndroid Build Coastguard Worker   */
4590*5e7646d2SAndroid Build Coastguard Worker 
4591*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG, "Scanning %s for jobs...", RequestRoot);
4592*5e7646d2SAndroid Build Coastguard Worker 
4593*5e7646d2SAndroid Build Coastguard Worker   if ((dir = cupsDirOpen(RequestRoot)) == NULL)
4594*5e7646d2SAndroid Build Coastguard Worker   {
4595*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_ERROR,
4596*5e7646d2SAndroid Build Coastguard Worker                     "Unable to open spool directory \"%s\": %s",
4597*5e7646d2SAndroid Build Coastguard Worker                     RequestRoot, strerror(errno));
4598*5e7646d2SAndroid Build Coastguard Worker     return;
4599*5e7646d2SAndroid Build Coastguard Worker   }
4600*5e7646d2SAndroid Build Coastguard Worker 
4601*5e7646d2SAndroid Build Coastguard Worker  /*
4602*5e7646d2SAndroid Build Coastguard Worker   * Read all the c##### files...
4603*5e7646d2SAndroid Build Coastguard Worker   */
4604*5e7646d2SAndroid Build Coastguard Worker 
4605*5e7646d2SAndroid Build Coastguard Worker   while ((dent = cupsDirRead(dir)) != NULL)
4606*5e7646d2SAndroid Build Coastguard Worker     if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c')
4607*5e7646d2SAndroid Build Coastguard Worker     {
4608*5e7646d2SAndroid Build Coastguard Worker      /*
4609*5e7646d2SAndroid Build Coastguard Worker       * Allocate memory for the job...
4610*5e7646d2SAndroid Build Coastguard Worker       */
4611*5e7646d2SAndroid Build Coastguard Worker 
4612*5e7646d2SAndroid Build Coastguard Worker       if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL)
4613*5e7646d2SAndroid Build Coastguard Worker       {
4614*5e7646d2SAndroid Build Coastguard Worker         cupsdLogMessage(CUPSD_LOG_ERROR, "Ran out of memory for jobs.");
4615*5e7646d2SAndroid Build Coastguard Worker 	cupsDirClose(dir);
4616*5e7646d2SAndroid Build Coastguard Worker 	return;
4617*5e7646d2SAndroid Build Coastguard Worker       }
4618*5e7646d2SAndroid Build Coastguard Worker 
4619*5e7646d2SAndroid Build Coastguard Worker      /*
4620*5e7646d2SAndroid Build Coastguard Worker       * Assign the job ID...
4621*5e7646d2SAndroid Build Coastguard Worker       */
4622*5e7646d2SAndroid Build Coastguard Worker 
4623*5e7646d2SAndroid Build Coastguard Worker       job->id              = atoi(dent->filename + 1);
4624*5e7646d2SAndroid Build Coastguard Worker       job->back_pipes[0]   = -1;
4625*5e7646d2SAndroid Build Coastguard Worker       job->back_pipes[1]   = -1;
4626*5e7646d2SAndroid Build Coastguard Worker       job->print_pipes[0]  = -1;
4627*5e7646d2SAndroid Build Coastguard Worker       job->print_pipes[1]  = -1;
4628*5e7646d2SAndroid Build Coastguard Worker       job->side_pipes[0]   = -1;
4629*5e7646d2SAndroid Build Coastguard Worker       job->side_pipes[1]   = -1;
4630*5e7646d2SAndroid Build Coastguard Worker       job->status_pipes[0] = -1;
4631*5e7646d2SAndroid Build Coastguard Worker       job->status_pipes[1] = -1;
4632*5e7646d2SAndroid Build Coastguard Worker 
4633*5e7646d2SAndroid Build Coastguard Worker       if (job->id >= NextJobId)
4634*5e7646d2SAndroid Build Coastguard Worker         NextJobId = job->id + 1;
4635*5e7646d2SAndroid Build Coastguard Worker 
4636*5e7646d2SAndroid Build Coastguard Worker      /*
4637*5e7646d2SAndroid Build Coastguard Worker       * Load the job...
4638*5e7646d2SAndroid Build Coastguard Worker       */
4639*5e7646d2SAndroid Build Coastguard Worker 
4640*5e7646d2SAndroid Build Coastguard Worker       if (cupsdLoadJob(job))
4641*5e7646d2SAndroid Build Coastguard Worker       {
4642*5e7646d2SAndroid Build Coastguard Worker        /*
4643*5e7646d2SAndroid Build Coastguard Worker         * Insert the job into the array, sorting by job priority and ID...
4644*5e7646d2SAndroid Build Coastguard Worker         */
4645*5e7646d2SAndroid Build Coastguard Worker 
4646*5e7646d2SAndroid Build Coastguard Worker 	cupsArrayAdd(Jobs, job);
4647*5e7646d2SAndroid Build Coastguard Worker 
4648*5e7646d2SAndroid Build Coastguard Worker 	if (job->state_value <= IPP_JOB_STOPPED)
4649*5e7646d2SAndroid Build Coastguard Worker 	  cupsArrayAdd(ActiveJobs, job);
4650*5e7646d2SAndroid Build Coastguard Worker 	else
4651*5e7646d2SAndroid Build Coastguard Worker 	  unload_job(job);
4652*5e7646d2SAndroid Build Coastguard Worker       }
4653*5e7646d2SAndroid Build Coastguard Worker       else
4654*5e7646d2SAndroid Build Coastguard Worker         free(job);
4655*5e7646d2SAndroid Build Coastguard Worker     }
4656*5e7646d2SAndroid Build Coastguard Worker 
4657*5e7646d2SAndroid Build Coastguard Worker   cupsDirClose(dir);
4658*5e7646d2SAndroid Build Coastguard Worker }
4659*5e7646d2SAndroid Build Coastguard Worker 
4660*5e7646d2SAndroid Build Coastguard Worker 
4661*5e7646d2SAndroid Build Coastguard Worker /*
4662*5e7646d2SAndroid Build Coastguard Worker  * 'remove_job_files()' - Remove the document files for a job.
4663*5e7646d2SAndroid Build Coastguard Worker  */
4664*5e7646d2SAndroid Build Coastguard Worker 
4665*5e7646d2SAndroid Build Coastguard Worker static void
remove_job_files(cupsd_job_t * job)4666*5e7646d2SAndroid Build Coastguard Worker remove_job_files(cupsd_job_t *job)	/* I - Job */
4667*5e7646d2SAndroid Build Coastguard Worker {
4668*5e7646d2SAndroid Build Coastguard Worker   int	i;				/* Looping var */
4669*5e7646d2SAndroid Build Coastguard Worker   char	filename[1024];			/* Document filename */
4670*5e7646d2SAndroid Build Coastguard Worker 
4671*5e7646d2SAndroid Build Coastguard Worker 
4672*5e7646d2SAndroid Build Coastguard Worker   if (job->num_files <= 0)
4673*5e7646d2SAndroid Build Coastguard Worker     return;
4674*5e7646d2SAndroid Build Coastguard Worker 
4675*5e7646d2SAndroid Build Coastguard Worker   for (i = 1; i <= job->num_files; i ++)
4676*5e7646d2SAndroid Build Coastguard Worker   {
4677*5e7646d2SAndroid Build Coastguard Worker     snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
4678*5e7646d2SAndroid Build Coastguard Worker 	     job->id, i);
4679*5e7646d2SAndroid Build Coastguard Worker     cupsdUnlinkOrRemoveFile(filename);
4680*5e7646d2SAndroid Build Coastguard Worker   }
4681*5e7646d2SAndroid Build Coastguard Worker 
4682*5e7646d2SAndroid Build Coastguard Worker   free(job->filetypes);
4683*5e7646d2SAndroid Build Coastguard Worker   free(job->compressions);
4684*5e7646d2SAndroid Build Coastguard Worker 
4685*5e7646d2SAndroid Build Coastguard Worker   job->file_time    = 0;
4686*5e7646d2SAndroid Build Coastguard Worker   job->num_files    = 0;
4687*5e7646d2SAndroid Build Coastguard Worker   job->filetypes    = NULL;
4688*5e7646d2SAndroid Build Coastguard Worker   job->compressions = NULL;
4689*5e7646d2SAndroid Build Coastguard Worker 
4690*5e7646d2SAndroid Build Coastguard Worker   LastEvent |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
4691*5e7646d2SAndroid Build Coastguard Worker }
4692*5e7646d2SAndroid Build Coastguard Worker 
4693*5e7646d2SAndroid Build Coastguard Worker 
4694*5e7646d2SAndroid Build Coastguard Worker /*
4695*5e7646d2SAndroid Build Coastguard Worker  * 'remove_job_history()' - Remove the control file for a job.
4696*5e7646d2SAndroid Build Coastguard Worker  */
4697*5e7646d2SAndroid Build Coastguard Worker 
4698*5e7646d2SAndroid Build Coastguard Worker static void
remove_job_history(cupsd_job_t * job)4699*5e7646d2SAndroid Build Coastguard Worker remove_job_history(cupsd_job_t *job)	/* I - Job */
4700*5e7646d2SAndroid Build Coastguard Worker {
4701*5e7646d2SAndroid Build Coastguard Worker   char	filename[1024];			/* Control filename */
4702*5e7646d2SAndroid Build Coastguard Worker 
4703*5e7646d2SAndroid Build Coastguard Worker 
4704*5e7646d2SAndroid Build Coastguard Worker  /*
4705*5e7646d2SAndroid Build Coastguard Worker   * Remove the job info file...
4706*5e7646d2SAndroid Build Coastguard Worker   */
4707*5e7646d2SAndroid Build Coastguard Worker 
4708*5e7646d2SAndroid Build Coastguard Worker   snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot,
4709*5e7646d2SAndroid Build Coastguard Worker 	   job->id);
4710*5e7646d2SAndroid Build Coastguard Worker   cupsdUnlinkOrRemoveFile(filename);
4711*5e7646d2SAndroid Build Coastguard Worker 
4712*5e7646d2SAndroid Build Coastguard Worker   LastEvent |= CUPSD_EVENT_PRINTER_STATE_CHANGED;
4713*5e7646d2SAndroid Build Coastguard Worker }
4714*5e7646d2SAndroid Build Coastguard Worker 
4715*5e7646d2SAndroid Build Coastguard Worker 
4716*5e7646d2SAndroid Build Coastguard Worker /*
4717*5e7646d2SAndroid Build Coastguard Worker  * 'set_time()' - Set one of the "time-at-xyz" attributes.
4718*5e7646d2SAndroid Build Coastguard Worker  */
4719*5e7646d2SAndroid Build Coastguard Worker 
4720*5e7646d2SAndroid Build Coastguard Worker static void
set_time(cupsd_job_t * job,const char * name)4721*5e7646d2SAndroid Build Coastguard Worker set_time(cupsd_job_t *job,		/* I - Job to update */
4722*5e7646d2SAndroid Build Coastguard Worker          const char  *name)		/* I - Name of attribute */
4723*5e7646d2SAndroid Build Coastguard Worker {
4724*5e7646d2SAndroid Build Coastguard Worker   char			date_name[128];	/* date-time-at-xxx */
4725*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t	*attr;		/* Time attribute */
4726*5e7646d2SAndroid Build Coastguard Worker   time_t		curtime;	/* Current time */
4727*5e7646d2SAndroid Build Coastguard Worker 
4728*5e7646d2SAndroid Build Coastguard Worker 
4729*5e7646d2SAndroid Build Coastguard Worker   curtime = time(NULL);
4730*5e7646d2SAndroid Build Coastguard Worker 
4731*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_DEBUG, "%s=%ld", name, (long)curtime);
4732*5e7646d2SAndroid Build Coastguard Worker 
4733*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL)
4734*5e7646d2SAndroid Build Coastguard Worker   {
4735*5e7646d2SAndroid Build Coastguard Worker     attr->value_tag         = IPP_TAG_INTEGER;
4736*5e7646d2SAndroid Build Coastguard Worker     attr->values[0].integer = curtime;
4737*5e7646d2SAndroid Build Coastguard Worker   }
4738*5e7646d2SAndroid Build Coastguard Worker 
4739*5e7646d2SAndroid Build Coastguard Worker   snprintf(date_name, sizeof(date_name), "date-%s", name);
4740*5e7646d2SAndroid Build Coastguard Worker 
4741*5e7646d2SAndroid Build Coastguard Worker   if ((attr = ippFindAttribute(job->attrs, date_name, IPP_TAG_ZERO)) != NULL)
4742*5e7646d2SAndroid Build Coastguard Worker   {
4743*5e7646d2SAndroid Build Coastguard Worker     attr->value_tag = IPP_TAG_DATE;
4744*5e7646d2SAndroid Build Coastguard Worker     ippSetDate(job->attrs, &attr, 0, ippTimeToDate(curtime));
4745*5e7646d2SAndroid Build Coastguard Worker   }
4746*5e7646d2SAndroid Build Coastguard Worker 
4747*5e7646d2SAndroid Build Coastguard Worker   if (!strcmp(name, "time-at-completed"))
4748*5e7646d2SAndroid Build Coastguard Worker   {
4749*5e7646d2SAndroid Build Coastguard Worker     job->completed_time = curtime;
4750*5e7646d2SAndroid Build Coastguard Worker 
4751*5e7646d2SAndroid Build Coastguard Worker     if (JobHistory < INT_MAX && attr)
4752*5e7646d2SAndroid Build Coastguard Worker       job->history_time = job->completed_time + JobHistory;
4753*5e7646d2SAndroid Build Coastguard Worker     else
4754*5e7646d2SAndroid Build Coastguard Worker       job->history_time = INT_MAX;
4755*5e7646d2SAndroid Build Coastguard Worker 
4756*5e7646d2SAndroid Build Coastguard Worker     if (job->history_time < JobHistoryUpdate || !JobHistoryUpdate)
4757*5e7646d2SAndroid Build Coastguard Worker       JobHistoryUpdate = job->history_time;
4758*5e7646d2SAndroid Build Coastguard Worker 
4759*5e7646d2SAndroid Build Coastguard Worker     if (JobFiles < INT_MAX && attr)
4760*5e7646d2SAndroid Build Coastguard Worker       job->file_time = job->completed_time + JobFiles;
4761*5e7646d2SAndroid Build Coastguard Worker     else
4762*5e7646d2SAndroid Build Coastguard Worker       job->file_time = INT_MAX;
4763*5e7646d2SAndroid Build Coastguard Worker 
4764*5e7646d2SAndroid Build Coastguard Worker     if (job->file_time < JobHistoryUpdate || !JobHistoryUpdate)
4765*5e7646d2SAndroid Build Coastguard Worker       JobHistoryUpdate = job->file_time;
4766*5e7646d2SAndroid Build Coastguard Worker 
4767*5e7646d2SAndroid Build Coastguard Worker     cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_time: JobHistoryUpdate=%ld",
4768*5e7646d2SAndroid Build Coastguard Worker 		    (long)JobHistoryUpdate);
4769*5e7646d2SAndroid Build Coastguard Worker   }
4770*5e7646d2SAndroid Build Coastguard Worker }
4771*5e7646d2SAndroid Build Coastguard Worker 
4772*5e7646d2SAndroid Build Coastguard Worker 
4773*5e7646d2SAndroid Build Coastguard Worker /*
4774*5e7646d2SAndroid Build Coastguard Worker  * 'start_job()' - Start a print job.
4775*5e7646d2SAndroid Build Coastguard Worker  */
4776*5e7646d2SAndroid Build Coastguard Worker 
4777*5e7646d2SAndroid Build Coastguard Worker static void
start_job(cupsd_job_t * job,cupsd_printer_t * printer)4778*5e7646d2SAndroid Build Coastguard Worker start_job(cupsd_job_t     *job,		/* I - Job ID */
4779*5e7646d2SAndroid Build Coastguard Worker           cupsd_printer_t *printer)	/* I - Printer to print job */
4780*5e7646d2SAndroid Build Coastguard Worker {
4781*5e7646d2SAndroid Build Coastguard Worker   const char	*filename;		/* Support filename */
4782*5e7646d2SAndroid Build Coastguard Worker   ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
4783*5e7646d2SAndroid Build Coastguard Worker 						   "job-cancel-after",
4784*5e7646d2SAndroid Build Coastguard Worker 						   IPP_TAG_INTEGER);
4785*5e7646d2SAndroid Build Coastguard Worker 					/* job-cancel-after attribute */
4786*5e7646d2SAndroid Build Coastguard Worker 
4787*5e7646d2SAndroid Build Coastguard Worker 
4788*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_job(job=%p(%d), printer=%p(%s))",
4789*5e7646d2SAndroid Build Coastguard Worker                   job, job->id, printer, printer->name);
4790*5e7646d2SAndroid Build Coastguard Worker 
4791*5e7646d2SAndroid Build Coastguard Worker  /*
4792*5e7646d2SAndroid Build Coastguard Worker   * Make sure we have some files around before we try to print...
4793*5e7646d2SAndroid Build Coastguard Worker   */
4794*5e7646d2SAndroid Build Coastguard Worker 
4795*5e7646d2SAndroid Build Coastguard Worker   if (job->num_files == 0)
4796*5e7646d2SAndroid Build Coastguard Worker   {
4797*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->reasons, 0, "aborted-by-system");
4798*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_ABORTED, CUPSD_JOB_DEFAULT,
4799*5e7646d2SAndroid Build Coastguard Worker                      "Aborting job because it has no files.");
4800*5e7646d2SAndroid Build Coastguard Worker     return;
4801*5e7646d2SAndroid Build Coastguard Worker   }
4802*5e7646d2SAndroid Build Coastguard Worker 
4803*5e7646d2SAndroid Build Coastguard Worker  /*
4804*5e7646d2SAndroid Build Coastguard Worker   * Update the printer and job state to "processing"...
4805*5e7646d2SAndroid Build Coastguard Worker   */
4806*5e7646d2SAndroid Build Coastguard Worker 
4807*5e7646d2SAndroid Build Coastguard Worker   if (!cupsdLoadJob(job))
4808*5e7646d2SAndroid Build Coastguard Worker     return;
4809*5e7646d2SAndroid Build Coastguard Worker 
4810*5e7646d2SAndroid Build Coastguard Worker   if (!job->printer_message)
4811*5e7646d2SAndroid Build Coastguard Worker     job->printer_message = ippFindAttribute(job->attrs,
4812*5e7646d2SAndroid Build Coastguard Worker                                             "job-printer-state-message",
4813*5e7646d2SAndroid Build Coastguard Worker                                             IPP_TAG_TEXT);
4814*5e7646d2SAndroid Build Coastguard Worker   if (job->printer_message)
4815*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->printer_message, 0, "");
4816*5e7646d2SAndroid Build Coastguard Worker 
4817*5e7646d2SAndroid Build Coastguard Worker   ippSetString(job->attrs, &job->reasons, 0, "job-printing");
4818*5e7646d2SAndroid Build Coastguard Worker   cupsdSetJobState(job, IPP_JOB_PROCESSING, CUPSD_JOB_DEFAULT, NULL);
4819*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0);
4820*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterReasons(printer, "-cups-remote-pending,"
4821*5e7646d2SAndroid Build Coastguard Worker 				  "cups-remote-pending-held,"
4822*5e7646d2SAndroid Build Coastguard Worker 				  "cups-remote-processing,"
4823*5e7646d2SAndroid Build Coastguard Worker 				  "cups-remote-stopped,"
4824*5e7646d2SAndroid Build Coastguard Worker 				  "cups-remote-canceled,"
4825*5e7646d2SAndroid Build Coastguard Worker 				  "cups-remote-aborted,"
4826*5e7646d2SAndroid Build Coastguard Worker 				  "cups-remote-completed");
4827*5e7646d2SAndroid Build Coastguard Worker 
4828*5e7646d2SAndroid Build Coastguard Worker   job->cost         = 0;
4829*5e7646d2SAndroid Build Coastguard Worker   job->current_file = 0;
4830*5e7646d2SAndroid Build Coastguard Worker   job->file_time    = 0;
4831*5e7646d2SAndroid Build Coastguard Worker   job->history_time = 0;
4832*5e7646d2SAndroid Build Coastguard Worker   job->progress     = 0;
4833*5e7646d2SAndroid Build Coastguard Worker   job->printer      = printer;
4834*5e7646d2SAndroid Build Coastguard Worker   printer->job      = job;
4835*5e7646d2SAndroid Build Coastguard Worker 
4836*5e7646d2SAndroid Build Coastguard Worker   if (cancel_after)
4837*5e7646d2SAndroid Build Coastguard Worker     job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
4838*5e7646d2SAndroid Build Coastguard Worker   else if (MaxJobTime > 0)
4839*5e7646d2SAndroid Build Coastguard Worker     job->cancel_time = time(NULL) + MaxJobTime;
4840*5e7646d2SAndroid Build Coastguard Worker   else
4841*5e7646d2SAndroid Build Coastguard Worker     job->cancel_time = 0;
4842*5e7646d2SAndroid Build Coastguard Worker 
4843*5e7646d2SAndroid Build Coastguard Worker  /*
4844*5e7646d2SAndroid Build Coastguard Worker   * Check for support files...
4845*5e7646d2SAndroid Build Coastguard Worker   */
4846*5e7646d2SAndroid Build Coastguard Worker 
4847*5e7646d2SAndroid Build Coastguard Worker   cupsdSetPrinterReasons(job->printer, "-cups-missing-filter-warning,"
4848*5e7646d2SAndroid Build Coastguard Worker 			               "cups-insecure-filter-warning");
4849*5e7646d2SAndroid Build Coastguard Worker 
4850*5e7646d2SAndroid Build Coastguard Worker   if (printer->pc)
4851*5e7646d2SAndroid Build Coastguard Worker   {
4852*5e7646d2SAndroid Build Coastguard Worker     for (filename = (const char *)cupsArrayFirst(printer->pc->support_files);
4853*5e7646d2SAndroid Build Coastguard Worker          filename;
4854*5e7646d2SAndroid Build Coastguard Worker          filename = (const char *)cupsArrayNext(printer->pc->support_files))
4855*5e7646d2SAndroid Build Coastguard Worker     {
4856*5e7646d2SAndroid Build Coastguard Worker       if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_FILE, !RunUser,
4857*5e7646d2SAndroid Build Coastguard Worker 			 cupsdLogFCMessage, printer))
4858*5e7646d2SAndroid Build Coastguard Worker         break;
4859*5e7646d2SAndroid Build Coastguard Worker     }
4860*5e7646d2SAndroid Build Coastguard Worker   }
4861*5e7646d2SAndroid Build Coastguard Worker 
4862*5e7646d2SAndroid Build Coastguard Worker  /*
4863*5e7646d2SAndroid Build Coastguard Worker   * Setup the last exit status and security profiles...
4864*5e7646d2SAndroid Build Coastguard Worker   */
4865*5e7646d2SAndroid Build Coastguard Worker 
4866*5e7646d2SAndroid Build Coastguard Worker   job->status   = 0;
4867*5e7646d2SAndroid Build Coastguard Worker   job->profile  = cupsdCreateProfile(job->id, 0);
4868*5e7646d2SAndroid Build Coastguard Worker   job->bprofile = cupsdCreateProfile(job->id, 1);
4869*5e7646d2SAndroid Build Coastguard Worker 
4870*5e7646d2SAndroid Build Coastguard Worker #ifdef HAVE_SANDBOX_H
4871*5e7646d2SAndroid Build Coastguard Worker   if ((!job->profile || !job->bprofile) && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF)
4872*5e7646d2SAndroid Build Coastguard Worker   {
4873*5e7646d2SAndroid Build Coastguard Worker    /*
4874*5e7646d2SAndroid Build Coastguard Worker     * Failure to create the sandbox profile means something really bad has
4875*5e7646d2SAndroid Build Coastguard Worker     * happened and we need to shutdown immediately.
4876*5e7646d2SAndroid Build Coastguard Worker     */
4877*5e7646d2SAndroid Build Coastguard Worker 
4878*5e7646d2SAndroid Build Coastguard Worker     return;
4879*5e7646d2SAndroid Build Coastguard Worker   }
4880*5e7646d2SAndroid Build Coastguard Worker #endif /* HAVE_SANDBOX_H */
4881*5e7646d2SAndroid Build Coastguard Worker 
4882*5e7646d2SAndroid Build Coastguard Worker  /*
4883*5e7646d2SAndroid Build Coastguard Worker   * Create the status pipes and buffer...
4884*5e7646d2SAndroid Build Coastguard Worker   */
4885*5e7646d2SAndroid Build Coastguard Worker 
4886*5e7646d2SAndroid Build Coastguard Worker   if (cupsdOpenPipe(job->status_pipes))
4887*5e7646d2SAndroid Build Coastguard Worker   {
4888*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG,
4889*5e7646d2SAndroid Build Coastguard Worker 		"Unable to create job status pipes - %s.", strerror(errno));
4890*5e7646d2SAndroid Build Coastguard Worker 
4891*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_STOPPED, CUPSD_JOB_DEFAULT,
4892*5e7646d2SAndroid Build Coastguard Worker 		     "Job stopped because the scheduler could not create the "
4893*5e7646d2SAndroid Build Coastguard Worker 		     "job status pipes.");
4894*5e7646d2SAndroid Build Coastguard Worker 
4895*5e7646d2SAndroid Build Coastguard Worker     cupsdDestroyProfile(job->profile);
4896*5e7646d2SAndroid Build Coastguard Worker     job->profile = NULL;
4897*5e7646d2SAndroid Build Coastguard Worker     cupsdDestroyProfile(job->bprofile);
4898*5e7646d2SAndroid Build Coastguard Worker     job->bprofile = NULL;
4899*5e7646d2SAndroid Build Coastguard Worker     return;
4900*5e7646d2SAndroid Build Coastguard Worker   }
4901*5e7646d2SAndroid Build Coastguard Worker 
4902*5e7646d2SAndroid Build Coastguard Worker   job->status_buffer = cupsdStatBufNew(job->status_pipes[0], NULL);
4903*5e7646d2SAndroid Build Coastguard Worker   job->status_level  = CUPSD_LOG_INFO;
4904*5e7646d2SAndroid Build Coastguard Worker 
4905*5e7646d2SAndroid Build Coastguard Worker  /*
4906*5e7646d2SAndroid Build Coastguard Worker   * Create the backchannel pipes and make them non-blocking...
4907*5e7646d2SAndroid Build Coastguard Worker   */
4908*5e7646d2SAndroid Build Coastguard Worker 
4909*5e7646d2SAndroid Build Coastguard Worker   if (cupsdOpenPipe(job->back_pipes))
4910*5e7646d2SAndroid Build Coastguard Worker   {
4911*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG,
4912*5e7646d2SAndroid Build Coastguard Worker 		"Unable to create back-channel pipes - %s.", strerror(errno));
4913*5e7646d2SAndroid Build Coastguard Worker 
4914*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_STOPPED, CUPSD_JOB_DEFAULT,
4915*5e7646d2SAndroid Build Coastguard Worker 		     "Job stopped because the scheduler could not create the "
4916*5e7646d2SAndroid Build Coastguard Worker 		     "back-channel pipes.");
4917*5e7646d2SAndroid Build Coastguard Worker 
4918*5e7646d2SAndroid Build Coastguard Worker     cupsdClosePipe(job->status_pipes);
4919*5e7646d2SAndroid Build Coastguard Worker     cupsdStatBufDelete(job->status_buffer);
4920*5e7646d2SAndroid Build Coastguard Worker     job->status_buffer = NULL;
4921*5e7646d2SAndroid Build Coastguard Worker 
4922*5e7646d2SAndroid Build Coastguard Worker     cupsdDestroyProfile(job->profile);
4923*5e7646d2SAndroid Build Coastguard Worker     job->profile = NULL;
4924*5e7646d2SAndroid Build Coastguard Worker     cupsdDestroyProfile(job->bprofile);
4925*5e7646d2SAndroid Build Coastguard Worker     job->bprofile = NULL;
4926*5e7646d2SAndroid Build Coastguard Worker     return;
4927*5e7646d2SAndroid Build Coastguard Worker   }
4928*5e7646d2SAndroid Build Coastguard Worker 
4929*5e7646d2SAndroid Build Coastguard Worker   fcntl(job->back_pipes[0], F_SETFL,
4930*5e7646d2SAndroid Build Coastguard Worker 	fcntl(job->back_pipes[0], F_GETFL) | O_NONBLOCK);
4931*5e7646d2SAndroid Build Coastguard Worker   fcntl(job->back_pipes[1], F_SETFL,
4932*5e7646d2SAndroid Build Coastguard Worker 	fcntl(job->back_pipes[1], F_GETFL) | O_NONBLOCK);
4933*5e7646d2SAndroid Build Coastguard Worker 
4934*5e7646d2SAndroid Build Coastguard Worker  /*
4935*5e7646d2SAndroid Build Coastguard Worker   * Create the side-channel pipes and make them non-blocking...
4936*5e7646d2SAndroid Build Coastguard Worker   */
4937*5e7646d2SAndroid Build Coastguard Worker 
4938*5e7646d2SAndroid Build Coastguard Worker   if (socketpair(AF_LOCAL, SOCK_STREAM, 0, job->side_pipes))
4939*5e7646d2SAndroid Build Coastguard Worker   {
4940*5e7646d2SAndroid Build Coastguard Worker     cupsdLogJob(job, CUPSD_LOG_DEBUG,
4941*5e7646d2SAndroid Build Coastguard Worker 		"Unable to create side-channel pipes - %s.", strerror(errno));
4942*5e7646d2SAndroid Build Coastguard Worker 
4943*5e7646d2SAndroid Build Coastguard Worker     cupsdSetJobState(job, IPP_JOB_STOPPED, CUPSD_JOB_DEFAULT,
4944*5e7646d2SAndroid Build Coastguard Worker 		     "Job stopped because the scheduler could not create the "
4945*5e7646d2SAndroid Build Coastguard Worker 		     "side-channel pipes.");
4946*5e7646d2SAndroid Build Coastguard Worker 
4947*5e7646d2SAndroid Build Coastguard Worker     cupsdClosePipe(job->back_pipes);
4948*5e7646d2SAndroid Build Coastguard Worker 
4949*5e7646d2SAndroid Build Coastguard Worker     cupsdClosePipe(job->status_pipes);
4950*5e7646d2SAndroid Build Coastguard Worker     cupsdStatBufDelete(job->status_buffer);
4951*5e7646d2SAndroid Build Coastguard Worker     job->status_buffer = NULL;
4952*5e7646d2SAndroid Build Coastguard Worker 
4953*5e7646d2SAndroid Build Coastguard Worker     cupsdDestroyProfile(job->profile);
4954*5e7646d2SAndroid Build Coastguard Worker     job->profile = NULL;
4955*5e7646d2SAndroid Build Coastguard Worker     cupsdDestroyProfile(job->bprofile);
4956*5e7646d2SAndroid Build Coastguard Worker     job->bprofile = NULL;
4957*5e7646d2SAndroid Build Coastguard Worker     return;
4958*5e7646d2SAndroid Build Coastguard Worker   }
4959*5e7646d2SAndroid Build Coastguard Worker 
4960*5e7646d2SAndroid Build Coastguard Worker   fcntl(job->side_pipes[0], F_SETFL,
4961*5e7646d2SAndroid Build Coastguard Worker 	fcntl(job->side_pipes[0], F_GETFL) | O_NONBLOCK);
4962*5e7646d2SAndroid Build Coastguard Worker   fcntl(job->side_pipes[1], F_SETFL,
4963*5e7646d2SAndroid Build Coastguard Worker 	fcntl(job->side_pipes[1], F_GETFL) | O_NONBLOCK);
4964*5e7646d2SAndroid Build Coastguard Worker 
4965*5e7646d2SAndroid Build Coastguard Worker   fcntl(job->side_pipes[0], F_SETFD,
4966*5e7646d2SAndroid Build Coastguard Worker 	fcntl(job->side_pipes[0], F_GETFD) | FD_CLOEXEC);
4967*5e7646d2SAndroid Build Coastguard Worker   fcntl(job->side_pipes[1], F_SETFD,
4968*5e7646d2SAndroid Build Coastguard Worker 	fcntl(job->side_pipes[1], F_GETFD) | FD_CLOEXEC);
4969*5e7646d2SAndroid Build Coastguard Worker 
4970*5e7646d2SAndroid Build Coastguard Worker  /*
4971*5e7646d2SAndroid Build Coastguard Worker   * Now start the first file in the job...
4972*5e7646d2SAndroid Build Coastguard Worker   */
4973*5e7646d2SAndroid Build Coastguard Worker 
4974*5e7646d2SAndroid Build Coastguard Worker   cupsdContinueJob(job);
4975*5e7646d2SAndroid Build Coastguard Worker }
4976*5e7646d2SAndroid Build Coastguard Worker 
4977*5e7646d2SAndroid Build Coastguard Worker 
4978*5e7646d2SAndroid Build Coastguard Worker /*
4979*5e7646d2SAndroid Build Coastguard Worker  * 'stop_job()' - Stop a print job.
4980*5e7646d2SAndroid Build Coastguard Worker  */
4981*5e7646d2SAndroid Build Coastguard Worker 
4982*5e7646d2SAndroid Build Coastguard Worker static void
stop_job(cupsd_job_t * job,cupsd_jobaction_t action)4983*5e7646d2SAndroid Build Coastguard Worker stop_job(cupsd_job_t       *job,	/* I - Job */
4984*5e7646d2SAndroid Build Coastguard Worker          cupsd_jobaction_t action)	/* I - Action */
4985*5e7646d2SAndroid Build Coastguard Worker {
4986*5e7646d2SAndroid Build Coastguard Worker   int	i;				/* Looping var */
4987*5e7646d2SAndroid Build Coastguard Worker 
4988*5e7646d2SAndroid Build Coastguard Worker 
4989*5e7646d2SAndroid Build Coastguard Worker   cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_job(job=%p(%d), action=%d)", job,
4990*5e7646d2SAndroid Build Coastguard Worker                   job->id, action);
4991*5e7646d2SAndroid Build Coastguard Worker 
4992*5e7646d2SAndroid Build Coastguard Worker   FilterLevel -= job->cost;
4993*5e7646d2SAndroid Build Coastguard Worker   job->cost   = 0;
4994*5e7646d2SAndroid Build Coastguard Worker 
4995*5e7646d2SAndroid Build Coastguard Worker   if (action == CUPSD_JOB_DEFAULT && !job->kill_time && job->backend > 0)
4996*5e7646d2SAndroid Build Coastguard Worker     job->kill_time = time(NULL) + JobKillDelay;
4997*5e7646d2SAndroid Build Coastguard Worker   else if (action >= CUPSD_JOB_FORCE)
4998*5e7646d2SAndroid Build Coastguard Worker     job->kill_time = 0;
4999*5e7646d2SAndroid Build Coastguard Worker 
5000*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; job->filters[i]; i ++)
5001*5e7646d2SAndroid Build Coastguard Worker     if (job->filters[i] > 0)
5002*5e7646d2SAndroid Build Coastguard Worker     {
5003*5e7646d2SAndroid Build Coastguard Worker       cupsdEndProcess(job->filters[i], action >= CUPSD_JOB_FORCE);
5004*5e7646d2SAndroid Build Coastguard Worker 
5005*5e7646d2SAndroid Build Coastguard Worker       if (action >= CUPSD_JOB_FORCE)
5006*5e7646d2SAndroid Build Coastguard Worker         job->filters[i] = -job->filters[i];
5007*5e7646d2SAndroid Build Coastguard Worker     }
5008*5e7646d2SAndroid Build Coastguard Worker 
5009*5e7646d2SAndroid Build Coastguard Worker   if (job->backend > 0)
5010*5e7646d2SAndroid Build Coastguard Worker   {
5011*5e7646d2SAndroid Build Coastguard Worker     cupsdEndProcess(job->backend, action >= CUPSD_JOB_FORCE);
5012*5e7646d2SAndroid Build Coastguard Worker 
5013*5e7646d2SAndroid Build Coastguard Worker     if (action >= CUPSD_JOB_FORCE)
5014*5e7646d2SAndroid Build Coastguard Worker       job->backend = -job->backend;
5015*5e7646d2SAndroid Build Coastguard Worker   }
5016*5e7646d2SAndroid Build Coastguard Worker 
5017*5e7646d2SAndroid Build Coastguard Worker   if (action >= CUPSD_JOB_FORCE)
5018*5e7646d2SAndroid Build Coastguard Worker   {
5019*5e7646d2SAndroid Build Coastguard Worker    /*
5020*5e7646d2SAndroid Build Coastguard Worker     * Clear job status...
5021*5e7646d2SAndroid Build Coastguard Worker     */
5022*5e7646d2SAndroid Build Coastguard Worker 
5023*5e7646d2SAndroid Build Coastguard Worker     job->status = 0;
5024*5e7646d2SAndroid Build Coastguard Worker   }
5025*5e7646d2SAndroid Build Coastguard Worker }
5026*5e7646d2SAndroid Build Coastguard Worker 
5027*5e7646d2SAndroid Build Coastguard Worker 
5028*5e7646d2SAndroid Build Coastguard Worker /*
5029*5e7646d2SAndroid Build Coastguard Worker  * 'unload_job()' - Unload a job from memory.
5030*5e7646d2SAndroid Build Coastguard Worker  */
5031*5e7646d2SAndroid Build Coastguard Worker 
5032*5e7646d2SAndroid Build Coastguard Worker static void
unload_job(cupsd_job_t * job)5033*5e7646d2SAndroid Build Coastguard Worker unload_job(cupsd_job_t *job)		/* I - Job */
5034*5e7646d2SAndroid Build Coastguard Worker {
5035*5e7646d2SAndroid Build Coastguard Worker   if (!job->attrs)
5036*5e7646d2SAndroid Build Coastguard Worker     return;
5037*5e7646d2SAndroid Build Coastguard Worker 
5038*5e7646d2SAndroid Build Coastguard Worker   cupsdLogJob(job, CUPSD_LOG_DEBUG, "Unloading...");
5039*5e7646d2SAndroid Build Coastguard Worker 
5040*5e7646d2SAndroid Build Coastguard Worker   ippDelete(job->attrs);
5041*5e7646d2SAndroid Build Coastguard Worker 
5042*5e7646d2SAndroid Build Coastguard Worker   job->attrs           = NULL;
5043*5e7646d2SAndroid Build Coastguard Worker   job->state           = NULL;
5044*5e7646d2SAndroid Build Coastguard Worker   job->reasons         = NULL;
5045*5e7646d2SAndroid Build Coastguard Worker   job->impressions     = NULL;
5046*5e7646d2SAndroid Build Coastguard Worker   job->sheets          = NULL;
5047*5e7646d2SAndroid Build Coastguard Worker   job->job_sheets      = NULL;
5048*5e7646d2SAndroid Build Coastguard Worker   job->printer_message = NULL;
5049*5e7646d2SAndroid Build Coastguard Worker   job->printer_reasons = NULL;
5050*5e7646d2SAndroid Build Coastguard Worker }
5051*5e7646d2SAndroid Build Coastguard Worker 
5052*5e7646d2SAndroid Build Coastguard Worker 
5053*5e7646d2SAndroid Build Coastguard Worker /*
5054*5e7646d2SAndroid Build Coastguard Worker  * 'update_job()' - Read a status update from a job's filters.
5055*5e7646d2SAndroid Build Coastguard Worker  */
5056*5e7646d2SAndroid Build Coastguard Worker 
5057*5e7646d2SAndroid Build Coastguard Worker void
update_job(cupsd_job_t * job)5058*5e7646d2SAndroid Build Coastguard Worker update_job(cupsd_job_t *job)		/* I - Job to check */
5059*5e7646d2SAndroid Build Coastguard Worker {
5060*5e7646d2SAndroid Build Coastguard Worker   int		i;			/* Looping var */
5061*5e7646d2SAndroid Build Coastguard Worker   char		message[CUPSD_SB_BUFFER_SIZE],
5062*5e7646d2SAndroid Build Coastguard Worker 					/* Message text */
5063*5e7646d2SAndroid Build Coastguard Worker 		*ptr;			/* Pointer update... */
5064*5e7646d2SAndroid Build Coastguard Worker   int		loglevel,		/* Log level for message */
5065*5e7646d2SAndroid Build Coastguard Worker 		event = 0;		/* Events? */
5066*5e7646d2SAndroid Build Coastguard Worker   cupsd_printer_t *printer = job->printer;
5067*5e7646d2SAndroid Build Coastguard Worker 					/* Printer */
5068*5e7646d2SAndroid Build Coastguard Worker   static const char * const levels[] =	/* Log levels */
5069*5e7646d2SAndroid Build Coastguard Worker 		{
5070*5e7646d2SAndroid Build Coastguard Worker 		  "NONE",
5071*5e7646d2SAndroid Build Coastguard Worker 		  "EMERG",
5072*5e7646d2SAndroid Build Coastguard Worker 		  "ALERT",
5073*5e7646d2SAndroid Build Coastguard Worker 		  "CRIT",
5074*5e7646d2SAndroid Build Coastguard Worker 		  "ERROR",
5075*5e7646d2SAndroid Build Coastguard Worker 		  "WARN",
5076*5e7646d2SAndroid Build Coastguard Worker 		  "NOTICE",
5077*5e7646d2SAndroid Build Coastguard Worker 		  "INFO",
5078*5e7646d2SAndroid Build Coastguard Worker 		  "DEBUG",
5079*5e7646d2SAndroid Build Coastguard Worker 		  "DEBUG2"
5080*5e7646d2SAndroid Build Coastguard Worker 		};
5081*5e7646d2SAndroid Build Coastguard Worker 
5082*5e7646d2SAndroid Build Coastguard Worker 
5083*5e7646d2SAndroid Build Coastguard Worker  /*
5084*5e7646d2SAndroid Build Coastguard Worker   * Get the printer associated with this job; if the printer is stopped for
5085*5e7646d2SAndroid Build Coastguard Worker   * any reason then job->printer will be reset to NULL, so make sure we have
5086*5e7646d2SAndroid Build Coastguard Worker   * a valid pointer...
5087*5e7646d2SAndroid Build Coastguard Worker   */
5088*5e7646d2SAndroid Build Coastguard Worker 
5089*5e7646d2SAndroid Build Coastguard Worker   while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel,
5090*5e7646d2SAndroid Build Coastguard Worker                                    message, sizeof(message))) != NULL)
5091*5e7646d2SAndroid Build Coastguard Worker   {
5092*5e7646d2SAndroid Build Coastguard Worker    /*
5093*5e7646d2SAndroid Build Coastguard Worker     * Process page and printer state messages as needed...
5094*5e7646d2SAndroid Build Coastguard Worker     */
5095*5e7646d2SAndroid Build Coastguard Worker 
5096*5e7646d2SAndroid Build Coastguard Worker     if (loglevel == CUPSD_LOG_PAGE)
5097*5e7646d2SAndroid Build Coastguard Worker     {
5098*5e7646d2SAndroid Build Coastguard Worker       int	impressions = ippGetInteger(job->impressions, 0);
5099*5e7646d2SAndroid Build Coastguard Worker 				/* Number of impressions printed */
5100*5e7646d2SAndroid Build Coastguard Worker       int	delta;		/* Number of impressions added */
5101*5e7646d2SAndroid Build Coastguard Worker 
5102*5e7646d2SAndroid Build Coastguard Worker      /*
5103*5e7646d2SAndroid Build Coastguard Worker       * Page message; send the message to the page_log file and update the
5104*5e7646d2SAndroid Build Coastguard Worker       * job sheet count...
5105*5e7646d2SAndroid Build Coastguard Worker       */
5106*5e7646d2SAndroid Build Coastguard Worker 
5107*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "PAGE: %s", message);
5108*5e7646d2SAndroid Build Coastguard Worker 
5109*5e7646d2SAndroid Build Coastguard Worker       if (!_cups_strncasecmp(message, "total ", 6))
5110*5e7646d2SAndroid Build Coastguard Worker       {
5111*5e7646d2SAndroid Build Coastguard Worker        /*
5112*5e7646d2SAndroid Build Coastguard Worker 	* Got a total count of pages from a backend or filter...
5113*5e7646d2SAndroid Build Coastguard Worker 	*/
5114*5e7646d2SAndroid Build Coastguard Worker 
5115*5e7646d2SAndroid Build Coastguard Worker 	int total = atoi(message + 6);	/* Total impressions */
5116*5e7646d2SAndroid Build Coastguard Worker 
5117*5e7646d2SAndroid Build Coastguard Worker 	if (total > impressions)
5118*5e7646d2SAndroid Build Coastguard Worker 	{
5119*5e7646d2SAndroid Build Coastguard Worker 	  delta       = total - impressions;
5120*5e7646d2SAndroid Build Coastguard Worker 	  impressions = total;
5121*5e7646d2SAndroid Build Coastguard Worker 	}
5122*5e7646d2SAndroid Build Coastguard Worker 	else
5123*5e7646d2SAndroid Build Coastguard Worker 	  delta = 0;
5124*5e7646d2SAndroid Build Coastguard Worker       }
5125*5e7646d2SAndroid Build Coastguard Worker       else
5126*5e7646d2SAndroid Build Coastguard Worker       {
5127*5e7646d2SAndroid Build Coastguard Worker        /*
5128*5e7646d2SAndroid Build Coastguard Worker         * Add the number of copies to the impression count...
5129*5e7646d2SAndroid Build Coastguard Worker         */
5130*5e7646d2SAndroid Build Coastguard Worker 
5131*5e7646d2SAndroid Build Coastguard Worker 	int copies;			/* Number of copies */
5132*5e7646d2SAndroid Build Coastguard Worker 
5133*5e7646d2SAndroid Build Coastguard Worker 	if (!sscanf(message, "%*d%d", &copies) || copies <= 0)
5134*5e7646d2SAndroid Build Coastguard Worker 	  copies = 1;
5135*5e7646d2SAndroid Build Coastguard Worker 
5136*5e7646d2SAndroid Build Coastguard Worker         delta = copies;
5137*5e7646d2SAndroid Build Coastguard Worker 	impressions += copies;
5138*5e7646d2SAndroid Build Coastguard Worker       }
5139*5e7646d2SAndroid Build Coastguard Worker 
5140*5e7646d2SAndroid Build Coastguard Worker       if (job->impressions)
5141*5e7646d2SAndroid Build Coastguard Worker         ippSetInteger(job->attrs, &job->impressions, 0, impressions);
5142*5e7646d2SAndroid Build Coastguard Worker 
5143*5e7646d2SAndroid Build Coastguard Worker       if (job->sheets)
5144*5e7646d2SAndroid Build Coastguard Worker       {
5145*5e7646d2SAndroid Build Coastguard Worker 	const char *sides = ippGetString(ippFindAttribute(job->attrs, "sides", IPP_TAG_KEYWORD), 0, NULL);
5146*5e7646d2SAndroid Build Coastguard Worker 
5147*5e7646d2SAndroid Build Coastguard Worker         if (sides && strcmp(sides, "one-sided"))
5148*5e7646d2SAndroid Build Coastguard Worker           ippSetInteger(job->attrs, &job->sheets, 0, impressions / 2);
5149*5e7646d2SAndroid Build Coastguard Worker 	else
5150*5e7646d2SAndroid Build Coastguard Worker           ippSetInteger(job->attrs, &job->sheets, 0, impressions);
5151*5e7646d2SAndroid Build Coastguard Worker 
5152*5e7646d2SAndroid Build Coastguard Worker 	cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, "Printed %d page(s).", ippGetInteger(job->sheets, 0));
5153*5e7646d2SAndroid Build Coastguard Worker       }
5154*5e7646d2SAndroid Build Coastguard Worker 
5155*5e7646d2SAndroid Build Coastguard Worker       job->dirty = 1;
5156*5e7646d2SAndroid Build Coastguard Worker       cupsdMarkDirty(CUPSD_DIRTY_JOBS);
5157*5e7646d2SAndroid Build Coastguard Worker 
5158*5e7646d2SAndroid Build Coastguard Worker       if (job->printer->page_limit)
5159*5e7646d2SAndroid Build Coastguard Worker 	cupsdUpdateQuota(job->printer, job->username, delta, 0);
5160*5e7646d2SAndroid Build Coastguard Worker     }
5161*5e7646d2SAndroid Build Coastguard Worker     else if (loglevel == CUPSD_LOG_JOBSTATE)
5162*5e7646d2SAndroid Build Coastguard Worker     {
5163*5e7646d2SAndroid Build Coastguard Worker      /*
5164*5e7646d2SAndroid Build Coastguard Worker       * Support "keyword" to set job-state-reasons to the specified keyword.
5165*5e7646d2SAndroid Build Coastguard Worker       * This is sufficient for the current paid printing stuff.
5166*5e7646d2SAndroid Build Coastguard Worker       */
5167*5e7646d2SAndroid Build Coastguard Worker 
5168*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "JOBSTATE: %s", message);
5169*5e7646d2SAndroid Build Coastguard Worker 
5170*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(message, "cups-retry-as-raster"))
5171*5e7646d2SAndroid Build Coastguard Worker         job->retry_as_raster = 1;
5172*5e7646d2SAndroid Build Coastguard Worker       else
5173*5e7646d2SAndroid Build Coastguard Worker         ippSetString(job->attrs, &job->reasons, 0, message);
5174*5e7646d2SAndroid Build Coastguard Worker     }
5175*5e7646d2SAndroid Build Coastguard Worker     else if (loglevel == CUPSD_LOG_STATE)
5176*5e7646d2SAndroid Build Coastguard Worker     {
5177*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "STATE: %s", message);
5178*5e7646d2SAndroid Build Coastguard Worker 
5179*5e7646d2SAndroid Build Coastguard Worker       if (!strcmp(message, "paused"))
5180*5e7646d2SAndroid Build Coastguard Worker       {
5181*5e7646d2SAndroid Build Coastguard Worker         cupsdStopPrinter(job->printer, 1);
5182*5e7646d2SAndroid Build Coastguard Worker 	return;
5183*5e7646d2SAndroid Build Coastguard Worker       }
5184*5e7646d2SAndroid Build Coastguard Worker       else if (message[0] && cupsdSetPrinterReasons(job->printer, message))
5185*5e7646d2SAndroid Build Coastguard Worker       {
5186*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5187*5e7646d2SAndroid Build Coastguard Worker 
5188*5e7646d2SAndroid Build Coastguard Worker         if (MaxJobTime > 0)
5189*5e7646d2SAndroid Build Coastguard Worker         {
5190*5e7646d2SAndroid Build Coastguard Worker          /*
5191*5e7646d2SAndroid Build Coastguard Worker           * Reset cancel time after connecting to the device...
5192*5e7646d2SAndroid Build Coastguard Worker           */
5193*5e7646d2SAndroid Build Coastguard Worker 
5194*5e7646d2SAndroid Build Coastguard Worker           for (i = 0; i < job->printer->num_reasons; i ++)
5195*5e7646d2SAndroid Build Coastguard Worker             if (!strcmp(job->printer->reasons[i], "connecting-to-device"))
5196*5e7646d2SAndroid Build Coastguard Worker               break;
5197*5e7646d2SAndroid Build Coastguard Worker 
5198*5e7646d2SAndroid Build Coastguard Worker           if (i >= job->printer->num_reasons)
5199*5e7646d2SAndroid Build Coastguard Worker           {
5200*5e7646d2SAndroid Build Coastguard Worker 	    ipp_attribute_t *cancel_after = ippFindAttribute(job->attrs,
5201*5e7646d2SAndroid Build Coastguard Worker 							     "job-cancel-after",
5202*5e7646d2SAndroid Build Coastguard Worker 							     IPP_TAG_INTEGER);
5203*5e7646d2SAndroid Build Coastguard Worker 					/* job-cancel-after attribute */
5204*5e7646d2SAndroid Build Coastguard Worker 
5205*5e7646d2SAndroid Build Coastguard Worker             if (cancel_after)
5206*5e7646d2SAndroid Build Coastguard Worker 	      job->cancel_time = time(NULL) + ippGetInteger(cancel_after, 0);
5207*5e7646d2SAndroid Build Coastguard Worker 	    else if (MaxJobTime > 0)
5208*5e7646d2SAndroid Build Coastguard Worker 	      job->cancel_time = time(NULL) + MaxJobTime;
5209*5e7646d2SAndroid Build Coastguard Worker 	    else
5210*5e7646d2SAndroid Build Coastguard Worker 	      job->cancel_time = 0;
5211*5e7646d2SAndroid Build Coastguard Worker 	  }
5212*5e7646d2SAndroid Build Coastguard Worker         }
5213*5e7646d2SAndroid Build Coastguard Worker       }
5214*5e7646d2SAndroid Build Coastguard Worker 
5215*5e7646d2SAndroid Build Coastguard Worker       update_job_attrs(job, 0);
5216*5e7646d2SAndroid Build Coastguard Worker     }
5217*5e7646d2SAndroid Build Coastguard Worker     else if (loglevel == CUPSD_LOG_ATTR)
5218*5e7646d2SAndroid Build Coastguard Worker     {
5219*5e7646d2SAndroid Build Coastguard Worker      /*
5220*5e7646d2SAndroid Build Coastguard Worker       * Set attribute(s)...
5221*5e7646d2SAndroid Build Coastguard Worker       */
5222*5e7646d2SAndroid Build Coastguard Worker 
5223*5e7646d2SAndroid Build Coastguard Worker       int		num_attrs;	/* Number of attributes */
5224*5e7646d2SAndroid Build Coastguard Worker       cups_option_t	*attrs;		/* Attributes */
5225*5e7646d2SAndroid Build Coastguard Worker       const char	*attr;		/* Attribute */
5226*5e7646d2SAndroid Build Coastguard Worker 
5227*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "ATTR: %s", message);
5228*5e7646d2SAndroid Build Coastguard Worker 
5229*5e7646d2SAndroid Build Coastguard Worker       num_attrs = cupsParseOptions(message, 0, &attrs);
5230*5e7646d2SAndroid Build Coastguard Worker 
5231*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("auth-info-default", num_attrs,
5232*5e7646d2SAndroid Build Coastguard Worker                                 attrs)) != NULL)
5233*5e7646d2SAndroid Build Coastguard Worker       {
5234*5e7646d2SAndroid Build Coastguard Worker         job->printer->num_options = cupsAddOption("auth-info", attr,
5235*5e7646d2SAndroid Build Coastguard Worker 						  job->printer->num_options,
5236*5e7646d2SAndroid Build Coastguard Worker 						  &(job->printer->options));
5237*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetPrinterAttrs(job->printer);
5238*5e7646d2SAndroid Build Coastguard Worker 
5239*5e7646d2SAndroid Build Coastguard Worker 	cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5240*5e7646d2SAndroid Build Coastguard Worker       }
5241*5e7646d2SAndroid Build Coastguard Worker 
5242*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("auth-info-required", num_attrs,
5243*5e7646d2SAndroid Build Coastguard Worker                                 attrs)) != NULL)
5244*5e7646d2SAndroid Build Coastguard Worker       {
5245*5e7646d2SAndroid Build Coastguard Worker         cupsdSetAuthInfoRequired(job->printer, attr, NULL);
5246*5e7646d2SAndroid Build Coastguard Worker 	cupsdSetPrinterAttrs(job->printer);
5247*5e7646d2SAndroid Build Coastguard Worker 
5248*5e7646d2SAndroid Build Coastguard Worker 	cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5249*5e7646d2SAndroid Build Coastguard Worker       }
5250*5e7646d2SAndroid Build Coastguard Worker 
5251*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("job-media-progress", num_attrs,
5252*5e7646d2SAndroid Build Coastguard Worker                                 attrs)) != NULL)
5253*5e7646d2SAndroid Build Coastguard Worker       {
5254*5e7646d2SAndroid Build Coastguard Worker         int progress = atoi(attr);
5255*5e7646d2SAndroid Build Coastguard Worker 
5256*5e7646d2SAndroid Build Coastguard Worker 
5257*5e7646d2SAndroid Build Coastguard Worker         if (progress >= 0 && progress <= 100)
5258*5e7646d2SAndroid Build Coastguard Worker 	{
5259*5e7646d2SAndroid Build Coastguard Worker 	  job->progress = progress;
5260*5e7646d2SAndroid Build Coastguard Worker 
5261*5e7646d2SAndroid Build Coastguard Worker 	  if (job->sheets)
5262*5e7646d2SAndroid Build Coastguard Worker 	    cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
5263*5e7646d2SAndroid Build Coastguard Worker 			  "Printing page %d, %d%%",
5264*5e7646d2SAndroid Build Coastguard Worker 			  job->sheets->values[0].integer, job->progress);
5265*5e7646d2SAndroid Build Coastguard Worker         }
5266*5e7646d2SAndroid Build Coastguard Worker       }
5267*5e7646d2SAndroid Build Coastguard Worker 
5268*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("printer-alert", num_attrs, attrs)) != NULL)
5269*5e7646d2SAndroid Build Coastguard Worker       {
5270*5e7646d2SAndroid Build Coastguard Worker         cupsdSetString(&job->printer->alert, attr);
5271*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5272*5e7646d2SAndroid Build Coastguard Worker       }
5273*5e7646d2SAndroid Build Coastguard Worker 
5274*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("printer-alert-description", num_attrs,
5275*5e7646d2SAndroid Build Coastguard Worker                                 attrs)) != NULL)
5276*5e7646d2SAndroid Build Coastguard Worker       {
5277*5e7646d2SAndroid Build Coastguard Worker         cupsdSetString(&job->printer->alert_description, attr);
5278*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5279*5e7646d2SAndroid Build Coastguard Worker       }
5280*5e7646d2SAndroid Build Coastguard Worker 
5281*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("marker-colors", num_attrs, attrs)) != NULL)
5282*5e7646d2SAndroid Build Coastguard Worker       {
5283*5e7646d2SAndroid Build Coastguard Worker         cupsdSetPrinterAttr(job->printer, "marker-colors", (char *)attr);
5284*5e7646d2SAndroid Build Coastguard Worker 	job->printer->marker_time = time(NULL);
5285*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5286*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5287*5e7646d2SAndroid Build Coastguard Worker       }
5288*5e7646d2SAndroid Build Coastguard Worker 
5289*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("marker-levels", num_attrs, attrs)) != NULL)
5290*5e7646d2SAndroid Build Coastguard Worker       {
5291*5e7646d2SAndroid Build Coastguard Worker         cupsdSetPrinterAttr(job->printer, "marker-levels", (char *)attr);
5292*5e7646d2SAndroid Build Coastguard Worker 	job->printer->marker_time = time(NULL);
5293*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5294*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5295*5e7646d2SAndroid Build Coastguard Worker       }
5296*5e7646d2SAndroid Build Coastguard Worker 
5297*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("marker-low-levels", num_attrs, attrs)) != NULL)
5298*5e7646d2SAndroid Build Coastguard Worker       {
5299*5e7646d2SAndroid Build Coastguard Worker         cupsdSetPrinterAttr(job->printer, "marker-low-levels", (char *)attr);
5300*5e7646d2SAndroid Build Coastguard Worker 	job->printer->marker_time = time(NULL);
5301*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5302*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5303*5e7646d2SAndroid Build Coastguard Worker       }
5304*5e7646d2SAndroid Build Coastguard Worker 
5305*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("marker-high-levels", num_attrs, attrs)) != NULL)
5306*5e7646d2SAndroid Build Coastguard Worker       {
5307*5e7646d2SAndroid Build Coastguard Worker         cupsdSetPrinterAttr(job->printer, "marker-high-levels", (char *)attr);
5308*5e7646d2SAndroid Build Coastguard Worker 	job->printer->marker_time = time(NULL);
5309*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5310*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5311*5e7646d2SAndroid Build Coastguard Worker       }
5312*5e7646d2SAndroid Build Coastguard Worker 
5313*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("marker-message", num_attrs, attrs)) != NULL)
5314*5e7646d2SAndroid Build Coastguard Worker       {
5315*5e7646d2SAndroid Build Coastguard Worker         cupsdSetPrinterAttr(job->printer, "marker-message", (char *)attr);
5316*5e7646d2SAndroid Build Coastguard Worker 	job->printer->marker_time = time(NULL);
5317*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5318*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5319*5e7646d2SAndroid Build Coastguard Worker       }
5320*5e7646d2SAndroid Build Coastguard Worker 
5321*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("marker-names", num_attrs, attrs)) != NULL)
5322*5e7646d2SAndroid Build Coastguard Worker       {
5323*5e7646d2SAndroid Build Coastguard Worker         cupsdSetPrinterAttr(job->printer, "marker-names", (char *)attr);
5324*5e7646d2SAndroid Build Coastguard Worker 	job->printer->marker_time = time(NULL);
5325*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5326*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5327*5e7646d2SAndroid Build Coastguard Worker       }
5328*5e7646d2SAndroid Build Coastguard Worker 
5329*5e7646d2SAndroid Build Coastguard Worker       if ((attr = cupsGetOption("marker-types", num_attrs, attrs)) != NULL)
5330*5e7646d2SAndroid Build Coastguard Worker       {
5331*5e7646d2SAndroid Build Coastguard Worker         cupsdSetPrinterAttr(job->printer, "marker-types", (char *)attr);
5332*5e7646d2SAndroid Build Coastguard Worker 	job->printer->marker_time = time(NULL);
5333*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE;
5334*5e7646d2SAndroid Build Coastguard Worker         cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
5335*5e7646d2SAndroid Build Coastguard Worker       }
5336*5e7646d2SAndroid Build Coastguard Worker 
5337*5e7646d2SAndroid Build Coastguard Worker       cupsFreeOptions(num_attrs, attrs);
5338*5e7646d2SAndroid Build Coastguard Worker     }
5339*5e7646d2SAndroid Build Coastguard Worker     else if (loglevel == CUPSD_LOG_PPD)
5340*5e7646d2SAndroid Build Coastguard Worker     {
5341*5e7646d2SAndroid Build Coastguard Worker      /*
5342*5e7646d2SAndroid Build Coastguard Worker       * Set attribute(s)...
5343*5e7646d2SAndroid Build Coastguard Worker       */
5344*5e7646d2SAndroid Build Coastguard Worker 
5345*5e7646d2SAndroid Build Coastguard Worker       cupsdLogJob(job, CUPSD_LOG_DEBUG, "PPD: %s", message);
5346*5e7646d2SAndroid Build Coastguard Worker 
5347*5e7646d2SAndroid Build Coastguard Worker       job->num_keywords = cupsParseOptions(message, job->num_keywords,
5348*5e7646d2SAndroid Build Coastguard Worker                                            &job->keywords);
5349*5e7646d2SAndroid Build Coastguard Worker     }
5350*5e7646d2SAndroid Build Coastguard Worker     else
5351*5e7646d2SAndroid Build Coastguard Worker     {
5352*5e7646d2SAndroid Build Coastguard Worker      /*
5353*5e7646d2SAndroid Build Coastguard Worker       * Strip legacy message prefix...
5354*5e7646d2SAndroid Build Coastguard Worker       */
5355*5e7646d2SAndroid Build Coastguard Worker 
5356*5e7646d2SAndroid Build Coastguard Worker       if (!strncmp(message, "recoverable:", 12))
5357*5e7646d2SAndroid Build Coastguard Worker       {
5358*5e7646d2SAndroid Build Coastguard Worker         ptr = message + 12;
5359*5e7646d2SAndroid Build Coastguard Worker 	while (isspace(*ptr & 255))
5360*5e7646d2SAndroid Build Coastguard Worker           ptr ++;
5361*5e7646d2SAndroid Build Coastguard Worker       }
5362*5e7646d2SAndroid Build Coastguard Worker       else if (!strncmp(message, "recovered:", 10))
5363*5e7646d2SAndroid Build Coastguard Worker       {
5364*5e7646d2SAndroid Build Coastguard Worker         ptr = message + 10;
5365*5e7646d2SAndroid Build Coastguard Worker 	while (isspace(*ptr & 255))
5366*5e7646d2SAndroid Build Coastguard Worker           ptr ++;
5367*5e7646d2SAndroid Build Coastguard Worker       }
5368*5e7646d2SAndroid Build Coastguard Worker       else
5369*5e7646d2SAndroid Build Coastguard Worker         ptr = message;
5370*5e7646d2SAndroid Build Coastguard Worker 
5371*5e7646d2SAndroid Build Coastguard Worker       if (*ptr)
5372*5e7646d2SAndroid Build Coastguard Worker         cupsdLogJob(job, loglevel == CUPSD_LOG_INFO ? CUPSD_LOG_DEBUG : loglevel, "%s", ptr);
5373*5e7646d2SAndroid Build Coastguard Worker 
5374*5e7646d2SAndroid Build Coastguard Worker       if (loglevel < CUPSD_LOG_DEBUG &&
5375*5e7646d2SAndroid Build Coastguard Worker           strcmp(job->printer->state_message, ptr))
5376*5e7646d2SAndroid Build Coastguard Worker       {
5377*5e7646d2SAndroid Build Coastguard Worker 	strlcpy(job->printer->state_message, ptr,
5378*5e7646d2SAndroid Build Coastguard Worker 		sizeof(job->printer->state_message));
5379*5e7646d2SAndroid Build Coastguard Worker 
5380*5e7646d2SAndroid Build Coastguard Worker 	event |= CUPSD_EVENT_PRINTER_STATE | CUPSD_EVENT_JOB_PROGRESS;
5381*5e7646d2SAndroid Build Coastguard Worker 
5382*5e7646d2SAndroid Build Coastguard Worker 	if (loglevel <= job->status_level && job->status_level > CUPSD_LOG_ERROR)
5383*5e7646d2SAndroid Build Coastguard Worker 	{
5384*5e7646d2SAndroid Build Coastguard Worker 	 /*
5385*5e7646d2SAndroid Build Coastguard Worker 	  * Some messages show in the job-printer-state-message attribute...
5386*5e7646d2SAndroid Build Coastguard Worker 	  */
5387*5e7646d2SAndroid Build Coastguard Worker 
5388*5e7646d2SAndroid Build Coastguard Worker 	  if (loglevel != CUPSD_LOG_NOTICE)
5389*5e7646d2SAndroid Build Coastguard Worker 	    job->status_level = loglevel;
5390*5e7646d2SAndroid Build Coastguard Worker 
5391*5e7646d2SAndroid Build Coastguard Worker 	  update_job_attrs(job, 1);
5392*5e7646d2SAndroid Build Coastguard Worker 
5393*5e7646d2SAndroid Build Coastguard Worker 	  cupsdLogJob(job, CUPSD_LOG_DEBUG,
5394*5e7646d2SAndroid Build Coastguard Worker 	              "Set job-printer-state-message to \"%s\", "
5395*5e7646d2SAndroid Build Coastguard Worker 	              "current level=%s",
5396*5e7646d2SAndroid Build Coastguard Worker 	              job->printer_message->values[0].string.text,
5397*5e7646d2SAndroid Build Coastguard Worker 	              levels[job->status_level]);
5398*5e7646d2SAndroid Build Coastguard Worker 	}
5399*5e7646d2SAndroid Build Coastguard Worker       }
5400*5e7646d2SAndroid Build Coastguard Worker     }
5401*5e7646d2SAndroid Build Coastguard Worker 
5402*5e7646d2SAndroid Build Coastguard Worker     if (!strchr(job->status_buffer->buffer, '\n'))
5403*5e7646d2SAndroid Build Coastguard Worker       break;
5404*5e7646d2SAndroid Build Coastguard Worker   }
5405*5e7646d2SAndroid Build Coastguard Worker 
5406*5e7646d2SAndroid Build Coastguard Worker   if (event & CUPSD_EVENT_JOB_PROGRESS)
5407*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
5408*5e7646d2SAndroid Build Coastguard Worker                   "%s", job->printer->state_message);
5409*5e7646d2SAndroid Build Coastguard Worker   if (event & CUPSD_EVENT_PRINTER_STATE)
5410*5e7646d2SAndroid Build Coastguard Worker     cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, job->printer, NULL,
5411*5e7646d2SAndroid Build Coastguard Worker 		  (job->printer->type & CUPS_PRINTER_CLASS) ?
5412*5e7646d2SAndroid Build Coastguard Worker 		      "Class \"%s\" state changed." :
5413*5e7646d2SAndroid Build Coastguard Worker 		      "Printer \"%s\" state changed.",
5414*5e7646d2SAndroid Build Coastguard Worker 		  job->printer->name);
5415*5e7646d2SAndroid Build Coastguard Worker 
5416*5e7646d2SAndroid Build Coastguard Worker 
5417*5e7646d2SAndroid Build Coastguard Worker   if (ptr == NULL && !job->status_buffer->bufused)
5418*5e7646d2SAndroid Build Coastguard Worker   {
5419*5e7646d2SAndroid Build Coastguard Worker    /*
5420*5e7646d2SAndroid Build Coastguard Worker     * See if all of the filters and the backend have returned their
5421*5e7646d2SAndroid Build Coastguard Worker     * exit statuses.
5422*5e7646d2SAndroid Build Coastguard Worker     */
5423*5e7646d2SAndroid Build Coastguard Worker 
5424*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; job->filters[i] < 0; i ++);
5425*5e7646d2SAndroid Build Coastguard Worker 
5426*5e7646d2SAndroid Build Coastguard Worker     if (job->filters[i])
5427*5e7646d2SAndroid Build Coastguard Worker     {
5428*5e7646d2SAndroid Build Coastguard Worker      /*
5429*5e7646d2SAndroid Build Coastguard Worker       * EOF but we haven't collected the exit status of all filters...
5430*5e7646d2SAndroid Build Coastguard Worker       */
5431*5e7646d2SAndroid Build Coastguard Worker 
5432*5e7646d2SAndroid Build Coastguard Worker       cupsdCheckProcess();
5433*5e7646d2SAndroid Build Coastguard Worker       return;
5434*5e7646d2SAndroid Build Coastguard Worker     }
5435*5e7646d2SAndroid Build Coastguard Worker 
5436*5e7646d2SAndroid Build Coastguard Worker     if (job->current_file >= job->num_files && job->backend > 0)
5437*5e7646d2SAndroid Build Coastguard Worker     {
5438*5e7646d2SAndroid Build Coastguard Worker      /*
5439*5e7646d2SAndroid Build Coastguard Worker       * EOF but we haven't collected the exit status of the backend...
5440*5e7646d2SAndroid Build Coastguard Worker       */
5441*5e7646d2SAndroid Build Coastguard Worker 
5442*5e7646d2SAndroid Build Coastguard Worker       cupsdCheckProcess();
5443*5e7646d2SAndroid Build Coastguard Worker       return;
5444*5e7646d2SAndroid Build Coastguard Worker     }
5445*5e7646d2SAndroid Build Coastguard Worker 
5446*5e7646d2SAndroid Build Coastguard Worker    /*
5447*5e7646d2SAndroid Build Coastguard Worker     * Handle the end of job stuff...
5448*5e7646d2SAndroid Build Coastguard Worker     */
5449*5e7646d2SAndroid Build Coastguard Worker 
5450*5e7646d2SAndroid Build Coastguard Worker     finalize_job(job, 1);
5451*5e7646d2SAndroid Build Coastguard Worker 
5452*5e7646d2SAndroid Build Coastguard Worker    /*
5453*5e7646d2SAndroid Build Coastguard Worker     * Try printing another job...
5454*5e7646d2SAndroid Build Coastguard Worker     */
5455*5e7646d2SAndroid Build Coastguard Worker 
5456*5e7646d2SAndroid Build Coastguard Worker     if (printer->state != IPP_PRINTER_STOPPED)
5457*5e7646d2SAndroid Build Coastguard Worker       cupsdCheckJobs();
5458*5e7646d2SAndroid Build Coastguard Worker   }
5459*5e7646d2SAndroid Build Coastguard Worker }
5460*5e7646d2SAndroid Build Coastguard Worker 
5461*5e7646d2SAndroid Build Coastguard Worker 
5462*5e7646d2SAndroid Build Coastguard Worker /*
5463*5e7646d2SAndroid Build Coastguard Worker  * 'update_job_attrs()' - Update the job-printer-* attributes.
5464*5e7646d2SAndroid Build Coastguard Worker  */
5465*5e7646d2SAndroid Build Coastguard Worker 
5466*5e7646d2SAndroid Build Coastguard Worker void
update_job_attrs(cupsd_job_t * job,int do_message)5467*5e7646d2SAndroid Build Coastguard Worker update_job_attrs(cupsd_job_t *job,	/* I - Job to update */
5468*5e7646d2SAndroid Build Coastguard Worker                  int         do_message)/* I - 1 = copy job-printer-state message */
5469*5e7646d2SAndroid Build Coastguard Worker {
5470*5e7646d2SAndroid Build Coastguard Worker   int			i;		/* Looping var */
5471*5e7646d2SAndroid Build Coastguard Worker   int			num_reasons;	/* Actual number of reasons */
5472*5e7646d2SAndroid Build Coastguard Worker   const char * const	*reasons;	/* Reasons */
5473*5e7646d2SAndroid Build Coastguard Worker   static const char	*none = "none";	/* "none" reason */
5474*5e7646d2SAndroid Build Coastguard Worker 
5475*5e7646d2SAndroid Build Coastguard Worker 
5476*5e7646d2SAndroid Build Coastguard Worker  /*
5477*5e7646d2SAndroid Build Coastguard Worker   * Get/create the job-printer-state-* attributes...
5478*5e7646d2SAndroid Build Coastguard Worker   */
5479*5e7646d2SAndroid Build Coastguard Worker 
5480*5e7646d2SAndroid Build Coastguard Worker   if (!job->printer_message)
5481*5e7646d2SAndroid Build Coastguard Worker   {
5482*5e7646d2SAndroid Build Coastguard Worker     if ((job->printer_message = ippFindAttribute(job->attrs,
5483*5e7646d2SAndroid Build Coastguard Worker                                                  "job-printer-state-message",
5484*5e7646d2SAndroid Build Coastguard Worker 						 IPP_TAG_TEXT)) == NULL)
5485*5e7646d2SAndroid Build Coastguard Worker       job->printer_message = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_TEXT,
5486*5e7646d2SAndroid Build Coastguard Worker                                           "job-printer-state-message",
5487*5e7646d2SAndroid Build Coastguard Worker 					  NULL, "");
5488*5e7646d2SAndroid Build Coastguard Worker   }
5489*5e7646d2SAndroid Build Coastguard Worker 
5490*5e7646d2SAndroid Build Coastguard Worker   if (!job->printer_reasons)
5491*5e7646d2SAndroid Build Coastguard Worker     job->printer_reasons = ippFindAttribute(job->attrs,
5492*5e7646d2SAndroid Build Coastguard Worker 					    "job-printer-state-reasons",
5493*5e7646d2SAndroid Build Coastguard Worker 					    IPP_TAG_KEYWORD);
5494*5e7646d2SAndroid Build Coastguard Worker 
5495*5e7646d2SAndroid Build Coastguard Worker  /*
5496*5e7646d2SAndroid Build Coastguard Worker   * Copy or clear the printer-state-message value as needed...
5497*5e7646d2SAndroid Build Coastguard Worker   */
5498*5e7646d2SAndroid Build Coastguard Worker 
5499*5e7646d2SAndroid Build Coastguard Worker   if (job->state_value != IPP_JOB_PROCESSING &&
5500*5e7646d2SAndroid Build Coastguard Worker       job->status_level == CUPSD_LOG_INFO)
5501*5e7646d2SAndroid Build Coastguard Worker   {
5502*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->printer_message, 0, "");
5503*5e7646d2SAndroid Build Coastguard Worker 
5504*5e7646d2SAndroid Build Coastguard Worker     job->dirty = 1;
5505*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_JOBS);
5506*5e7646d2SAndroid Build Coastguard Worker   }
5507*5e7646d2SAndroid Build Coastguard Worker   else if (job->printer->state_message[0] && do_message)
5508*5e7646d2SAndroid Build Coastguard Worker   {
5509*5e7646d2SAndroid Build Coastguard Worker     ippSetString(job->attrs, &job->printer_message, 0, job->printer->state_message);
5510*5e7646d2SAndroid Build Coastguard Worker 
5511*5e7646d2SAndroid Build Coastguard Worker     job->dirty = 1;
5512*5e7646d2SAndroid Build Coastguard Worker     cupsdMarkDirty(CUPSD_DIRTY_JOBS);
5513*5e7646d2SAndroid Build Coastguard Worker   }
5514*5e7646d2SAndroid Build Coastguard Worker 
5515*5e7646d2SAndroid Build Coastguard Worker  /*
5516*5e7646d2SAndroid Build Coastguard Worker   * ... and the printer-state-reasons value...
5517*5e7646d2SAndroid Build Coastguard Worker   */
5518*5e7646d2SAndroid Build Coastguard Worker 
5519*5e7646d2SAndroid Build Coastguard Worker   if (job->printer->num_reasons == 0)
5520*5e7646d2SAndroid Build Coastguard Worker   {
5521*5e7646d2SAndroid Build Coastguard Worker     num_reasons = 1;
5522*5e7646d2SAndroid Build Coastguard Worker     reasons     = &none;
5523*5e7646d2SAndroid Build Coastguard Worker   }
5524*5e7646d2SAndroid Build Coastguard Worker   else
5525*5e7646d2SAndroid Build Coastguard Worker   {
5526*5e7646d2SAndroid Build Coastguard Worker     num_reasons = job->printer->num_reasons;
5527*5e7646d2SAndroid Build Coastguard Worker     reasons     = (const char * const *)job->printer->reasons;
5528*5e7646d2SAndroid Build Coastguard Worker   }
5529*5e7646d2SAndroid Build Coastguard Worker 
5530*5e7646d2SAndroid Build Coastguard Worker   if (!job->printer_reasons || job->printer_reasons->num_values != num_reasons)
5531*5e7646d2SAndroid Build Coastguard Worker   {
5532*5e7646d2SAndroid Build Coastguard Worker    /*
5533*5e7646d2SAndroid Build Coastguard Worker     * Replace/create a job-printer-state-reasons attribute...
5534*5e7646d2SAndroid Build Coastguard Worker     */
5535*5e7646d2SAndroid Build Coastguard Worker 
5536*5e7646d2SAndroid Build Coastguard Worker     ippDeleteAttribute(job->attrs, job->printer_reasons);
5537*5e7646d2SAndroid Build Coastguard Worker 
5538*5e7646d2SAndroid Build Coastguard Worker     job->printer_reasons = ippAddStrings(job->attrs,
5539*5e7646d2SAndroid Build Coastguard Worker                                          IPP_TAG_JOB, IPP_TAG_KEYWORD,
5540*5e7646d2SAndroid Build Coastguard Worker 					 "job-printer-state-reasons",
5541*5e7646d2SAndroid Build Coastguard Worker 					 num_reasons, NULL, NULL);
5542*5e7646d2SAndroid Build Coastguard Worker   }
5543*5e7646d2SAndroid Build Coastguard Worker   else
5544*5e7646d2SAndroid Build Coastguard Worker   {
5545*5e7646d2SAndroid Build Coastguard Worker    /*
5546*5e7646d2SAndroid Build Coastguard Worker     * Don't bother clearing the reason strings if they are the same...
5547*5e7646d2SAndroid Build Coastguard Worker     */
5548*5e7646d2SAndroid Build Coastguard Worker 
5549*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < num_reasons; i ++)
5550*5e7646d2SAndroid Build Coastguard Worker       if (strcmp(job->printer_reasons->values[i].string.text, reasons[i]))
5551*5e7646d2SAndroid Build Coastguard Worker         break;
5552*5e7646d2SAndroid Build Coastguard Worker 
5553*5e7646d2SAndroid Build Coastguard Worker     if (i >= num_reasons)
5554*5e7646d2SAndroid Build Coastguard Worker       return;
5555*5e7646d2SAndroid Build Coastguard Worker 
5556*5e7646d2SAndroid Build Coastguard Worker    /*
5557*5e7646d2SAndroid Build Coastguard Worker     * Not the same, so free the current strings...
5558*5e7646d2SAndroid Build Coastguard Worker     */
5559*5e7646d2SAndroid Build Coastguard Worker 
5560*5e7646d2SAndroid Build Coastguard Worker     for (i = 0; i < num_reasons; i ++)
5561*5e7646d2SAndroid Build Coastguard Worker       _cupsStrFree(job->printer_reasons->values[i].string.text);
5562*5e7646d2SAndroid Build Coastguard Worker   }
5563*5e7646d2SAndroid Build Coastguard Worker 
5564*5e7646d2SAndroid Build Coastguard Worker  /*
5565*5e7646d2SAndroid Build Coastguard Worker   * Copy the reasons...
5566*5e7646d2SAndroid Build Coastguard Worker   */
5567*5e7646d2SAndroid Build Coastguard Worker 
5568*5e7646d2SAndroid Build Coastguard Worker   for (i = 0; i < num_reasons; i ++)
5569*5e7646d2SAndroid Build Coastguard Worker     job->printer_reasons->values[i].string.text = _cupsStrAlloc(reasons[i]);
5570*5e7646d2SAndroid Build Coastguard Worker 
5571*5e7646d2SAndroid Build Coastguard Worker   job->dirty = 1;
5572*5e7646d2SAndroid Build Coastguard Worker   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
5573*5e7646d2SAndroid Build Coastguard Worker }
5574