]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/job.c
Use cupsArray API to store network interface list, and allocate the hostname
[thirdparty/cups.git] / scheduler / job.c
CommitLineData
2d7cba2b 1/*
c9d3f842 2 * "$Id$"
2d7cba2b 3 *
93894a43 4 * Job management routines for the Common UNIX Printing System (CUPS).
2d7cba2b 5 *
6851edcd 6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
2d7cba2b 7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
8784b6a6 17 * 44141 Airport View Drive, Suite 204
8650fcf2 18 * Hollywood, Maryland 20636 USA
2d7cba2b 19 *
edfd3c3d 20 * Voice: (301) 373-9600
2d7cba2b 21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
589eb420 26 * cupsdAddJob() - Add a new job to the job queue...
27 * cupsdCancelJob() - Cancel the specified print job.
28 * cupsdCancelJobs() - Cancel all jobs for the given destination/user...
29 * cupsdCheckJobs() - Check the pending jobs and start any if the
f3e786fc 30 * destination is available.
589eb420 31 * cupsdCleanJobs() - Clean out old jobs.
32 * cupsdFreeAllJobs() - Free all jobs from memory.
33 * cupsdFindJob() - Find the specified job.
34 * cupsdGetPrinterJobCount() - Get the number of pending, processing,
f3e786fc 35 * or held jobs in a printer or class.
589eb420 36 * cupsdGetUserJobCount() - Get the number of pending, processing,
f3e786fc 37 * or held jobs for a user.
589eb420 38 * cupsdHoldJob() - Hold the specified job.
39 * cupsdLoadAllJobs() - Load all jobs from disk.
40 * cupsdMoveJob() - Move the specified job to a different
f3e786fc 41 * destination.
589eb420 42 * cupsdReleaseJob() - Release the specified job.
43 * cupsdRestartJob() - Restart the specified job.
44 * cupsdSaveJob() - Save a job to disk.
45 * cupsdSetJobHoldUntil() - Set the hold time for a job...
46 * cupsdSetJobPriority() - Set the priority of a job, moving it up/down
f3e786fc 47 * in the list as needed.
589eb420 48 * cupsdStartJob() - Start a print job.
49 * cupsdStopAllJobs() - Stop all print jobs.
50 * cupsdStopJob() - Stop a print job.
51 * cupsdUpdateJob() - Read a status update from a job's filters.
f3e786fc 52 * compare_active_jobs() - Compare the job IDs and priorities of two jobs.
53 * compare_jobs() - Compare the job IDs of two jobs.
54 * ipp_length() - Compute the size of the buffer needed to hold
55 * the textual IPP attributes.
56 * set_hold_until() - Set the hold time and update job-hold-until attribute.
2d7cba2b 57 */
58
59/*
60 * Include necessary headers...
61 */
62
a9de544f 63#include "cupsd.h"
9d13ae31 64#include <grp.h>
6248387b 65#include <cups/backend.h>
08379093 66#include <cups/dir.h>
a9de544f 67
68
d59a189c 69/*
70 * Local globals...
71 */
72
73static mime_filter_t gziptoany_filter =
74 {
75 NULL, /* Source type */
76 NULL, /* Destination type */
77 0, /* Cost */
78 "gziptoany" /* Filter program to run */
79 };
80
81
bfa1abf0 82/*
83 * Local functions...
84 */
85
82306f04 86static int compare_active_jobs(void *first, void *second, void *data);
87static int compare_jobs(void *first, void *second, void *data);
88static int ipp_length(ipp_t *ipp);
589eb420 89static void set_time(cupsd_job_t *job, const char *name);
90static void set_hold_until(cupsd_job_t *job, time_t holdtime);
bfa1abf0 91
92
93894a43 93/*
589eb420 94 * 'cupsdAddJob()' - Add a new job to the job queue...
93894a43 95 */
96
f3e786fc 97cupsd_job_t * /* O - New job record */
98cupsdAddJob(int priority, /* I - Job priority */
99 const char *dest) /* I - Job destination */
a9de544f 100{
f3e786fc 101 cupsd_job_t *job; /* New job record */
a9de544f 102
103
589eb420 104 job = calloc(sizeof(cupsd_job_t), 1);
a9de544f 105
18fe941f 106 job->id = NextJobId ++;
107 job->priority = priority;
108 job->back_pipes[0] = -1;
109 job->back_pipes[1] = -1;
110 job->print_pipes[0] = -1;
111 job->print_pipes[1] = -1;
18fe941f 112
589eb420 113 cupsdSetString(&job->dest, dest);
a9de544f 114
82306f04 115 /*
116 * Add the new job to the "all jobs" and "active jobs" lists...
117 */
a9de544f 118
82306f04 119 cupsArrayAdd(Jobs, job);
120 cupsArrayAdd(ActiveJobs, job);
a9de544f 121
122 return (job);
123}
124
125
93894a43 126/*
589eb420 127 * 'cupsdCancelJob()' - Cancel the specified print job.
93894a43 128 */
129
a9de544f 130void
7726c8b4 131cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */
132 int purge) /* I - Purge jobs? */
a9de544f 133{
f3e786fc 134 int i; /* Looping var */
f3e786fc 135 char filename[1024]; /* Job filename */
a9de544f 136
137
7726c8b4 138 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCancelJob: id = %d", job->id);
6abc7437 139
82306f04 140 /*
141 * Remove the job from the active list...
142 */
4979ce3d 143
82306f04 144 cupsArrayRemove(ActiveJobs, job);
6abc7437 145
82306f04 146 /*
147 * Stop any processes that are working on the current job...
148 */
7ebf3a09 149
82306f04 150 if (job->state->values[0].integer == IPP_JOB_PROCESSING)
7726c8b4 151 cupsdStopJob(job, 0);
48e211f3 152
82306f04 153 cupsArrayRemove(ActiveJobs, job);
48e211f3 154
82306f04 155 job->state->values[0].integer = IPP_JOB_CANCELLED;
a9de544f 156
82306f04 157 set_time(job, "time-at-completed");
e09246c8 158
82306f04 159 cupsdExpireSubscriptions(NULL, job);
bd84e0d1 160
82306f04 161 /*
162 * Remove any authentication data...
163 */
bd84e0d1 164
82306f04 165 snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot,
166 job->id);
167 unlink(filename);
1049abbe 168
82306f04 169 /*
170 * Remove the print file for good if we aren't preserving jobs or
171 * files...
172 */
1049abbe 173
82306f04 174 job->current_file = 0;
a9de544f 175
82306f04 176 if (!JobHistory || !JobFiles || purge ||
177 (job->dtype & CUPS_PRINTER_REMOTE))
178 for (i = 1; i <= job->num_files; i ++)
179 {
180 snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
181 job->id, i);
182 unlink(filename);
183 }
a9de544f 184
82306f04 185 if (JobHistory && !purge && !(job->dtype & CUPS_PRINTER_REMOTE))
186 {
187 /*
188 * Save job state info...
189 */
a9de544f 190
7726c8b4 191 cupsdSaveJob(job);
82306f04 192 }
193 else
194 {
195 /*
196 * Remove the job info file...
197 */
bd84e0d1 198
82306f04 199 snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot,
200 job->id);
201 unlink(filename);
7ebf3a09 202
82306f04 203 /*
204 * Remove the job from the "all jobs" list...
205 */
4efad428 206
82306f04 207 cupsArrayRemove(Jobs, job);
43fe1146 208
82306f04 209 /*
210 * Free all memory used...
211 */
a9de544f 212
82306f04 213 if (job->attrs != NULL)
214 ippDelete(job->attrs);
215
216 if (job->num_files > 0)
217 {
218 free(job->compressions);
219 free(job->filetypes);
a9de544f 220 }
82306f04 221
589eb420 222 cupsdClearString(&job->username);
223 cupsdClearString(&job->dest);
82306f04 224
225 free(job);
226 }
a9de544f 227}
228
229
93894a43 230/*
589eb420 231 * 'cupsdCancelJobs()' - Cancel all jobs for the given destination/user...
93894a43 232 */
233
a9de544f 234void
f3e786fc 235cupsdCancelJobs(const char *dest, /* I - Destination to cancel */
236 const char *username, /* I - Username or NULL */
237 int purge) /* I - Purge jobs? */
a9de544f 238{
f3e786fc 239 cupsd_job_t *job; /* Current job */
a9de544f 240
241
589eb420 242 for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
82306f04 243 job;
589eb420 244 job = (cupsd_job_t *)cupsArrayNext(Jobs))
82306f04 245 if ((dest == NULL || !strcmp(job->dest, dest)) &&
246 (username == NULL || !strcmp(job->username, username)))
a9de544f 247 {
248 /*
dd9e85de 249 * Cancel all jobs matching this destination/user...
a9de544f 250 */
251
82306f04 252 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
277a6a9b 253 purge ? "Job purged." : "Job canceled.");
42f94780 254
7726c8b4 255 cupsdCancelJob(job, purge);
a9de544f 256 }
96df88bb 257
589eb420 258 cupsdCheckJobs();
93894a43 259}
a9de544f 260
261
93894a43 262/*
589eb420 263 * 'cupsdCheckJobs()' - Check the pending jobs and start any if the destination
f3e786fc 264 * is available.
93894a43 265 */
266
267void
589eb420 268cupsdCheckJobs(void)
a9de544f 269{
f3e786fc 270 cupsd_job_t *job; /* Current job in queue */
271 cupsd_printer_t *printer, /* Printer destination */
272 *pclass; /* Printer class destination */
a9de544f 273
274
589eb420 275 DEBUG_puts("cupsdCheckJobs()");
6abc7437 276
589eb420 277 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
82306f04 278 job;
589eb420 279 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
6abc7437 280 {
05ca02bc 281 /*
282 * Start held jobs if they are ready...
283 */
284
82306f04 285 if (job->state->values[0].integer == IPP_JOB_HELD &&
286 job->hold_until &&
287 job->hold_until < time(NULL))
288 job->state->values[0].integer = IPP_JOB_PENDING;
05ca02bc 289
bd84e0d1 290 /*
291 * Start pending jobs if the destination is available...
292 */
293
6de33945 294 if (job->state->values[0].integer == IPP_JOB_PENDING && !NeedReload &&
295 !Sleeping)
93894a43 296 {
589eb420 297 printer = cupsdFindDest(job->dest);
b62fb4c4 298 pclass = NULL;
b5cb0608 299
82306f04 300 while (printer &&
301 (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS)))
a2c6b8b1 302 {
303 /*
82306f04 304 * If the class is remote, just pass it to the remote server...
a2c6b8b1 305 */
306
753453e4 307 pclass = printer;
308
82306f04 309 if (!(pclass->type & CUPS_PRINTER_REMOTE))
310 {
311 if (pclass->state != IPP_PRINTER_STOPPED)
589eb420 312 printer = cupsdFindAvailablePrinter(job->dest);
82306f04 313 else
314 printer = NULL;
315 }
a2c6b8b1 316 }
317
82306f04 318 if (!printer && !pclass)
93894a43 319 {
320 /*
321 * Whoa, the printer and/or class for this destination went away;
322 * cancel the job...
323 */
a9de544f 324
f3e786fc 325 cupsdLogMessage(CUPSD_LOG_WARN,
326 "Printer/class %s has gone away; cancelling job %d!",
327 job->dest, job->id);
42f94780 328
82306f04 329 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 330 "Job canceled because the destination printer/class has gone away.");
42f94780 331
7726c8b4 332 cupsdCancelJob(job, 1);
93894a43 333 }
82306f04 334 else if (printer)
93894a43 335 {
336 /*
29a78848 337 * See if the printer is available or remote and not printing a job;
338 * if so, start the job...
93894a43 339 */
340
8661ecdc 341 if (pclass)
342 {
343 /*
344 * Add/update a job-actual-printer-uri attribute for this job
345 * so that we know which printer actually printed the job...
346 */
347
348 ipp_attribute_t *attr; /* job-actual-printer-uri attribute */
349
350
351 if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri",
352 IPP_TAG_URI)) != NULL)
353 cupsdSetString(&attr->values[0].string.text, printer->uri);
354 else
355 ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI,
356 "job-actual-printer-uri", NULL, printer->uri);
357 }
358
29a78848 359 if (printer->state == IPP_PRINTER_IDLE || /* Printer is idle */
360 ((printer->type & CUPS_PRINTER_REMOTE) && /* Printer is remote */
361 !printer->job)) /* and not printing a job */
7726c8b4 362 cupsdStartJob(job, printer);
93894a43 363 }
364 }
6abc7437 365 }
a9de544f 366}
367
368
d7845573 369/*
589eb420 370 * 'cupsdCleanJobs()' - Clean out old jobs.
d7845573 371 */
372
373void
589eb420 374cupsdCleanJobs(void)
d7845573 375{
f3e786fc 376 cupsd_job_t *job; /* Current job */
d7845573 377
378
82306f04 379 if (!MaxJobs)
d7845573 380 return;
381
589eb420 382 for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
82306f04 383 job && cupsArrayCount(Jobs) >= MaxJobs;
589eb420 384 job = (cupsd_job_t *)cupsArrayNext(Jobs))
d7845573 385 if (job->state->values[0].integer >= IPP_JOB_CANCELLED)
7726c8b4 386 cupsdCancelJob(job, 1);
d7845573 387}
388
389
017c50f3 390/*
589eb420 391 * 'cupsdFinishJob()' - Finish a job.
017c50f3 392 */
393
394void
f3e786fc 395cupsdFinishJob(cupsd_job_t *job) /* I - Job */
017c50f3 396{
f3e786fc 397 int job_history; /* Did cupsdCancelJob() keep the job? */
398 cupsd_printer_t *printer; /* Current printer */
017c50f3 399
400
f3e786fc 401 cupsdLogMessage(CUPSD_LOG_DEBUG,
402 "cupsdFinishJob: job %d, file %d is complete.",
403 job->id, job->current_file - 1);
017c50f3 404
f3e786fc 405 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishJob: job->status is %d",
406 job->status);
556f5ea5 407
294f4cee 408 if (job->status_buffer && job->current_file >= job->num_files)
017c50f3 409 {
410 /*
411 * Close the pipe and clear the input bit.
412 */
413
f3e786fc 414 cupsdLogMessage(CUPSD_LOG_DEBUG2,
415 "cupsdFinishJob: Removing fd %d from InputSet...",
416 job->status_buffer->fd);
017c50f3 417
294f4cee 418 FD_CLR(job->status_buffer->fd, InputSet);
017c50f3 419
f3e786fc 420 cupsdLogMessage(CUPSD_LOG_DEBUG2,
421 "cupsdFinishJob: Closing status input pipe %d...",
422 job->status_buffer->fd);
294f4cee 423
424 cupsdStatBufDelete(job->status_buffer);
017c50f3 425
294f4cee 426 job->status_buffer = NULL;
017c50f3 427 }
428
6851edcd 429 printer = job->printer;
430
017c50f3 431 if (job->status < 0)
432 {
433 /*
434 * Backend had errors; stop it...
435 */
436
6248387b 437 switch (-job->status)
438 {
439 default :
440 case CUPS_BACKEND_FAILED :
441 /*
442 * Backend failure, use the error-policy to determine how to
443 * act...
444 */
017c50f3 445
7726c8b4 446 cupsdStopJob(job, 0);
6248387b 447 job->state->values[0].integer = IPP_JOB_PENDING;
7726c8b4 448 cupsdSaveJob(job);
017c50f3 449
6248387b 450 /*
451 * If the job was queued to a class, try requeuing it... For
452 * faxes and retry-job queues, hold the current job for 5 minutes.
453 */
017c50f3 454
6248387b 455 if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
589eb420 456 cupsdCheckJobs();
6248387b 457 else if ((printer->type & CUPS_PRINTER_FAX) ||
458 !strcmp(printer->error_policy, "retry-job"))
459 {
460 /*
461 * See how many times we've tried to send the job; if more than
462 * the limit, cancel the job.
463 */
464
465 job->tries ++;
466
c61400d4 467 if (job->tries >= JobRetryLimit)
6248387b 468 {
469 /*
470 * Too many tries...
471 */
472
f3e786fc 473 cupsdLogMessage(CUPSD_LOG_ERROR,
474 "Canceling job %d since it could not be sent after %d tries.",
c61400d4 475 job->id, JobRetryLimit);
6248387b 476
477 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 478 "Job canceled since it could not be sent after %d tries.",
c61400d4 479 JobRetryLimit);
6248387b 480
7726c8b4 481 cupsdCancelJob(job, 0);
6248387b 482 }
483 else
484 {
485 /*
486 * Try again in N seconds...
487 */
488
c61400d4 489 set_hold_until(job, time(NULL) + JobRetryInterval);
6248387b 490 }
491 }
492 else if (!strcmp(printer->error_policy, "abort-job"))
7726c8b4 493 cupsdCancelJob(job, 0);
6248387b 494 break;
017c50f3 495
6248387b 496 case CUPS_BACKEND_CANCEL :
497 /*
498 * Cancel the job...
499 */
017c50f3 500
7726c8b4 501 cupsdCancelJob(job, 0);
6248387b 502 break;
42f94780 503
6248387b 504 case CUPS_BACKEND_HOLD :
505 /*
506 * Hold the job...
507 */
42f94780 508
7726c8b4 509 cupsdStopJob(job, 0);
510 cupsdSetJobHoldUntil(job, "indefinite");
511 cupsdSaveJob(job);
6248387b 512 break;
017c50f3 513
6248387b 514 case CUPS_BACKEND_STOP :
515 /*
516 * Stop the printer...
517 */
017c50f3 518
7726c8b4 519 cupsdStopJob(job, 0);
520 cupsdSaveJob(job);
589eb420 521 cupsdSetPrinterState(printer, IPP_PRINTER_STOPPED, 1);
6248387b 522 break;
523
524 case CUPS_BACKEND_AUTH_REQUIRED :
7726c8b4 525 cupsdStopJob(job, 0);
526 cupsdSetJobHoldUntil(job, "authenticated");
527 cupsdSaveJob(job);
48e211f3 528
529 cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job,
530 "Authentication is required for job %d.", job->id);
6248387b 531 break;
017c50f3 532 }
6248387b 533
534 /*
535 * Try printing another job...
536 */
537
589eb420 538 cupsdCheckJobs();
017c50f3 539 }
540 else if (job->status > 0)
541 {
542 /*
6851edcd 543 * Filter had errors; stop job...
017c50f3 544 */
545
6851edcd 546 cupsdStopJob(job, 1);
547 cupsdSaveJob(job);
548 cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, job->printer, job,
549 "Job stopped due to filter errors; please consult the "
550 "error_log file for details.");
551 cupsdCheckJobs();
017c50f3 552 }
553 else
554 {
555 /*
556 * Job printed successfully; cancel it...
557 */
558
559 if (job->current_file < job->num_files)
560 {
6851edcd 561 /*
562 * Start the next file in the job...
563 */
564
017c50f3 565 FilterLevel -= job->cost;
7726c8b4 566 cupsdStartJob(job, job->printer);
017c50f3 567 }
568 else
569 {
6851edcd 570 /*
571 * Close out this job...
572 */
573
fd0624de 574 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
575 "Job completed successfully.");
576
017c50f3 577 job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE);
578
7726c8b4 579 cupsdCancelJob(job, 0);
017c50f3 580
581 if (job_history)
582 {
583 job->state->values[0].integer = IPP_JOB_COMPLETED;
7726c8b4 584 cupsdSaveJob(job);
017c50f3 585 }
586
6851edcd 587 /*
588 * Clear the printer's state_message and move on...
589 */
590
591 printer->state_message[0] = '\0';
592
589eb420 593 cupsdCheckJobs();
017c50f3 594 }
595 }
596}
597
598
5fe35f41 599/*
589eb420 600 * 'cupsdFreeAllJobs()' - Free all jobs from memory.
5fe35f41 601 */
602
603void
589eb420 604cupsdFreeAllJobs(void)
5fe35f41 605{
f3e786fc 606 cupsd_job_t *job; /* Current job */
5fe35f41 607
608
589eb420 609 cupsdHoldSignals();
5f46b949 610
589eb420 611 cupsdStopAllJobs();
5fe35f41 612
589eb420 613 for (job = (cupsd_job_t *)cupsArrayFirst(Jobs);
82306f04 614 job;
589eb420 615 job = (cupsd_job_t *)cupsArrayNext(Jobs))
5fe35f41 616 {
82306f04 617 cupsArrayRemove(Jobs, job);
618 cupsArrayRemove(ActiveJobs, job);
5fe35f41 619
620 ippDelete(job->attrs);
d59a189c 621
622 if (job->num_files > 0)
623 {
624 free(job->compressions);
625 free(job->filetypes);
626 }
627
5fe35f41 628 free(job);
629 }
f219b8a8 630
589eb420 631 cupsdReleaseSignals();
5fe35f41 632}
633
634
93894a43 635/*
589eb420 636 * 'cupsdFindJob()' - Find the specified job.
93894a43 637 */
638
f3e786fc 639cupsd_job_t * /* O - Job data */
640cupsdFindJob(int id) /* I - Job ID */
a9de544f 641{
7726c8b4 642 cupsd_job_t key; /* Search key */
a9de544f 643
644
82306f04 645 key.id = id;
a9de544f 646
589eb420 647 return ((cupsd_job_t *)cupsArrayFind(Jobs, &key));
a9de544f 648}
649
650
7b1b1c6e 651/*
589eb420 652 * 'cupsdGetPrinterJobCount()' - Get the number of pending, processing,
f3e786fc 653 * or held jobs in a printer or class.
7b1b1c6e 654 */
655
656int /* O - Job count */
f3e786fc 657cupsdGetPrinterJobCount(
658 const char *dest) /* I - Printer or class name */
7b1b1c6e 659{
f3e786fc 660 int count; /* Job count */
661 cupsd_job_t *job; /* Current job */
7b1b1c6e 662
663
589eb420 664 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0;
82306f04 665 job;
589eb420 666 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
82306f04 667 if (!strcasecmp(job->dest, dest))
7b1b1c6e 668 count ++;
669
670 return (count);
671}
672
673
674/*
589eb420 675 * 'cupsdGetUserJobCount()' - Get the number of pending, processing,
f3e786fc 676 * or held jobs for a user.
7b1b1c6e 677 */
678
679int /* O - Job count */
f3e786fc 680cupsdGetUserJobCount(
681 const char *username) /* I - Username */
7b1b1c6e 682{
f3e786fc 683 int count; /* Job count */
684 cupsd_job_t *job; /* Current job */
7b1b1c6e 685
686
589eb420 687 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0;
82306f04 688 job;
589eb420 689 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
82306f04 690 if (!strcasecmp(job->username, username))
7b1b1c6e 691 count ++;
692
693 return (count);
694}
695
696
bd84e0d1 697/*
589eb420 698 * 'cupsdHoldJob()' - Hold the specified job.
bd84e0d1 699 */
700
701void
7726c8b4 702cupsdHoldJob(cupsd_job_t *job) /* I - Job data */
bd84e0d1 703{
7726c8b4 704 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdHoldJob: id = %d", job->id);
bd84e0d1 705
1049abbe 706 if (job->state->values[0].integer == IPP_JOB_PROCESSING)
7726c8b4 707 cupsdStopJob(job, 0);
bd84e0d1 708
589eb420 709 DEBUG_puts("cupsdHoldJob: setting state to held...");
962e5a9f 710
1049abbe 711 job->state->values[0].integer = IPP_JOB_HELD;
bd84e0d1 712
7726c8b4 713 cupsdSaveJob(job);
f63a2256 714
589eb420 715 cupsdCheckJobs();
bd84e0d1 716}
717
718
719/*
589eb420 720 * 'cupsdLoadAllJobs()' - Load all jobs from disk.
bd84e0d1 721 */
722
723void
589eb420 724cupsdLoadAllJobs(void)
bd84e0d1 725{
f3e786fc 726 cups_dir_t *dir; /* Directory */
727 cups_dentry_t *dent; /* Directory entry */
728 char filename[1024]; /* Full filename of job file */
2b290bbf 729 cups_file_t *fp; /* Job file */
f3e786fc 730 cupsd_job_t *job; /* New job */
731 int jobid, /* Current job ID */
732 fileid; /* Current file ID */
733 ipp_attribute_t *attr; /* Job attribute */
734 char method[HTTP_MAX_URI],
735 /* Method portion of URI */
736 username[HTTP_MAX_URI],
737 /* Username portion of URI */
738 host[HTTP_MAX_URI],
739 /* Host portion of URI */
740 resource[HTTP_MAX_URI];
741 /* Resource portion of URI */
742 int port; /* Port portion of URI */
f3e786fc 743 const char *dest; /* Destination */
744 mime_type_t **filetypes; /* New filetypes array */
745 int *compressions; /* New compressions array */
bd84e0d1 746
747
1049abbe 748 /*
82306f04 749 * First create the job lists...
1049abbe 750 */
bd84e0d1 751
82306f04 752 if (!Jobs)
753 Jobs = cupsArrayNew(compare_jobs, NULL);
754
755 if (!ActiveJobs)
756 ActiveJobs = cupsArrayNew(compare_active_jobs, NULL);
56f7cb11 757
82306f04 758 /*
759 * Then open the requests directory...
760 */
761
f3e786fc 762 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdLoadAllJobs: Scanning %s...",
763 RequestRoot);
bf9e2a45 764
08379093 765 if ((dir = cupsDirOpen(RequestRoot)) == NULL)
56f7cb11 766 {
f3e786fc 767 cupsdLogMessage(CUPSD_LOG_ERROR,
768 "cupsdLoadAllJobs: Unable to open spool directory %s: %s",
769 RequestRoot, strerror(errno));
1049abbe 770 return;
56f7cb11 771 }
1049abbe 772
773 /*
774 * Read all the c##### files...
775 */
776
08379093 777 while ((dent = cupsDirRead(dir)) != NULL)
778 if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c')
1049abbe 779 {
780 /*
781 * Allocate memory for the job...
782 */
783
589eb420 784 if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL)
1049abbe 785 {
f3e786fc 786 cupsdLogMessage(CUPSD_LOG_ERROR,
787 "cupsdLoadAllJobs: Ran out of memory for jobs!");
08379093 788 cupsDirClose(dir);
1049abbe 789 return;
790 }
791
792 if ((job->attrs = ippNew()) == NULL)
793 {
794 free(job);
f3e786fc 795 cupsdLogMessage(CUPSD_LOG_ERROR,
796 "cupsdLoadAllJobs: Ran out of memory for job attributes!");
08379093 797 cupsDirClose(dir);
1049abbe 798 return;
799 }
800
801 /*
802 * Assign the job ID...
803 */
804
08379093 805 job->id = atoi(dent->filename + 1);
017c50f3 806 job->back_pipes[0] = -1;
807 job->back_pipes[1] = -1;
808 job->print_pipes[0] = -1;
809 job->print_pipes[1] = -1;
1049abbe 810
f3e786fc 811 cupsdLogMessage(CUPSD_LOG_DEBUG,
812 "cupsdLoadAllJobs: Loading attributes for job %d...",
813 job->id);
56f7cb11 814
1049abbe 815 if (job->id >= NextJobId)
816 NextJobId = job->id + 1;
817
818 /*
819 * Load the job control file...
820 */
821
08379093 822 snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->filename);
2b290bbf 823 if ((fp = cupsFileOpen(filename, "r")) == NULL)
99de6da0 824 {
f3e786fc 825 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 826 "cupsdLoadAllJobs: Unable to open job control file "
827 "\"%s\" - %s!",
f3e786fc 828 filename, strerror(errno));
99de6da0 829 ippDelete(job->attrs);
830 free(job);
db911fcb 831 unlink(filename);
99de6da0 832 continue;
833 }
db911fcb 834 else
1049abbe 835 {
2b290bbf 836 if (ippReadIO(fp, (ipp_iocb_t)cupsFileRead, 1, NULL,
837 job->attrs) != IPP_DATA)
db911fcb 838 {
f3e786fc 839 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 840 "cupsdLoadAllJobs: Unable to read job control file "
841 "\"%s\"!",
f3e786fc 842 filename);
2b290bbf 843 cupsFileClose(fp);
db911fcb 844 ippDelete(job->attrs);
845 free(job);
846 unlink(filename);
847 continue;
848 }
849
2b290bbf 850 cupsFileClose(fp);
1049abbe 851 }
852
8fc34542 853 if ((job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM)) == NULL)
854 {
f3e786fc 855 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 856 "cupsdLoadAllJobs: Missing or bad job-state attribute "
857 "in control file \"%s\"!",
f3e786fc 858 filename);
8fc34542 859 ippDelete(job->attrs);
860 free(job);
861 unlink(filename);
862 continue;
863 }
415199da 864
8be52672 865 if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) == NULL)
866 {
f3e786fc 867 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 868 "cupsdLoadAllJobs: No job-printer-uri attribute in "
869 "control file \"%s\"!",
f3e786fc 870 filename);
8be52672 871 ippDelete(job->attrs);
872 free(job);
723c82e1 873 unlink(filename);
8be52672 874 continue;
875 }
876
00a1fad8 877 httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text, method,
878 sizeof(method), username, sizeof(username), host,
879 sizeof(host), &port, resource, sizeof(resource));
1049abbe 880
9b4efe89 881 if ((dest = cupsdValidateDest(host, resource, &(job->dtype),
882 NULL)) == NULL)
1049abbe 883 {
f3e786fc 884 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 885 "cupsdLoadAllJobs: Unable to queue job for destination "
886 "\"%s\"!",
f3e786fc 887 attr->values[0].string.text);
1049abbe 888 ippDelete(job->attrs);
889 free(job);
723c82e1 890 unlink(filename);
1049abbe 891 continue;
892 }
893
589eb420 894 cupsdSetString(&job->dest, dest);
1049abbe 895
3dc4d2a9 896 job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
897 IPP_TAG_INTEGER);
f3e786fc 898 job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
1049abbe 899
2b290bbf 900 if ((attr = ippFindAttribute(job->attrs, "job-priority",
901 IPP_TAG_INTEGER)) == NULL)
d3d40607 902 {
f3e786fc 903 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 904 "cupsdLoadAllJobs: Missing or bad job-priority "
905 "attribute in control file \"%s\"!",
f3e786fc 906 filename);
d3d40607 907 ippDelete(job->attrs);
908 free(job);
909 unlink(filename);
910 continue;
911 }
1049abbe 912 job->priority = attr->values[0].integer;
913
2b290bbf 914 if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name",
915 IPP_TAG_NAME)) == NULL)
d3d40607 916 {
f3e786fc 917 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 918 "cupsdLoadAllJobs: Missing or bad "
919 "job-originating-user-name attribute in control file "
920 "\"%s\"!",
f3e786fc 921 filename);
d3d40607 922 ippDelete(job->attrs);
923 free(job);
924 unlink(filename);
925 continue;
926 }
589eb420 927 cupsdSetString(&job->username, attr->values[0].string.text);
1049abbe 928
929 /*
930 * Insert the job into the array, sorting by job priority and ID...
931 */
932
82306f04 933 cupsArrayAdd(Jobs, job);
934 if (job->state->values[0].integer < IPP_JOB_STOPPED)
935 cupsArrayAdd(ActiveJobs,job);
ec36d2ed 936
937 /*
938 * Set the job hold-until time and state...
939 */
940
941 if (job->state->values[0].integer == IPP_JOB_HELD)
942 {
2b290bbf 943 if ((attr = ippFindAttribute(job->attrs, "job-hold-until",
944 IPP_TAG_KEYWORD)) == NULL)
ec36d2ed 945 attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
946
947 if (attr == NULL)
948 job->state->values[0].integer = IPP_JOB_PENDING;
949 else
7726c8b4 950 cupsdSetJobHoldUntil(job, attr->values[0].string.text);
ec36d2ed 951 }
952 else if (job->state->values[0].integer == IPP_JOB_PROCESSING)
953 job->state->values[0].integer = IPP_JOB_PENDING;
1049abbe 954 }
955
956 /*
957 * Read all the d##### files...
958 */
959
08379093 960 cupsDirRewind(dir);
1049abbe 961
08379093 962 while ((dent = cupsDirRead(dir)) != NULL)
963 if (strlen(dent->filename) > 7 && dent->filename[0] == 'd' &&
964 strchr(dent->filename, '-'))
1049abbe 965 {
966 /*
967 * Find the job...
968 */
969
08379093 970 jobid = atoi(dent->filename + 1);
971 fileid = atoi(strchr(dent->filename, '-') + 1);
1049abbe 972
f3e786fc 973 cupsdLogMessage(CUPSD_LOG_DEBUG,
974 "cupsdLoadAllJobs: Auto-typing document file %s...",
975 dent->filename);
56f7cb11 976
08379093 977 snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->filename);
1049abbe 978
589eb420 979 if ((job = cupsdFindJob(jobid)) == NULL)
1049abbe 980 {
f3e786fc 981 cupsdLogMessage(CUPSD_LOG_ERROR,
982 "cupsdLoadAllJobs: Orphaned print file \"%s\"!",
983 filename);
723c82e1 984 unlink(filename);
1049abbe 985 continue;
986 }
987
988 if (fileid > job->num_files)
989 {
990 if (job->num_files == 0)
d59a189c 991 {
992 compressions = (int *)calloc(fileid, sizeof(int));
993 filetypes = (mime_type_t **)calloc(fileid, sizeof(mime_type_t *));
994 }
1049abbe 995 else
d59a189c 996 {
997 compressions = (int *)realloc(job->compressions,
998 sizeof(int) * fileid);
999 filetypes = (mime_type_t **)realloc(job->filetypes,
1000 sizeof(mime_type_t *) * fileid);
1001 }
1049abbe 1002
d59a189c 1003 if (compressions == NULL || filetypes == NULL)
1049abbe 1004 {
2b290bbf 1005 cupsdLogMessage(CUPSD_LOG_ERROR,
1006 "cupsdLoadAllJobs: Ran out of memory for job file "
1007 "types!");
1049abbe 1008 continue;
1009 }
1010
d59a189c 1011 job->compressions = compressions;
1012 job->filetypes = filetypes;
1013 job->num_files = fileid;
1049abbe 1014 }
1015
d59a189c 1016 job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename,
1017 job->compressions + fileid - 1);
35a2ba9d 1018
1019 if (job->filetypes[fileid - 1] == NULL)
df7507f5 1020 job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application",
1021 "vnd.cups-raw");
1049abbe 1022 }
1023
08379093 1024 cupsDirClose(dir);
04de52f8 1025
43fe1146 1026 /*
1027 * Clean out old jobs as needed...
1028 */
1029
589eb420 1030 cupsdCleanJobs();
bd84e0d1 1031}
1032
1033
93894a43 1034/*
589eb420 1035 * 'cupsdMoveJob()' - Move the specified job to a different destination.
93894a43 1036 */
1037
a9de544f 1038void
7726c8b4 1039cupsdMoveJob(cupsd_job_t *job, /* I - Job */
1040 const char *dest) /* I - Destination */
a9de544f 1041{
017c50f3 1042 ipp_attribute_t *attr; /* job-printer-uri attribute */
f3e786fc 1043 cupsd_printer_t *p; /* Destination printer or class */
262ed403 1044
a9de544f 1045
82306f04 1046 /*
7726c8b4 1047 * Find the printer...
82306f04 1048 */
262ed403 1049
589eb420 1050 if ((p = cupsdFindDest(dest)) == NULL)
262ed403 1051 return;
a9de544f 1052
82306f04 1053 /*
1054 * Don't move completed jobs...
1055 */
753453e4 1056
82306f04 1057 if (job->state->values[0].integer >= IPP_JOB_PROCESSING)
1058 return;
1049abbe 1059
82306f04 1060 /*
1061 * Change the destination information...
1062 */
262ed403 1063
589eb420 1064 cupsdSetString(&job->dest, dest);
82306f04 1065 job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE |
1066 CUPS_PRINTER_IMPLICIT);
a9de544f 1067
82306f04 1068 if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL)
589eb420 1069 cupsdSetString(&(attr->values[0].string.text), p->uri);
82306f04 1070
7726c8b4 1071 cupsdSaveJob(job);
a9de544f 1072}
1073
1074
bd84e0d1 1075/*
589eb420 1076 * 'cupsdReleaseJob()' - Release the specified job.
bd84e0d1 1077 */
1078
1079void
7726c8b4 1080cupsdReleaseJob(cupsd_job_t *job) /* I - Job */
bd84e0d1 1081{
7726c8b4 1082 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReleaseJob: id = %d", job->id);
bd84e0d1 1083
1049abbe 1084 if (job->state->values[0].integer == IPP_JOB_HELD)
bd84e0d1 1085 {
589eb420 1086 DEBUG_puts("cupsdReleaseJob: setting state to pending...");
962e5a9f 1087
1049abbe 1088 job->state->values[0].integer = IPP_JOB_PENDING;
7726c8b4 1089 cupsdSaveJob(job);
589eb420 1090 cupsdCheckJobs();
f63a2256 1091 }
1092}
1093
1094
1095/*
589eb420 1096 * 'cupsdRestartJob()' - Restart the specified job.
f63a2256 1097 */
1098
1099void
7726c8b4 1100cupsdRestartJob(cupsd_job_t *job) /* I - Job */
f63a2256 1101{
7726c8b4 1102 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRestartJob: id = %d", job->id);
f63a2256 1103
1e437ea6 1104 if (job->state->values[0].integer == IPP_JOB_STOPPED || JobFiles)
f63a2256 1105 {
53510eae 1106 job->tries = 0;
f63a2256 1107 job->state->values[0].integer = IPP_JOB_PENDING;
7726c8b4 1108 cupsdSaveJob(job);
589eb420 1109 cupsdCheckJobs();
bd84e0d1 1110 }
1111}
1112
1113
1114/*
589eb420 1115 * 'cupsdSaveJob()' - Save a job to disk.
bd84e0d1 1116 */
1117
1118void
7726c8b4 1119cupsdSaveJob(cupsd_job_t *job) /* I - Job */
bd84e0d1 1120{
f3e786fc 1121 char filename[1024]; /* Job control filename */
2b290bbf 1122 cups_file_t *fp; /* Job file */
1049abbe 1123
1124
7726c8b4 1125 snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id);
99de6da0 1126
2b290bbf 1127 if ((fp = cupsFileOpen(filename, "w")) == NULL)
99de6da0 1128 {
f3e786fc 1129 cupsdLogMessage(CUPSD_LOG_ERROR,
2b290bbf 1130 "cupsdSaveJob: Unable to create job control file "
1131 "\"%s\" - %s.",
f3e786fc 1132 filename, strerror(errno));
a2fc3d31 1133 return;
99de6da0 1134 }
1135
2b290bbf 1136 fchmod(cupsFileNumber(fp), 0600);
1137 fchown(cupsFileNumber(fp), RunUser, Group);
6cd03542 1138
2b290bbf 1139 ippWriteIO(fp, (ipp_iocb_t)cupsFileWrite, 1, NULL, job->attrs);
6cd03542 1140
2b290bbf 1141 cupsFileClose(fp);
bd84e0d1 1142}
1143
1144
e583bc2d 1145/*
589eb420 1146 * 'cupsdSetJobHoldUntil()' - Set the hold time for a job...
e583bc2d 1147 */
1148
1149void
7726c8b4 1150cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */
1151 const char *when) /* I - When to resume */
e583bc2d 1152{
e583bc2d 1153 time_t curtime; /* Current time */
1154 struct tm *curdate; /* Current date */
1155 int hour; /* Hold hour */
1156 int minute; /* Hold minute */
1157 int second; /* Hold second */
1158
1159
7726c8b4 1160 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetJobHoldUntil(%d, \"%s\")",
1161 job->id, when);
e583bc2d 1162
1163 second = 0;
1164
7726c8b4 1165 if (!strcmp(when, "indefinite") || !strcmp(when, "authenticated"))
e583bc2d 1166 {
1167 /*
1168 * Hold indefinitely...
1169 */
1170
1171 job->hold_until = 0;
1172 }
82306f04 1173 else if (!strcmp(when, "day-time"))
e583bc2d 1174 {
1175 /*
1176 * Hold to 6am the next morning unless local time is < 6pm.
1177 */
1178
1179 curtime = time(NULL);
1180 curdate = localtime(&curtime);
1181
1182 if (curdate->tm_hour < 18)
1183 job->hold_until = curtime;
1184 else
1185 job->hold_until = curtime +
1186 ((29 - curdate->tm_hour) * 60 + 59 -
1187 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
1188 }
82306f04 1189 else if (!strcmp(when, "evening") || strcmp(when, "night"))
e583bc2d 1190 {
1191 /*
1192 * Hold to 6pm unless local time is > 6pm or < 6am.
1193 */
1194
1195 curtime = time(NULL);
1196 curdate = localtime(&curtime);
1197
1198 if (curdate->tm_hour < 6 || curdate->tm_hour >= 18)
1199 job->hold_until = curtime;
1200 else
1201 job->hold_until = curtime +
1202 ((17 - curdate->tm_hour) * 60 + 59 -
1203 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
1204 }
82306f04 1205 else if (!strcmp(when, "second-shift"))
e583bc2d 1206 {
1207 /*
1208 * Hold to 4pm unless local time is > 4pm.
1209 */
1210
1211 curtime = time(NULL);
1212 curdate = localtime(&curtime);
1213
1214 if (curdate->tm_hour >= 16)
1215 job->hold_until = curtime;
1216 else
1217 job->hold_until = curtime +
1218 ((15 - curdate->tm_hour) * 60 + 59 -
1219 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
1220 }
82306f04 1221 else if (!strcmp(when, "third-shift"))
e583bc2d 1222 {
1223 /*
1224 * Hold to 12am unless local time is < 8am.
1225 */
1226
1227 curtime = time(NULL);
1228 curdate = localtime(&curtime);
1229
1230 if (curdate->tm_hour < 8)
1231 job->hold_until = curtime;
1232 else
1233 job->hold_until = curtime +
1234 ((23 - curdate->tm_hour) * 60 + 59 -
1235 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
1236 }
82306f04 1237 else if (!strcmp(when, "weekend"))
e583bc2d 1238 {
1239 /*
1240 * Hold to weekend unless we are in the weekend.
1241 */
1242
1243 curtime = time(NULL);
1244 curdate = localtime(&curtime);
1245
82306f04 1246 if (curdate->tm_wday || curdate->tm_wday == 6)
e583bc2d 1247 job->hold_until = curtime;
1248 else
1249 job->hold_until = curtime +
1250 (((5 - curdate->tm_wday) * 24 +
1251 (17 - curdate->tm_hour)) * 60 + 59 -
1252 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
e532393d 1253 }
e583bc2d 1254 else if (sscanf(when, "%d:%d:%d", &hour, &minute, &second) >= 2)
1255 {
1256 /*
e6746ecb 1257 * Hold to specified GMT time (HH:MM or HH:MM:SS)...
e583bc2d 1258 */
1259
1260 curtime = time(NULL);
e6746ecb 1261 curdate = gmtime(&curtime);
e583bc2d 1262
1263 job->hold_until = curtime +
1264 ((hour - curdate->tm_hour) * 60 + minute -
1265 curdate->tm_min) * 60 + second - curdate->tm_sec;
1266
1267 /*
1268 * Hold until next day as needed...
1269 */
1270
1271 if (job->hold_until < curtime)
1272 job->hold_until += 24 * 60 * 60 * 60;
1273 }
962e5a9f 1274
f3e786fc 1275 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetJobHoldUntil: hold_until = %d",
1276 (int)job->hold_until);
e583bc2d 1277}
1278
1279
9cbd98eb 1280/*
7726c8b4 1281 * 'cupsdSetJobPriority()' - Set the priority of a job, moving it up/down in
1282 * the list as needed.
9cbd98eb 1283 */
1284
1285void
7726c8b4 1286cupsdSetJobPriority(
1287 cupsd_job_t *job, /* I - Job ID */
1288 int priority) /* I - New priority (0 to 100) */
9cbd98eb 1289{
f3e786fc 1290 ipp_attribute_t *attr; /* Job attribute */
9cbd98eb 1291
1292
82306f04 1293 /*
1294 * Don't change completed jobs...
1295 */
1296
1297 if (job->state->values[0].integer >= IPP_JOB_PROCESSING)
9cbd98eb 1298 return;
1299
1300 /*
82306f04 1301 * Set the new priority and re-add the job into the active list...
9cbd98eb 1302 */
1303
82306f04 1304 cupsArrayRemove(ActiveJobs, job);
1305
9cbd98eb 1306 job->priority = priority;
1307
1308 if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) != NULL)
1309 attr->values[0].integer = priority;
1310 else
1311 ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
1312 priority);
1313
82306f04 1314 cupsArrayAdd(ActiveJobs, job);
9cbd98eb 1315
7726c8b4 1316 cupsdSaveJob(job);
9cbd98eb 1317}
1318
1319
93894a43 1320/*
589eb420 1321 * 'cupsdStartJob()' - Start a print job.
93894a43 1322 */
1323
a9de544f 1324void
7726c8b4 1325cupsdStartJob(cupsd_job_t *job, /* I - Job ID */
f3e786fc 1326 cupsd_printer_t *printer) /* I - Printer to print job */
a9de544f 1327{
f3e786fc 1328 int i; /* Looping var */
1329 int slot; /* Pipe slot */
0557217b 1330 cups_array_t *filters; /* Filters for job */
1331 mime_filter_t *filter, /* Current filter */
1332 port_monitor; /* Port monitor filter */
f3e786fc 1333 char method[255], /* Method for output */
1334 *optptr, /* Pointer to options */
1335 *valptr; /* Pointer in value string */
1336 ipp_attribute_t *attr; /* Current attribute */
1337 int pid; /* Process ID of new filter process */
1338 int banner_page; /* 1 if banner page, 0 otherwise */
1339 int statusfds[2], /* Pipes used between the filters and scheduler */
1340 filterfds[2][2];/* Pipes used between the filters */
1341 int envc; /* Number of environment variables */
1342 char *argv[8], /* Filter command-line arguments */
1343 sani_uri[1024], /* Sanitized DEVICE_URI env var */
1344 filename[1024], /* Job filename */
1345 command[1024], /* Full path to filter/backend command */
1346 jobid[255], /* Job ID string */
1347 title[IPP_MAX_NAME],
1348 /* Job title string */
1349 copies[255], /* # copies string */
1350 *envp[100], /* Environment variables */
1351 charset[255], /* CHARSET environment variable */
1352 class_name[255],/* CLASS environment variable */
1353 classification[1024],
1354 /* CLASSIFICATION environment variable */
1355 content_type[1024],
1356 /* CONTENT_TYPE environment variable */
1357 device_uri[1024],
1358 /* DEVICE_URI environment variable */
1359 lang[255], /* LANG environment variable */
1360 ppd[1024], /* PPD environment variable */
1361 printer_name[255],
1362 /* PRINTER environment variable */
1363 rip_max_cache[255];
1364 /* RIP_MAX_CACHE environment variable */
1365 static char *options = NULL;/* Full list of options */
1366 static int optlength = 0; /* Length of option buffer */
1367
1368
7726c8b4 1369 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob() id = %d, file = %d/%d",
1370 job->id, job->current_file, job->num_files);
93336dbc 1371
82306f04 1372 if (job->num_files == 0)
b4257036 1373 {
f3e786fc 1374 cupsdLogMessage(CUPSD_LOG_ERROR, "Job ID %d has no files! Cancelling it!",
7726c8b4 1375 job->id);
42f94780 1376
82306f04 1377 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 1378 "Job canceled because it has no files.");
42f94780 1379
7726c8b4 1380 cupsdCancelJob(job, 0);
b4257036 1381 return;
1382 }
1383
e63d9801 1384 /*
1385 * Figure out what filters are required to convert from
1386 * the source to the destination type...
1387 */
1388
0557217b 1389 filters = NULL;
82306f04 1390 job->cost = 0;
e63d9801 1391
a7a1daf4 1392 if (printer->raw)
e63d9801 1393 {
1394 /*
a7a1daf4 1395 * Remote jobs and raw queues go directly to the printer without
d47f8ebe 1396 * filtering...
e63d9801 1397 */
6abc7437 1398
f3e786fc 1399 cupsdLogMessage(CUPSD_LOG_DEBUG,
1400 "cupsdStartJob: Sending job to queue tagged as raw...");
8f9fe91c 1401
e63d9801 1402 filters = NULL;
1403 }
1404 else
1405 {
1406 /*
1407 * Local jobs get filtered...
1408 */
a9de544f 1409
82306f04 1410 filters = mimeFilter(MimeDatabase, job->filetypes[job->current_file],
0557217b 1411 printer->filetype, &(job->cost), MAX_FILTERS - 1);
6abc7437 1412
0557217b 1413 if (!filters)
e63d9801 1414 {
f3e786fc 1415 cupsdLogMessage(CUPSD_LOG_ERROR,
1416 "Unable to convert file %d to printable format for job %d!",
1417 job->current_file, job->id);
1418 cupsdLogMessage(CUPSD_LOG_INFO,
1419 "Hint: Do you have ESP Ghostscript installed?");
deb855a2 1420
f3e786fc 1421 if (LogLevel < CUPSD_LOG_DEBUG)
1422 cupsdLogMessage(CUPSD_LOG_INFO,
1423 "Hint: Try setting the LogLevel to \"debug\".");
deb855a2 1424
82306f04 1425 job->current_file ++;
93336dbc 1426
82306f04 1427 if (job->current_file == job->num_files)
42f94780 1428 {
82306f04 1429 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 1430 "Job canceled because it has no files that can be printed.");
42f94780 1431
7726c8b4 1432 cupsdCancelJob(job, 0);
42f94780 1433 }
93336dbc 1434
e63d9801 1435 return;
1436 }
8239f206 1437
753453e4 1438 /*
1439 * Remove NULL ("-") filters...
1440 */
1441
0557217b 1442 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
1443 filter;
1444 filter = (mime_filter_t *)cupsArrayNext(filters))
1445 if (!strcmp(filter->filter, "-"))
1446 cupsArrayRemove(filters, filter);
753453e4 1447
0557217b 1448 if (cupsArrayCount(filters) == 0)
753453e4 1449 {
0557217b 1450 cupsArrayDelete(filters);
753453e4 1451 filters = NULL;
1452 }
8239f206 1453 }
1454
1455 /*
1456 * See if the filter cost is too high...
1457 */
1458
82306f04 1459 if ((FilterLevel + job->cost) > FilterLimit && FilterLevel > 0 &&
fcc9e285 1460 FilterLimit > 0)
8239f206 1461 {
1462 /*
1463 * Don't print this job quite yet...
1464 */
1465
0557217b 1466 cupsArrayDelete(filters);
8239f206 1467
f3e786fc 1468 cupsdLogMessage(CUPSD_LOG_INFO,
1469 "Holding job %d because filter limit has been reached.",
7726c8b4 1470 job->id);
f3e786fc 1471 cupsdLogMessage(CUPSD_LOG_DEBUG,
1472 "cupsdStartJob: id=%d, file=%d, cost=%d, level=%d, limit=%d",
7726c8b4 1473 job->id, job->current_file, job->cost, FilterLevel,
1474 FilterLimit);
8239f206 1475 return;
e63d9801 1476 }
c7fa9d06 1477
82306f04 1478 FilterLevel += job->cost;
8239f206 1479
d59a189c 1480 /*
1481 * Add decompression filters, if any...
1482 */
1483
82306f04 1484 if (job->compressions[job->current_file])
d59a189c 1485 {
1486 /*
1487 * Add gziptoany filter to the front of the list...
1488 */
1489
0557217b 1490 if (!cupsArrayInsert(filters, &gziptoany_filter))
d59a189c 1491 {
f3e786fc 1492 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add decompression filter - %s",
1493 strerror(errno));
d59a189c 1494
8650fcf2 1495 if (filters != NULL)
1496 free(filters);
d59a189c 1497
82306f04 1498 job->current_file ++;
d59a189c 1499
82306f04 1500 if (job->current_file == job->num_files)
42f94780 1501 {
82306f04 1502 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
0557217b 1503 "Job canceled because the print file could not be "
1504 "decompressed.");
42f94780 1505
7726c8b4 1506 cupsdCancelJob(job, 0);
42f94780 1507 }
d59a189c 1508
1509 return;
1510 }
d59a189c 1511 }
1512
a9bef0b2 1513 /*
1514 * Add port monitor, if any...
1515 */
1516
1517 if (printer->port_monitor)
1518 {
1519 /*
1520 * Add port monitor to the end of the list...
1521 */
1522
0557217b 1523 if (!cupsArrayAdd(filters, &port_monitor))
a9bef0b2 1524 {
f3e786fc 1525 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add port monitor - %s",
1526 strerror(errno));
a9bef0b2 1527
1528 if (filters != NULL)
1529 free(filters);
1530
82306f04 1531 job->current_file ++;
a9bef0b2 1532
82306f04 1533 if (job->current_file == job->num_files)
a9bef0b2 1534 {
82306f04 1535 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
0557217b 1536 "Job canceled because the port monitor could not be "
1537 "added.");
a9bef0b2 1538
7726c8b4 1539 cupsdCancelJob(job, 0);
a9bef0b2 1540 }
1541
1542 return;
1543 }
1544
0557217b 1545 snprintf(port_monitor.filter, sizeof(port_monitor.filter),
a9bef0b2 1546 "%s/monitor/%s", ServerBin, printer->port_monitor);
a9bef0b2 1547 }
1548
8239f206 1549 /*
1550 * Update the printer and job state to "processing"...
1551 */
1552
82306f04 1553 job->state->values[0].integer = IPP_JOB_PROCESSING;
1554 job->status = 0;
1555 job->printer = printer;
7726c8b4 1556 printer->job = job;
589eb420 1557 cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0);
8239f206 1558
82306f04 1559 if (job->current_file == 0)
a2fc3d31 1560 {
82306f04 1561 set_time(job, "time-at-processing");
1562 cupsdOpenPipe(job->back_pipes);
a2fc3d31 1563 }
8239f206 1564
b5cb0608 1565 /*
1566 * Determine if we are printing a banner page or not...
1567 */
1568
f3e786fc 1569 if (job->job_sheets == NULL)
753453e4 1570 {
f3e786fc 1571 cupsdLogMessage(CUPSD_LOG_DEBUG, "No job-sheets attribute.");
1572 if ((job->job_sheets =
82306f04 1573 ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL)
f3e786fc 1574 cupsdLogMessage(CUPSD_LOG_DEBUG,
1575 "... but someone added one without setting job_sheets!");
753453e4 1576 }
f3e786fc 1577 else if (job->job_sheets->num_values == 1)
1578 cupsdLogMessage(CUPSD_LOG_DEBUG, "job-sheets=%s",
1579 job->job_sheets->values[0].string.text);
b5cb0608 1580 else
f3e786fc 1581 cupsdLogMessage(CUPSD_LOG_DEBUG, "job-sheets=%s,%s",
1582 job->job_sheets->values[0].string.text,
1583 job->job_sheets->values[1].string.text);
b5cb0608 1584
934ef66d 1585 if (printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
b5cb0608 1586 banner_page = 0;
f3e786fc 1587 else if (job->job_sheets == NULL)
b5cb0608 1588 banner_page = 0;
f3e786fc 1589 else if (strcasecmp(job->job_sheets->values[0].string.text, "none") != 0 &&
82306f04 1590 job->current_file == 0)
b5cb0608 1591 banner_page = 1;
f3e786fc 1592 else if (job->job_sheets->num_values > 1 &&
1593 strcasecmp(job->job_sheets->values[1].string.text, "none") != 0 &&
82306f04 1594 job->current_file == (job->num_files - 1))
b5cb0608 1595 banner_page = 1;
1596 else
1597 banner_page = 0;
1598
f3e786fc 1599 cupsdLogMessage(CUPSD_LOG_DEBUG, "banner_page = %d", banner_page);
b5cb0608 1600
e63d9801 1601 /*
1602 * Building the options string is harder than it needs to be, but
1603 * for the moment we need to pass strings for command-line args and
1604 * not IPP attribute pointers... :)
673d1710 1605 *
ad717326 1606 * First allocate/reallocate the option buffer as needed...
673d1710 1607 */
1608
82306f04 1609 i = ipp_length(job->attrs);
673d1710 1610
1611 if (i > optlength)
1612 {
1613 if (optlength == 0)
1614 optptr = malloc(i);
1615 else
1616 optptr = realloc(options, i);
1617
1618 if (optptr == NULL)
1619 {
f3e786fc 1620 cupsdLogMessage(CUPSD_LOG_CRIT,
1621 "cupsdStartJob: Unable to allocate %d bytes for option buffer for job %d!",
7726c8b4 1622 i, job->id);
673d1710 1623
1624 if (filters != NULL)
1625 free(filters);
1626
82306f04 1627 FilterLevel -= job->cost;
42f94780 1628
82306f04 1629 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 1630 "Job canceled because the server ran out of memory.");
42f94780 1631
7726c8b4 1632 cupsdCancelJob(job, 0);
673d1710 1633 return;
1634 }
1635
1636 options = optptr;
1637 optlength = i;
1638 }
1639
1640 /*
1641 * Now loop through the attributes and convert them to the textual
1642 * representation used by the filters...
e63d9801 1643 */
6abc7437 1644
e63d9801 1645 optptr = options;
1646 *optptr = '\0';
5b88701c 1647
82306f04 1648 snprintf(title, sizeof(title), "%s-%d", printer->name, job->id);
e63d9801 1649 strcpy(copies, "1");
6abc7437 1650
82306f04 1651 for (attr = job->attrs->attrs; attr != NULL; attr = attr->next)
e63d9801 1652 {
1653 if (strcmp(attr->name, "copies") == 0 &&
1654 attr->value_tag == IPP_TAG_INTEGER)
a3e17a89 1655 {
1656 /*
1657 * Don't use the # copies attribute if we are printing the job sheets...
1658 */
1659
b5cb0608 1660 if (!banner_page)
a3e17a89 1661 sprintf(copies, "%d", attr->values[0].integer);
1662 }
e63d9801 1663 else if (strcmp(attr->name, "job-name") == 0 &&
1664 (attr->value_tag == IPP_TAG_NAME ||
1665 attr->value_tag == IPP_TAG_NAMELANG))
def978d5 1666 strlcpy(title, attr->values[0].string.text, sizeof(title));
d588a92e 1667 else if (attr->group_tag == IPP_TAG_JOB)
e63d9801 1668 {
c0521f33 1669 /*
1670 * Filter out other unwanted attributes...
1671 */
1672
e63d9801 1673 if (attr->value_tag == IPP_TAG_MIMETYPE ||
1674 attr->value_tag == IPP_TAG_NAMELANG ||
1675 attr->value_tag == IPP_TAG_TEXTLANG ||
1676 attr->value_tag == IPP_TAG_URI ||
ec6338d6 1677 attr->value_tag == IPP_TAG_URISCHEME ||
1678 attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */
e63d9801 1679 continue;
6abc7437 1680
83f08393 1681 if (strncmp(attr->name, "time-", 5) == 0)
1682 continue;
1683
1684 if (strncmp(attr->name, "job-", 4) == 0 &&
1685 !(printer->type & CUPS_PRINTER_REMOTE))
1686 continue;
1687
1688 if (strncmp(attr->name, "job-", 4) == 0 &&
d11458ff 1689 strcmp(attr->name, "job-billing") != 0 &&
83f08393 1690 strcmp(attr->name, "job-sheets") != 0 &&
1691 strcmp(attr->name, "job-hold-until") != 0 &&
1692 strcmp(attr->name, "job-priority") != 0)
c0521f33 1693 continue;
1694
b91c8a76 1695 if ((strcmp(attr->name, "page-label") == 0 ||
801766ac 1696 strcmp(attr->name, "page-border") == 0 ||
34089ee8 1697 strncmp(attr->name, "number-up", 9) == 0 ||
1698 strcmp(attr->name, "page-set") == 0) &&
b5cb0608 1699 banner_page)
1700 continue;
1701
c0521f33 1702 /*
1703 * Otherwise add them to the list...
1704 */
1705
e63d9801 1706 if (optptr > options)
50f63f23 1707 strlcat(optptr, " ", optlength - (optptr - options));
6abc7437 1708
e63d9801 1709 if (attr->value_tag != IPP_TAG_BOOLEAN)
6abc7437 1710 {
50f63f23 1711 strlcat(optptr, attr->name, optlength - (optptr - options));
1712 strlcat(optptr, "=", optlength - (optptr - options));
6abc7437 1713 }
1714
e63d9801 1715 for (i = 0; i < attr->num_values; i ++)
1716 {
1717 if (i)
50f63f23 1718 strlcat(optptr, ",", optlength - (optptr - options));
6abc7437 1719
e63d9801 1720 optptr += strlen(optptr);
6abc7437 1721
e63d9801 1722 switch (attr->value_tag)
1723 {
1724 case IPP_TAG_INTEGER :
1725 case IPP_TAG_ENUM :
50f63f23 1726 snprintf(optptr, optlength - (optptr - options),
d588a92e 1727 "%d", attr->values[i].integer);
e63d9801 1728 break;
1729
1730 case IPP_TAG_BOOLEAN :
1731 if (!attr->values[i].boolean)
50f63f23 1732 strlcat(optptr, "no", optlength - (optptr - options));
e63d9801 1733
1734 case IPP_TAG_NOVALUE :
def978d5 1735 strlcat(optptr, attr->name,
50f63f23 1736 optlength - (optptr - options));
e63d9801 1737 break;
1738
1739 case IPP_TAG_RANGE :
74cfdb8b 1740 if (attr->values[i].range.lower == attr->values[i].range.upper)
50f63f23 1741 snprintf(optptr, optlength - (optptr - options) - 1,
74cfdb8b 1742 "%d", attr->values[i].range.lower);
1743 else
50f63f23 1744 snprintf(optptr, optlength - (optptr - options) - 1,
74cfdb8b 1745 "%d-%d", attr->values[i].range.lower,
1746 attr->values[i].range.upper);
e63d9801 1747 break;
1748
1749 case IPP_TAG_RESOLUTION :
50f63f23 1750 snprintf(optptr, optlength - (optptr - options) - 1,
d588a92e 1751 "%dx%d%s", attr->values[i].resolution.xres,
1752 attr->values[i].resolution.yres,
1753 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
1754 "dpi" : "dpc");
e63d9801 1755 break;
1756
1757 case IPP_TAG_STRING :
1758 case IPP_TAG_TEXT :
1759 case IPP_TAG_NAME :
1760 case IPP_TAG_KEYWORD :
1761 case IPP_TAG_CHARSET :
1762 case IPP_TAG_LANGUAGE :
d81dac78 1763 for (valptr = attr->values[i].string.text; *valptr;)
e63d9801 1764 {
9a424b1e 1765 if (strchr(" \t\n\\\'\"", *valptr))
1766 *optptr++ = '\\';
1767 *optptr++ = *valptr++;
e63d9801 1768 }
9a424b1e 1769
1770 *optptr = '\0';
e63d9801 1771 break;
d21a7597 1772
1773 default :
1774 break; /* anti-compiler-warning-code */
e63d9801 1775 }
6abc7437 1776 }
1777
e63d9801 1778 optptr += strlen(optptr);
1779 }
1780 }
6abc7437 1781
e63d9801 1782 /*
1783 * Build the command-line arguments for the filters. Each filter
1784 * has 6 or 7 arguments:
1785 *
1786 * argv[0] = printer
1787 * argv[1] = job ID
1788 * argv[2] = username
1789 * argv[3] = title
1790 * argv[4] = # copies
1791 * argv[5] = options
1792 * argv[6] = filename (optional; normally stdin)
1793 *
1794 * This allows legacy printer drivers that use the old System V
1795 * printing interface to be used by CUPS.
1796 */
1797
82306f04 1798 sprintf(jobid, "%d", job->id);
a6988fb1 1799 snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
82306f04 1800 job->id, job->current_file + 1);
e63d9801 1801
1802 argv[0] = printer->name;
1803 argv[1] = jobid;
82306f04 1804 argv[2] = job->username;
e63d9801 1805 argv[3] = title;
1806 argv[4] = copies;
1807 argv[5] = options;
e09246c8 1808 argv[6] = filename;
e63d9801 1809 argv[7] = NULL;
1810
f3e786fc 1811 cupsdLogMessage(CUPSD_LOG_DEBUG,
1812 "cupsdStartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
1813 argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
e63d9801 1814
1815 /*
1816 * Create environment variable strings for the filters...
1817 */
1818
82306f04 1819 attr = ippFindAttribute(job->attrs, "attributes-natural-language",
e63d9801 1820 IPP_TAG_LANGUAGE);
31e65f97 1821
1822 switch (strlen(attr->values[0].string.text))
1823 {
1824 default :
1825 /*
1826 * This is an unknown or badly formatted language code; use
1827 * the POSIX locale...
1828 */
1829
291355eb 1830 strcpy(lang, "LANG=C");
31e65f97 1831 break;
1832
1833 case 2 :
1834 /*
1835 * Just the language code (ll)...
1836 */
1837
291355eb 1838 snprintf(lang, sizeof(lang), "LANG=%s",
31e65f97 1839 attr->values[0].string.text);
1840 break;
1841
1842 case 5 :
1843 /*
1844 * Language and country code (ll-cc)...
1845 */
1846
291355eb 1847 snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c",
31e65f97 1848 attr->values[0].string.text[0],
1849 attr->values[0].string.text[1],
da275f55 1850 toupper(attr->values[0].string.text[3] & 255),
1851 toupper(attr->values[0].string.text[4] & 255));
31e65f97 1852 break;
1853 }
e63d9801 1854
82306f04 1855 attr = ippFindAttribute(job->attrs, "document-format",
e63d9801 1856 IPP_TAG_MIMETYPE);
ad2b0c5f 1857 if (attr != NULL &&
1858 (optptr = strstr(attr->values[0].string.text, "charset=")) != NULL)
a6988fb1 1859 snprintf(charset, sizeof(charset), "CHARSET=%s", optptr + 8);
e63d9801 1860 else
1861 {
82306f04 1862 attr = ippFindAttribute(job->attrs, "attributes-charset",
e63d9801 1863 IPP_TAG_CHARSET);
a6988fb1 1864 snprintf(charset, sizeof(charset), "CHARSET=%s",
1865 attr->values[0].string.text);
e63d9801 1866 }
6abc7437 1867
a6988fb1 1868 snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
82306f04 1869 job->filetypes[job->current_file]->super,
1870 job->filetypes[job->current_file]->type);
04de52f8 1871 snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", printer->device_uri);
18157eca 1872 cupsdSanitizeURI(printer->device_uri, sani_uri, sizeof(sani_uri));
df3f73ff 1873 snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot, printer->name);
a6988fb1 1874 snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name);
291355eb 1875 snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache);
1876
1877 envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
1878
dd63ebe2 1879 envp[envc ++] = charset;
291355eb 1880 envp[envc ++] = lang;
dd63ebe2 1881 envp[envc ++] = ppd;
291355eb 1882 envp[envc ++] = rip_max_cache;
dd63ebe2 1883 envp[envc ++] = content_type;
1884 envp[envc ++] = device_uri;
1885 envp[envc ++] = printer_name;
997cf8b0 1886
36992080 1887 if (Classification && !banner_page)
753453e4 1888 {
82306f04 1889 if ((attr = ippFindAttribute(job->attrs, "job-sheets",
753453e4 1890 IPP_TAG_NAME)) == NULL)
1891 snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1892 Classification);
1893 else if (attr->num_values > 1 &&
1894 strcmp(attr->values[1].string.text, "none") != 0)
1895 snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1896 attr->values[1].string.text);
1897 else
1898 snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1899 attr->values[0].string.text);
dd63ebe2 1900
1901 envp[envc ++] = classification;
753453e4 1902 }
1cf29e95 1903
82306f04 1904 if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
dd63ebe2 1905 {
82306f04 1906 snprintf(class_name, sizeof(class_name), "CLASS=%s", job->dest);
dd63ebe2 1907 envp[envc ++] = class_name;
1908 }
e63d9801 1909
b696f4e3 1910 envp[envc] = NULL;
dd63ebe2 1911
1912 for (i = 0; i < envc; i ++)
2cb3f80d 1913 if (strncmp(envp[i], "DEVICE_URI=", 11))
f3e786fc 1914 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: envp[%d]=\"%s\"",
1915 i, envp[i]);
2cb3f80d 1916 else
f3e786fc 1917 cupsdLogMessage(CUPSD_LOG_DEBUG,
1918 "cupsdStartJob: envp[%d]=\"DEVICE_URI=%s\"", i, sani_uri);
e63d9801 1919
82306f04 1920 job->current_file ++;
1049abbe 1921
e63d9801 1922 /*
1923 * Now create processes for all of the filters...
1924 */
1925
8650fcf2 1926 if (cupsdOpenPipe(statusfds))
e63d9801 1927 {
f3e786fc 1928 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create job status pipes - %s.",
1929 strerror(errno));
a6988fb1 1930 snprintf(printer->state_message, sizeof(printer->state_message),
1931 "Unable to create status pipes - %s.", strerror(errno));
c8a55d2c 1932
589eb420 1933 cupsdAddPrinterHistory(printer);
db3c5bfd 1934
1935 if (filters != NULL)
1936 free(filters);
1937
82306f04 1938 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 1939 "Job canceled because the server could not create the job status pipes.");
42f94780 1940
7726c8b4 1941 cupsdCancelJob(job, 0);
e63d9801 1942 return;
1943 }
6abc7437 1944
f3e786fc 1945 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: statusfds = [ %d %d ]",
1946 statusfds[0], statusfds[1]);
bfa1abf0 1947
e6df8a90 1948#ifdef FD_CLOEXEC
1949 fcntl(statusfds[0], F_SETFD, FD_CLOEXEC);
1950 fcntl(statusfds[1], F_SETFD, FD_CLOEXEC);
1951#endif /* FD_CLOEXEC */
1952
82306f04 1953 job->status_buffer = cupsdStatBufNew(statusfds[0], "[Job %d]",
1954 job->id);
1955 job->status = 0;
1956 memset(job->filters, 0, sizeof(job->filters));
6abc7437 1957
e63d9801 1958 filterfds[1][0] = open("/dev/null", O_RDONLY);
1959 filterfds[1][1] = -1;
93336dbc 1960
db3c5bfd 1961 if (filterfds[1][0] < 0)
1962 {
f3e786fc 1963 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"/dev/null\" - %s.",
1964 strerror(errno));
db3c5bfd 1965 snprintf(printer->state_message, sizeof(printer->state_message),
1966 "Unable to open \"/dev/null\" - %s.", strerror(errno));
1967
589eb420 1968 cupsdAddPrinterHistory(printer);
db3c5bfd 1969
1970 if (filters != NULL)
1971 free(filters);
1972
8650fcf2 1973 cupsdClosePipe(statusfds);
7726c8b4 1974 cupsdCancelJob(job, 0);
db3c5bfd 1975 return;
1976 }
1977
1978 fcntl(filterfds[1][0], F_SETFD, fcntl(filterfds[1][0], F_GETFD) | FD_CLOEXEC);
1979
f3e786fc 1980 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: filterfds[%d] = [ %d %d ]",
1981 1, filterfds[1][0], filterfds[1][1]);
bfa1abf0 1982
0557217b 1983 for (i = 0, slot = 0, filter = (mime_filter_t *)cupsArrayFirst(filters);
1984 filter;
1985 i ++, filter = (mime_filter_t *)cupsArrayNext(filters))
e63d9801 1986 {
0557217b 1987 if (filter->filter[0] != '/')
a6988fb1 1988 snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
0557217b 1989 filter->filter);
e63d9801 1990 else
0557217b 1991 strlcpy(command, filter->filter, sizeof(command));
6abc7437 1992
0557217b 1993 if (i < (cupsArrayCount(filters) - 1))
8650fcf2 1994 {
1995 if (cupsdOpenPipe(filterfds[slot]))
1996 {
f3e786fc 1997 cupsdLogMessage(CUPSD_LOG_ERROR,
1998 "Unable to create job filter pipes - %s.",
1999 strerror(errno));
8650fcf2 2000 snprintf(printer->state_message, sizeof(printer->state_message),
2001 "Unable to create filter pipes - %s.", strerror(errno));
589eb420 2002 cupsdAddPrinterHistory(printer);
8650fcf2 2003
0557217b 2004 cupsArrayDelete(filters);
8650fcf2 2005
2006 cupsdClosePipe(statusfds);
2007 cupsdClosePipe(filterfds[!slot]);
42f94780 2008
82306f04 2009 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 2010 "Job canceled because the server could not create the filter pipes.");
42f94780 2011
7726c8b4 2012 cupsdCancelJob(job, 0);
8650fcf2 2013 return;
2014 }
2015 }
e63d9801 2016 else
2017 {
82306f04 2018 if (job->current_file == 1)
a2fc3d31 2019 {
2020 if (strncmp(printer->device_uri, "file:", 5) != 0)
8650fcf2 2021 {
82306f04 2022 if (cupsdOpenPipe(job->print_pipes))
8650fcf2 2023 {
f3e786fc 2024 cupsdLogMessage(CUPSD_LOG_ERROR,
2025 "Unable to create job backend pipes - %s.",
2026 strerror(errno));
8650fcf2 2027 snprintf(printer->state_message, sizeof(printer->state_message),
42f94780 2028 "Unable to create backend pipes - %s.", strerror(errno));
589eb420 2029 cupsdAddPrinterHistory(printer);
8650fcf2 2030
0557217b 2031 cupsArrayDelete(filters);
8650fcf2 2032
2033 cupsdClosePipe(statusfds);
2034 cupsdClosePipe(filterfds[!slot]);
42f94780 2035
82306f04 2036 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 2037 "Job canceled because the server could not create the backend pipes.");
42f94780 2038
7726c8b4 2039 cupsdCancelJob(job, 0);
8650fcf2 2040 return;
2041 }
2042 }
a2fc3d31 2043 else
2044 {
82306f04 2045 job->print_pipes[0] = -1;
e6df8a90 2046 if (!strncmp(printer->device_uri, "file:/dev/", 10) &&
2047 strcmp(printer->device_uri, "file:/dev/null"))
82306f04 2048 job->print_pipes[1] = open(printer->device_uri + 5,
f3e786fc 2049 O_WRONLY | O_EXCL);
e6df8a90 2050 else if (!strncmp(printer->device_uri, "file:///dev/", 12) &&
2051 strcmp(printer->device_uri, "file:///dev/null"))
82306f04 2052 job->print_pipes[1] = open(printer->device_uri + 7,
f3e786fc 2053 O_WRONLY | O_EXCL);
a2fc3d31 2054 else
82306f04 2055 job->print_pipes[1] = open(printer->device_uri + 5,
f3e786fc 2056 O_WRONLY | O_CREAT | O_TRUNC, 0600);
18fe941f 2057
82306f04 2058 if (job->print_pipes[1] < 0)
db3c5bfd 2059 {
f3e786fc 2060 cupsdLogMessage(CUPSD_LOG_ERROR,
2061 "Unable to open output file \"%s\" - %s.",
2062 printer->device_uri, strerror(errno));
db3c5bfd 2063 snprintf(printer->state_message, sizeof(printer->state_message),
2064 "Unable to open output file \"%s\" - %s.",
2065 printer->device_uri, strerror(errno));
2066
589eb420 2067 cupsdAddPrinterHistory(printer);
db3c5bfd 2068
0557217b 2069 cupsArrayDelete(filters);
db3c5bfd 2070
8650fcf2 2071 cupsdClosePipe(statusfds);
2072 cupsdClosePipe(filterfds[!slot]);
42f94780 2073
82306f04 2074 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 2075 "Job canceled because the server could not open the output file.");
42f94780 2076
7726c8b4 2077 cupsdCancelJob(job, 0);
db3c5bfd 2078 return;
2079 }
2080
82306f04 2081 fcntl(job->print_pipes[1], F_SETFD,
2082 fcntl(job->print_pipes[1], F_GETFD) | FD_CLOEXEC);
db3c5bfd 2083 }
e6df8a90 2084
f3e786fc 2085 cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: print_pipes = [ %d %d ]",
82306f04 2086 job->print_pipes[0], job->print_pipes[1]);
a2fc3d31 2087 }
2088
82306f04 2089 filterfds[slot][0] = job->print_pipes[0];
2090 filterfds[slot][1] = job->print_pipes[1];
e63d9801 2091 }
6abc7437 2092
f3e786fc 2093 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: filter = \"%s\"", command);
2094 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: filterfds[%d] = [ %d %d ]",
2095 slot, filterfds[slot][0], filterfds[slot][1]);
6abc7437 2096
a665f6fc 2097 pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
2098 filterfds[slot][1], statusfds[1],
82306f04 2099 job->back_pipes[0], 0, job->filters + i);
6abc7437 2100
f3e786fc 2101 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2102 "cupsdStartJob: Closing filter pipes for slot %d [ %d %d ]...",
2103 !slot, filterfds[!slot][0], filterfds[!slot][1]);
18fe941f 2104
8650fcf2 2105 cupsdClosePipe(filterfds[!slot]);
6abc7437 2106
e63d9801 2107 if (pid == 0)
2108 {
f3e786fc 2109 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to start filter \"%s\" - %s.",
0557217b 2110 filter->filter, strerror(errno));
a6988fb1 2111 snprintf(printer->state_message, sizeof(printer->state_message),
2112 "Unable to start filter \"%s\" - %s.",
0557217b 2113 filter->filter, strerror(errno));
a5ba1d82 2114
589eb420 2115 cupsdAddPrinterHistory(printer);
c8a55d2c 2116
0557217b 2117 cupsArrayDelete(filters);
a5ba1d82 2118
589eb420 2119 cupsdAddPrinterHistory(printer);
c8a55d2c 2120
82306f04 2121 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 2122 "Job canceled because the server could not execute a filter.");
42f94780 2123
7726c8b4 2124 cupsdCancelJob(job, 0);
e63d9801 2125 return;
2126 }
6abc7437 2127
f3e786fc 2128 cupsdLogMessage(CUPSD_LOG_INFO, "Started filter %s (PID %d) for job %d.",
2129 command, pid, job->id);
db911fcb 2130
2131 argv[6] = NULL;
2132 slot = !slot;
e63d9801 2133 }
6abc7437 2134
0557217b 2135 cupsArrayDelete(filters);
bfa1abf0 2136
e63d9801 2137 /*
2138 * Finally, pipe the final output into a backend process if needed...
2139 */
6abc7437 2140
e63d9801 2141 if (strncmp(printer->device_uri, "file:", 5) != 0)
2142 {
82306f04 2143 if (job->current_file == 1)
a2fc3d31 2144 {
2145 sscanf(printer->device_uri, "%254[^:]", method);
2146 snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, method);
e31bfb6e 2147
18157eca 2148 argv[0] = sani_uri;
e31bfb6e 2149
a2fc3d31 2150 filterfds[slot][0] = -1;
2151 filterfds[slot][1] = open("/dev/null", O_WRONLY);
e31bfb6e 2152
db3c5bfd 2153 if (filterfds[slot][1] < 0)
2154 {
f3e786fc 2155 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"/dev/null\" - %s.",
2156 strerror(errno));
db3c5bfd 2157 snprintf(printer->state_message, sizeof(printer->state_message),
2158 "Unable to open \"/dev/null\" - %s.", strerror(errno));
2159
589eb420 2160 cupsdAddPrinterHistory(printer);
db3c5bfd 2161
8650fcf2 2162 cupsdClosePipe(statusfds);
42f94780 2163
82306f04 2164 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 2165 "Job canceled because the server could not open a file.");
42f94780 2166
7726c8b4 2167 cupsdCancelJob(job, 0);
db3c5bfd 2168 return;
2169 }
2170
2171 fcntl(filterfds[slot][1], F_SETFD,
2172 fcntl(filterfds[slot][1], F_GETFD) | FD_CLOEXEC);
2173
f3e786fc 2174 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: backend = \"%s\"",
2175 command);
2176 cupsdLogMessage(CUPSD_LOG_DEBUG,
2177 "cupsdStartJob: filterfds[%d] = [ %d %d ]",
2178 slot, filterfds[slot][0], filterfds[slot][1]);
e31bfb6e 2179
a665f6fc 2180 pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0],
2181 filterfds[slot][1], statusfds[1],
82306f04 2182 job->back_pipes[1], 1,
2183 &(job->backend));
e31bfb6e 2184
a2fc3d31 2185 if (pid == 0)
2186 {
f3e786fc 2187 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to start backend \"%s\" - %s.",
2188 method, strerror(errno));
a2fc3d31 2189 snprintf(printer->state_message, sizeof(printer->state_message),
2190 "Unable to start backend \"%s\" - %s.", method, strerror(errno));
e31bfb6e 2191
f3e786fc 2192 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2193 "cupsdStartJob: Closing print pipes [ %d %d ]...",
2194 job->print_pipes[0], job->print_pipes[1]);
6cd03542 2195
82306f04 2196 cupsdClosePipe(job->print_pipes);
a2fc3d31 2197
f3e786fc 2198 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2199 "cupsdStartJob: Closing back pipes [ %d %d ]...",
2200 job->back_pipes[0], job->back_pipes[1]);
6cd03542 2201
82306f04 2202 cupsdClosePipe(job->back_pipes);
6cd03542 2203
82306f04 2204 cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job,
8661ecdc 2205 "Job canceled because the server could not execute the backend.");
42f94780 2206
7726c8b4 2207 cupsdCancelJob(job, 0);
a2fc3d31 2208 return;
2209 }
2210 else
2211 {
f3e786fc 2212 cupsdLogMessage(CUPSD_LOG_INFO,
2213 "Started backend %s (PID %d) for job %d.",
2214 command, pid, job->id);
a2fc3d31 2215 }
e63d9801 2216 }
a2fc3d31 2217
82306f04 2218 if (job->current_file == job->num_files)
e63d9801 2219 {
f3e786fc 2220 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2221 "cupsdStartJob: Closing print pipes [ %d %d ]...",
2222 job->print_pipes[0], job->print_pipes[1]);
6cd03542 2223
82306f04 2224 cupsdClosePipe(job->print_pipes);
a2fc3d31 2225
f3e786fc 2226 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2227 "cupsdStartJob: Closing back pipes [ %d %d ]...",
2228 job->back_pipes[0], job->back_pipes[1]);
6cd03542 2229
82306f04 2230 cupsdClosePipe(job->back_pipes);
e63d9801 2231 }
2232 }
2233 else
2234 {
db911fcb 2235 filterfds[slot][0] = -1;
2236 filterfds[slot][1] = -1;
bfa1abf0 2237
82306f04 2238 if (job->current_file == job->num_files)
a2fc3d31 2239 {
f3e786fc 2240 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2241 "cupsdStartJob: Closing print pipes [ %d %d ]...",
2242 job->print_pipes[0], job->print_pipes[1]);
18fe941f 2243
82306f04 2244 cupsdClosePipe(job->print_pipes);
a2fc3d31 2245 }
e63d9801 2246 }
bfa1abf0 2247
f3e786fc 2248 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2249 "cupsdStartJob: Closing filter pipes for slot %d [ %d %d ]...",
2250 slot, filterfds[slot][0], filterfds[slot][1]);
18fe941f 2251
8650fcf2 2252 cupsdClosePipe(filterfds[slot]);
6abc7437 2253
f3e786fc 2254 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2255 "cupsdStartJob: Closing status output pipe %d...",
2256 statusfds[1]);
18fe941f 2257
e63d9801 2258 close(statusfds[1]);
6abc7437 2259
f3e786fc 2260 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2261 "cupsdStartJob: Adding fd %d to InputSet...",
2262 job->status_buffer->fd);
99de6da0 2263
82306f04 2264 FD_SET(job->status_buffer->fd, InputSet);
b9af0be2 2265
2266 cupsdAddEvent(CUPSD_EVENT_JOB_STATE, job->printer, job, "Job #%d started.",
2267 job->id);
a9de544f 2268}
2269
2270
bd84e0d1 2271/*
589eb420 2272 * 'cupsdStopAllJobs()' - Stop all print jobs.
bd84e0d1 2273 */
2274
2275void
589eb420 2276cupsdStopAllJobs(void)
bd84e0d1 2277{
589eb420 2278 cupsd_job_t *job; /* Current job */
1049abbe 2279
2280
589eb420 2281 DEBUG_puts("cupsdStopAllJobs()");
1049abbe 2282
589eb420 2283 for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
82306f04 2284 job;
589eb420 2285 job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
82306f04 2286 if (job->state->values[0].integer == IPP_JOB_PROCESSING)
1049abbe 2287 {
7726c8b4 2288 cupsdStopJob(job, 1);
82306f04 2289 job->state->values[0].integer = IPP_JOB_PENDING;
1049abbe 2290 }
bd84e0d1 2291}
2292
2293
93894a43 2294/*
589eb420 2295 * 'cupsdStopJob()' - Stop a print job.
93894a43 2296 */
2297
a9de544f 2298void
7726c8b4 2299cupsdStopJob(cupsd_job_t *job, /* I - Job */
2300 int force) /* I - 1 = Force all filters to stop */
a9de544f 2301{
7726c8b4 2302 int i; /* Looping var */
a9de544f 2303
2304
f3e786fc 2305 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStopJob: id = %d, force = %d",
7726c8b4 2306 job->id, force);
6abc7437 2307
82306f04 2308 if (job->state->values[0].integer != IPP_JOB_PROCESSING)
2309 return;
6abc7437 2310
82306f04 2311 FilterLevel -= job->cost;
8239f206 2312
82306f04 2313 if (job->status < 0 &&
2314 !(job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) &&
2315 !(job->printer->type & CUPS_PRINTER_FAX) &&
2316 !strcmp(job->printer->error_policy, "stop-printer"))
589eb420 2317 cupsdSetPrinterState(job->printer, IPP_PRINTER_STOPPED, 1);
82306f04 2318 else if (job->printer->state != IPP_PRINTER_STOPPED)
589eb420 2319 cupsdSetPrinterState(job->printer, IPP_PRINTER_IDLE, 0);
553ce970 2320
f3e786fc 2321 cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStopJob: printer state is %d",
2322 job->printer->state);
e09246c8 2323
82306f04 2324 job->state->values[0].integer = IPP_JOB_STOPPED;
2325 job->printer->job = NULL;
2326 job->printer = NULL;
a9de544f 2327
82306f04 2328 job->current_file --;
1049abbe 2329
82306f04 2330 for (i = 0; job->filters[i]; i ++)
2331 if (job->filters[i] > 0)
2332 {
2333 cupsdEndProcess(job->filters[i], force);
2334 job->filters[i] = 0;
2335 }
882031b3 2336
82306f04 2337 if (job->backend > 0)
2338 {
2339 cupsdEndProcess(job->backend, force);
2340 job->backend = 0;
2341 }
a2fc3d31 2342
f3e786fc 2343 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2344 "cupsdStopJob: Closing print pipes [ %d %d ]...",
2345 job->print_pipes[0], job->print_pipes[1]);
6cd03542 2346
82306f04 2347 cupsdClosePipe(job->print_pipes);
a2fc3d31 2348
f3e786fc 2349 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2350 "cupsdStopJob: Closing back pipes [ %d %d ]...",
2351 job->back_pipes[0], job->back_pipes[1]);
6cd03542 2352
82306f04 2353 cupsdClosePipe(job->back_pipes);
a2fc3d31 2354
82306f04 2355 if (job->status_buffer)
2356 {
2357 /*
2358 * Close the pipe and clear the input bit.
2359 */
8d5e3b76 2360
f3e786fc 2361 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2362 "cupsdStopJob: Removing fd %d from InputSet...",
2363 job->status_buffer->fd);
db911fcb 2364
82306f04 2365 FD_CLR(job->status_buffer->fd, InputSet);
db911fcb 2366
f3e786fc 2367 cupsdLogMessage(CUPSD_LOG_DEBUG2,
2368 "cupsdStopJob: Closing status input pipe %d...",
2369 job->status_buffer->fd);
db911fcb 2370
82306f04 2371 cupsdStatBufDelete(job->status_buffer);
db911fcb 2372
82306f04 2373 job->status_buffer = NULL;
2374 }
a9de544f 2375}
2d7cba2b 2376
2377
2378/*
589eb420 2379 * 'cupsdUpdateJob()' - Read a status update from a job's filters.
6abc7437 2380 */
2381
2382void
f3e786fc 2383cupsdUpdateJob(cupsd_job_t *job) /* I - Job to check */
6abc7437 2384{
017c50f3 2385 int i; /* Looping var */
017c50f3 2386 int copies; /* Number of copies printed */
294f4cee 2387 char message[1024], /* Message text */
2388 *ptr; /* Pointer update... */
017c50f3 2389 int loglevel; /* Log level for message */
96df88bb 2390
6abc7437 2391
294f4cee 2392 while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel,
2393 message, sizeof(message))) != NULL)
ea315b09 2394 {
2395 /*
294f4cee 2396 * Process page and printer state messages as needed...
ea315b09 2397 */
96df88bb 2398
f3e786fc 2399 if (loglevel == CUPSD_LOG_PAGE)
ea315b09 2400 {
c7fa9d06 2401 /*
aa0cb334 2402 * Page message; send the message to the page_log file and update the
2403 * job sheet count...
c7fa9d06 2404 */
2405
ad2b0c5f 2406 if (job->sheets != NULL)
2407 {
8f4595eb 2408 if (!strncasecmp(message, "total ", 6))
b521f3fc 2409 {
8f4595eb 2410 /*
2411 * Got a total count of pages from a backend or filter...
2412 */
b521f3fc 2413
8f4595eb 2414 copies = atoi(message + 6);
2415 copies -= job->sheets->values[0].integer; /* Just track the delta */
2416 }
2417 else if (!sscanf(message, "%*d%d", &copies))
2418 copies = 1;
2419
2420 job->sheets->values[0].integer += copies;
b521f3fc 2421
8f4595eb 2422 if (job->printer->page_limit)
589eb420 2423 cupsdUpdateQuota(job->printer, job->username, copies, 0);
ad2b0c5f 2424 }
aa0cb334 2425
589eb420 2426 cupsdLogPage(job, message);
42f94780 2427
2428 cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job,
2429 "Printed %d page(s).", job->sheets->values[0].integer);
ea315b09 2430 }
f3e786fc 2431 else if (loglevel == CUPSD_LOG_STATE)
6851edcd 2432 {
589eb420 2433 cupsdSetPrinterReasons(job->printer, message);
6851edcd 2434 cupsdAddPrinterHistory(job->printer);
2435 }
f3e786fc 2436 else if (loglevel == CUPSD_LOG_ATTR)
6248387b 2437 {
2438 /*
2439 * Set attribute(s)...
2440 */
2441
2442 /**** TODO ****/
2443 }
7c9b0290 2444#ifdef __APPLE__
2445 else if (!strncmp(message, "recoverable:", 12))
2446 {
2447 cupsdSetPrinterReasons(job->printer,
2448 "+com.apple.print.recoverable-warning");
2449
a2e8b3e8 2450 ptr = message + 12;
2451 while (isspace(*ptr & 255))
2452 ptr ++;
7c9b0290 2453
a2e8b3e8 2454 cupsdSetString(&job->printer->recoverable, ptr);
7c9b0290 2455 cupsdAddPrinterHistory(job->printer);
2456 }
2457 else if (!strncmp(message, "recovered:", 10))
2458 {
2459 cupsdSetPrinterReasons(job->printer,
2460 "-com.apple.print.recoverable-warning");
2461
a2e8b3e8 2462 ptr = message + 10;
2463 while (isspace(*ptr & 255))
2464 ptr ++;
7c9b0290 2465
a2e8b3e8 2466 cupsdSetString(&job->printer->recoverable, ptr);
7c9b0290 2467 cupsdAddPrinterHistory(job->printer);
2468 }
2469#endif /* __APPLE__ */
6851edcd 2470 else
2471 {
2472 /*
2473 * Some message to show in the printer-state-message attribute...
2474 */
2475
2476 strlcpy(job->printer->state_message, message,
2477 sizeof(job->printer->state_message));
2478 cupsdAddPrinterHistory(job->printer);
2479 }
96df88bb 2480
294f4cee 2481 if (!strchr(job->status_buffer->buffer, '\n'))
2482 break;
96df88bb 2483 }
ea315b09 2484
294f4cee 2485 if (ptr == NULL)
6abc7437 2486 {
d89de04a 2487 /*
2488 * See if all of the filters and the backend have returned their
2489 * exit statuses.
2490 */
2491
017c50f3 2492 for (i = 0; job->filters[i] < 0; i ++);
2493
2494 if (job->filters[i])
2495 return;
d89de04a 2496
2497 if (job->current_file >= job->num_files && job->backend > 0)
2498 return;
2499
2500 /*
2501 * Handle the end of job stuff...
2502 */
2503
589eb420 2504 cupsdFinishJob(job);
6abc7437 2505 }
2506}
2507
2508
82306f04 2509/*
2510 * 'compare_active_jobs()' - Compare the job IDs and priorities of two jobs.
2511 */
2512
2513static int /* O - Difference */
2514compare_active_jobs(void *first, /* I - First job */
2515 void *second, /* I - Second job */
2516 void *data) /* I - App data (not used) */
2517{
2518 int diff; /* Difference */
2519
2520
589eb420 2521 if ((diff = ((cupsd_job_t *)first)->priority - ((cupsd_job_t *)second)->priority) != 0)
82306f04 2522 return (diff);
2523 else
589eb420 2524 return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
82306f04 2525}
2526
2527
2528/*
2529 * 'compare_jobs()' - Compare the job IDs of two jobs.
2530 */
2531
2532static int /* O - Difference */
2533compare_jobs(void *first, /* I - First job */
2534 void *second, /* I - Second job */
2535 void *data) /* I - App data (not used) */
2536{
589eb420 2537 return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id);
82306f04 2538}
2539
2540
ad717326 2541/*
2542 * 'ipp_length()' - Compute the size of the buffer needed to hold
2543 * the textual IPP attributes.
2544 */
2545
017c50f3 2546int /* O - Size of buffer to hold IPP attributes */
2547ipp_length(ipp_t *ipp) /* I - IPP request */
ad717326 2548{
017c50f3 2549 int bytes; /* Number of bytes */
2550 int i; /* Looping var */
2551 ipp_attribute_t *attr; /* Current attribute */
ad717326 2552
2553
2554 /*
2555 * Loop through all attributes...
2556 */
2557
2558 bytes = 0;
2559
2560 for (attr = ipp->attrs; attr != NULL; attr = attr->next)
2561 {
2562 /*
2563 * Skip attributes that won't be sent to filters...
2564 */
2565
2566 if (attr->value_tag == IPP_TAG_MIMETYPE ||
2567 attr->value_tag == IPP_TAG_NAMELANG ||
2568 attr->value_tag == IPP_TAG_TEXTLANG ||
2569 attr->value_tag == IPP_TAG_URI ||
2570 attr->value_tag == IPP_TAG_URISCHEME)
2571 continue;
2572
2573 if (strncmp(attr->name, "time-", 5) == 0)
2574 continue;
2575
2576 /*
2577 * Add space for a leading space and commas between each value.
2578 * For the first attribute, the leading space isn't used, so the
2579 * extra byte can be used as the nul terminator...
2580 */
2581
2582 bytes ++; /* " " separator */
2583 bytes += attr->num_values; /* "," separators */
2584
2585 /*
2586 * Boolean attributes appear as "foo,nofoo,foo,nofoo", while
2587 * other attributes appear as "foo=value1,value2,...,valueN".
2588 */
2589
2590 if (attr->value_tag != IPP_TAG_BOOLEAN)
2591 bytes += strlen(attr->name);
2592 else
2593 bytes += attr->num_values * strlen(attr->name);
2594
2595 /*
2596 * Now add the size required for each value in the attribute...
2597 */
2598
2599 switch (attr->value_tag)
2600 {
2601 case IPP_TAG_INTEGER :
2602 case IPP_TAG_ENUM :
2603 /*
2604 * Minimum value of a signed integer is -2147483647, or 11 digits.
2605 */
2606
2607 bytes += attr->num_values * 11;
2608 break;
2609
2610 case IPP_TAG_BOOLEAN :
2611 /*
2612 * Add two bytes for each false ("no") value...
2613 */
2614
2615 for (i = 0; i < attr->num_values; i ++)
2616 if (!attr->values[i].boolean)
2617 bytes += 2;
2618 break;
2619
2620 case IPP_TAG_RANGE :
2621 /*
2622 * A range is two signed integers separated by a hyphen, or
2623 * 23 characters max.
2624 */
2625
2626 bytes += attr->num_values * 23;
2627 break;
2628
2629 case IPP_TAG_RESOLUTION :
2630 /*
2631 * A resolution is two signed integers separated by an "x" and
2632 * suffixed by the units, or 26 characters max.
2633 */
2634
2635 bytes += attr->num_values * 26;
2636 break;
2637
2638 case IPP_TAG_STRING :
2639 case IPP_TAG_TEXT :
2640 case IPP_TAG_NAME :
2641 case IPP_TAG_KEYWORD :
2642 case IPP_TAG_CHARSET :
2643 case IPP_TAG_LANGUAGE :
2644 /*
2645 * Strings can contain characters that need quoting. We need
2646 * at least 2 * len + 2 characters to cover the quotes and
2647 * any backslashes in the string.
2648 */
2649
2650 for (i = 0; i < attr->num_values; i ++)
2651 bytes += 2 * strlen(attr->values[i].string.text) + 2;
2652 break;
2653
2654 default :
2655 break; /* anti-compiler-warning-code */
2656 }
2657 }
2658
2659 return (bytes);
2660}
2661
2662
7ebf3a09 2663/*
0ccccc99 2664 * 'set_time()' - Set one of the "time-at-xyz" attributes...
7ebf3a09 2665 */
2666
2667static void
f3e786fc 2668set_time(cupsd_job_t *job, /* I - Job to update */
2669 const char *name) /* I - Name of attribute */
7ebf3a09 2670{
f3e786fc 2671 ipp_attribute_t *attr; /* Time attribute */
7ebf3a09 2672
2673
0ccccc99 2674 if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL)
7ebf3a09 2675 {
0ccccc99 2676 attr->value_tag = IPP_TAG_INTEGER;
2677 attr->values[0].integer = time(NULL);
7ebf3a09 2678 }
7ebf3a09 2679}
2680
2681
bfa1abf0 2682/*
225b3683 2683 * 'set_hold_until()' - Set the hold time and update job-hold-until attribute...
2684 */
2685
2686static void
f3e786fc 2687set_hold_until(cupsd_job_t *job, /* I - Job to update */
2688 time_t holdtime) /* I - Hold until time */
225b3683 2689{
2690 ipp_attribute_t *attr; /* job-hold-until attribute */
2691 struct tm *holddate; /* Hold date */
2692 char holdstr[64]; /* Hold time */
2693
2694
2695 /*
2696 * Set the hold_until value and hold the job...
2697 */
2698
f3e786fc 2699 cupsdLogMessage(CUPSD_LOG_DEBUG, "set_hold_until: hold_until = %d", (int)holdtime);
225b3683 2700
2701 job->state->values[0].integer = IPP_JOB_HELD;
2702 job->hold_until = holdtime;
2703
2704 /*
2705 * Update the job-hold-until attribute with a string representing GMT
2706 * time (HH:MM:SS)...
2707 */
2708
2709 holddate = gmtime(&holdtime);
2710 snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour,
2711 holddate->tm_min, holddate->tm_sec);
2712
2713 if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
2714 attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
2715
2716 /*
2717 * Either add the attribute or update the value of the existing one
2718 */
2719
2720 if (attr == NULL)
2721 attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD,
2722 "job-hold-until", NULL, holdstr);
2723 else
589eb420 2724 cupsdSetString(&attr->values[0].string.text, holdstr);
225b3683 2725
7726c8b4 2726 cupsdSaveJob(job);
225b3683 2727}
2728
2729
2730/*
c9d3f842 2731 * End of "$Id$".
2d7cba2b 2732 */