]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/job.c
Fix SAMBA driver export - the Win95 export commands weren't right,
[thirdparty/cups.git] / scheduler / job.c
1 /*
2 * "$Id: job.c,v 1.139 2001/11/09 17:19:43 mike Exp $"
3 *
4 * Job management routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2001 by Easy Software Products, all rights reserved.
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
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * AddJob() - Add a new job to the job queue...
27 * CancelJob() - Cancel the specified print job.
28 * CancelJobs() - Cancel all jobs on the given printer or class.
29 * CheckJobs() - Check the pending jobs and start any if the
30 * destination is available.
31 * CleanJobs() - Clean out old jobs.
32 * FindJob() - Find the specified job.
33 * GetPrinterJobCount() - Get the number of pending, processing,
34 * or held jobs in a printer or class.
35 * GetUserJobCount() - Get the number of pending, processing,
36 * or held jobs for a user.
37 * HoldJob() - Hold the specified job.
38 * LoadAllJobs() - Load all jobs from disk.
39 * LoadJob() - Load a job from disk.
40 * MoveJob() - Move the specified job to a different
41 * destination.
42 * ReleaseJob() - Release the specified job.
43 * RestartJob() - Restart the specified job.
44 * SaveJob() - Save a job to disk.
45 * SetJobHoldUntil() - Set the hold time for a job...
46 * SetJobPriority() - Set the priority of a job, moving it up/down
47 * in the list as needed.
48 * StartJob() - Start a print job.
49 * StopAllJobs() - Stop all print jobs.
50 * StopJob() - Stop a print job.
51 * UpdateJob() - Read a status update from a job's filters.
52 * ipp_read_file() - Read an IPP request from a file.
53 * ipp_write_file() - Write an IPP request to a file.
54 * start_process() - Start a background process.
55 */
56
57 /*
58 * Include necessary headers...
59 */
60
61 #include "cupsd.h"
62 #include <grp.h>
63
64
65 /*
66 * Local functions...
67 */
68
69 static ipp_state_t ipp_read_file(const char *filename, ipp_t *ipp);
70 static ipp_state_t ipp_write_file(const char *filename, ipp_t *ipp);
71 static void set_time(job_t *job, const char *name);
72 static int start_process(const char *command, char *argv[],
73 char *envp[], int in, int out, int err,
74 int root);
75
76
77 /*
78 * 'AddJob()' - Add a new job to the job queue...
79 */
80
81 job_t * /* O - New job record */
82 AddJob(int priority, /* I - Job priority */
83 const char *dest) /* I - Job destination */
84 {
85 job_t *job, /* New job record */
86 *current, /* Current job in queue */
87 *prev; /* Previous job in queue */
88
89
90 job = calloc(sizeof(job_t), 1);
91
92 job->id = NextJobId ++;
93 job->priority = priority;
94 strncpy(job->dest, dest, sizeof(job->dest) - 1);
95
96 NumJobs ++;
97
98 for (current = Jobs, prev = NULL;
99 current != NULL;
100 prev = current, current = current->next)
101 if (job->priority > current->priority)
102 break;
103
104 job->next = current;
105 if (prev != NULL)
106 prev->next = job;
107 else
108 Jobs = job;
109
110 return (job);
111 }
112
113
114 /*
115 * 'CancelJob()' - Cancel the specified print job.
116 */
117
118 void
119 CancelJob(int id, /* I - Job to cancel */
120 int purge) /* I - Purge jobs? */
121 {
122 int i; /* Looping var */
123 job_t *current, /* Current job */
124 *prev; /* Previous job in list */
125 char filename[1024]; /* Job filename */
126
127
128 LogMessage(L_DEBUG, "CancelJob: id = %d", id);
129
130 for (current = Jobs, prev = NULL; current != NULL; prev = current, current = current->next)
131 if (current->id == id)
132 {
133 /*
134 * Stop any processes that are working on the current...
135 */
136
137 DEBUG_puts("CancelJob: found job in list.");
138
139 if (current->state->values[0].integer == IPP_JOB_PROCESSING)
140 StopJob(current->id);
141
142 current->state->values[0].integer = IPP_JOB_CANCELLED;
143
144 set_time(current, "time-at-completed");
145
146 /*
147 * Remove the print file for good if we aren't preserving jobs or
148 * files...
149 */
150
151 current->current_file = 0;
152
153 if (!JobHistory || !JobFiles || purge)
154 for (i = 1; i <= current->num_files; i ++)
155 {
156 snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
157 current->id, i);
158 unlink(filename);
159 }
160
161 if (JobHistory && !purge)
162 {
163 /*
164 * Save job state info...
165 */
166
167 SaveJob(current->id);
168 }
169 else
170 {
171 /*
172 * Remove the job info file...
173 */
174
175 snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot,
176 current->id);
177 unlink(filename);
178
179 /*
180 * Update pointers if we aren't preserving jobs...
181 */
182
183 if (prev == NULL)
184 Jobs = current->next;
185 else
186 prev->next = current->next;
187
188 /*
189 * Free all memory used...
190 */
191
192 if (current->attrs != NULL)
193 ippDelete(current->attrs);
194
195 free(current->filetypes);
196
197 free(current);
198
199 NumJobs --;
200 }
201
202 return;
203 }
204 }
205
206
207 /*
208 * 'CancelJobs()' - Cancel all jobs on the given printer or class.
209 */
210
211 void
212 CancelJobs(const char *dest) /* I - Destination to cancel */
213 {
214 job_t *current; /* Current job */
215
216
217 for (current = Jobs; current != NULL;)
218 if (strcmp(current->dest, dest) == 0)
219 {
220 /*
221 * Cancel all jobs matching this destination...
222 */
223
224 CancelJob(current->id, 1);
225
226 current = Jobs;
227 }
228 else
229 current = current->next;
230
231 CheckJobs();
232 }
233
234
235 /*
236 * 'CheckJobs()' - Check the pending jobs and start any if the destination
237 * is available.
238 */
239
240 void
241 CheckJobs(void)
242 {
243 job_t *current, /* Current job in queue */
244 *next; /* Next job in queue */
245 printer_t *printer, /* Printer destination */
246 *pclass; /* Printer class destination */
247
248
249 DEBUG_puts("CheckJobs()");
250
251 for (current = Jobs; current != NULL; current = next)
252 {
253 /*
254 * Save next pointer in case the job is cancelled en-route.
255 */
256
257 next = current->next;
258
259 /*
260 * Start held jobs if they are ready...
261 */
262
263 if (current->state->values[0].integer == IPP_JOB_HELD &&
264 current->hold_until &&
265 current->hold_until < time(NULL))
266 current->state->values[0].integer = IPP_JOB_PENDING;
267
268 /*
269 * Start pending jobs if the destination is available...
270 */
271
272 if (current->state->values[0].integer == IPP_JOB_PENDING)
273 {
274 if ((pclass = FindClass(current->dest)) != NULL)
275 {
276 /*
277 * If the class is remote, just pass it to the remote server...
278 */
279
280 if (pclass->type & CUPS_PRINTER_REMOTE)
281 printer = pclass;
282 else if (pclass->state != IPP_PRINTER_STOPPED)
283 printer = FindAvailablePrinter(current->dest);
284 else
285 printer = NULL;
286 }
287 else
288 printer = FindPrinter(current->dest);
289
290 if (printer != NULL && (printer->type & CUPS_PRINTER_IMPLICIT))
291 {
292 /*
293 * Handle implicit classes...
294 */
295
296 pclass = printer;
297
298 if (pclass->state != IPP_PRINTER_STOPPED)
299 printer = FindAvailablePrinter(current->dest);
300 else
301 printer = NULL;
302 }
303
304 if (printer == NULL && pclass == NULL)
305 {
306 /*
307 * Whoa, the printer and/or class for this destination went away;
308 * cancel the job...
309 */
310
311 LogMessage(L_WARN, "Printer/class %s has gone away; cancelling job %d!",
312 current->dest, current->id);
313 CancelJob(current->id, 1);
314 }
315 else if (printer != NULL)
316 {
317 /*
318 * See if the printer is available or remote and not printing a job;
319 * if so, start the job...
320 */
321
322 if (printer->state == IPP_PRINTER_IDLE || /* Printer is idle */
323 ((printer->type & CUPS_PRINTER_REMOTE) && /* Printer is remote */
324 !printer->job)) /* and not printing a job */
325 StartJob(current->id, printer);
326 }
327 }
328 }
329 }
330
331
332 /*
333 * 'CleanJobs()' - Clean out old jobs.
334 */
335
336 void
337 CleanJobs(void)
338 {
339 job_t *job, /* Current job */
340 *next; /* Next job */
341
342
343 if (MaxJobs == 0)
344 return;
345
346 for (job = Jobs; job && NumJobs >= MaxJobs; job = next)
347 {
348 next = job->next;
349
350 if (job->state->values[0].integer >= IPP_JOB_CANCELLED)
351 CancelJob(job->id, 1);
352 }
353 }
354
355
356 /*
357 * 'FindJob()' - Find the specified job.
358 */
359
360 job_t * /* O - Job data */
361 FindJob(int id) /* I - Job ID */
362 {
363 job_t *current; /* Current job */
364
365
366 for (current = Jobs; current != NULL; current = current->next)
367 if (current->id == id)
368 break;
369
370 return (current);
371 }
372
373
374 /*
375 * 'GetPrinterJobCount()' - Get the number of pending, processing,
376 * or held jobs in a printer or class.
377 */
378
379 int /* O - Job count */
380 GetPrinterJobCount(const char *dest) /* I - Printer or class name */
381 {
382 int count; /* Job count */
383 job_t *job; /* Current job */
384
385
386 for (job = Jobs, count = 0; job != NULL; job = job->next)
387 if (job->state->values[0].integer <= IPP_JOB_PROCESSING &&
388 strcasecmp(job->dest, dest) == 0)
389 count ++;
390
391 return (count);
392 }
393
394
395 /*
396 * 'GetUserJobCount()' - Get the number of pending, processing,
397 * or held jobs for a user.
398 */
399
400 int /* O - Job count */
401 GetUserJobCount(const char *username) /* I - Username */
402 {
403 int count; /* Job count */
404 job_t *job; /* Current job */
405
406
407 for (job = Jobs, count = 0; job != NULL; job = job->next)
408 if (job->state->values[0].integer <= IPP_JOB_PROCESSING &&
409 strcmp(job->username, username) == 0)
410 count ++;
411
412 return (count);
413 }
414
415
416 /*
417 * 'HoldJob()' - Hold the specified job.
418 */
419
420 void
421 HoldJob(int id) /* I - Job ID */
422 {
423 job_t *job; /* Job data */
424
425
426 LogMessage(L_DEBUG, "HoldJob: id = %d", id);
427
428 if ((job = FindJob(id)) == NULL)
429 return;
430
431 if (job->state->values[0].integer == IPP_JOB_PROCESSING)
432 StopJob(id);
433
434 DEBUG_puts("HoldJob: setting state to held...");
435
436 job->state->values[0].integer = IPP_JOB_HELD;
437
438 SaveJob(id);
439
440 CheckJobs();
441 }
442
443
444 /*
445 * 'LoadAllJobs()' - Load all jobs from disk.
446 */
447
448 void
449 LoadAllJobs(void)
450 {
451 DIR *dir; /* Directory */
452 DIRENT *dent; /* Directory entry */
453 char filename[1024]; /* Full filename of job file */
454 job_t *job, /* New job */
455 *current, /* Current job */
456 *prev; /* Previous job */
457 int jobid, /* Current job ID */
458 fileid; /* Current file ID */
459 ipp_attribute_t *attr; /* Job attribute */
460 char method[HTTP_MAX_URI],
461 /* Method portion of URI */
462 username[HTTP_MAX_URI],
463 /* Username portion of URI */
464 host[HTTP_MAX_URI],
465 /* Host portion of URI */
466 resource[HTTP_MAX_URI];
467 /* Resource portion of URI */
468 int port; /* Port portion of URI */
469 printer_t *p; /* Printer or class */
470 const char *dest; /* Destination */
471 mime_type_t **filetypes; /* New filetypes array */
472
473
474 /*
475 * First open the requests directory...
476 */
477
478 if ((dir = opendir(RequestRoot)) == NULL)
479 return;
480
481 /*
482 * Read all the c##### files...
483 */
484
485 while ((dent = readdir(dir)) != NULL)
486 if (NAMLEN(dent) == 6 && dent->d_name[0] == 'c')
487 {
488 /*
489 * Allocate memory for the job...
490 */
491
492 if ((job = calloc(sizeof(job_t), 1)) == NULL)
493 {
494 LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for jobs!");
495 closedir(dir);
496 return;
497 }
498
499 if ((job->attrs = ippNew()) == NULL)
500 {
501 free(job);
502 LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job attributes!");
503 closedir(dir);
504 return;
505 }
506
507 /*
508 * Assign the job ID...
509 */
510
511 job->id = atoi(dent->d_name + 1);
512
513 if (job->id >= NextJobId)
514 NextJobId = job->id + 1;
515
516 /*
517 * Load the job control file...
518 */
519
520 snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name);
521 if (ipp_read_file(filename, job->attrs) != IPP_DATA)
522 {
523 LogMessage(L_ERROR, "LoadAllJobs: Unable to read job control file \"%s\"!",
524 filename);
525 ippDelete(job->attrs);
526 free(job);
527 unlink(filename);
528 continue;
529 }
530
531 if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) == NULL)
532 {
533 LogMessage(L_ERROR, "LoadAllJobs: No job-printer-uri attribute in control file \"%s\"!",
534 filename);
535 ippDelete(job->attrs);
536 free(job);
537 unlink(filename);
538 continue;
539 }
540
541 httpSeparate(attr->values[0].string.text, method, username, host,
542 &port, resource);
543
544 if ((dest = ValidateDest(host, resource, &(job->dtype))) == NULL)
545 {
546 /*
547 * Job queued on remote printer or class, so add it...
548 */
549
550 if (strncmp(resource, "/classes/", 9) == 0)
551 {
552 p = AddClass(resource + 9);
553 strcpy(p->make_model, "Remote Class on unknown");
554 }
555 else
556 {
557 p = AddPrinter(resource + 10);
558 strcpy(p->make_model, "Remote Printer on unknown");
559 }
560
561 p->state = IPP_PRINTER_STOPPED;
562 p->type |= CUPS_PRINTER_REMOTE;
563 p->browse_time = 2147483647;
564
565 strcpy(p->location, "Location Unknown");
566 strcpy(p->info, "No Information Available");
567 p->hostname[0] = '\0';
568
569 SetPrinterAttrs(p);
570 dest = p->name;
571 }
572
573 if (dest == NULL)
574 {
575 LogMessage(L_ERROR, "LoadAllJobs: Unable to queue job for destination \"%s\"!",
576 attr->values[0].string.text);
577 ippDelete(job->attrs);
578 free(job);
579 unlink(filename);
580 continue;
581 }
582
583 strncpy(job->dest, dest, sizeof(job->dest) - 1);
584
585 job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed",
586 IPP_TAG_INTEGER);
587 job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM);
588 job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME);
589
590 attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER);
591 job->priority = attr->values[0].integer;
592
593 attr = ippFindAttribute(job->attrs, "job-name", IPP_TAG_NAME);
594 strncpy(job->title, attr->values[0].string.text,
595 sizeof(job->title) - 1);
596
597 attr = ippFindAttribute(job->attrs, "job-originating-user-name", IPP_TAG_NAME);
598 strncpy(job->username, attr->values[0].string.text,
599 sizeof(job->username) - 1);
600
601 if (job->state->values[0].integer == IPP_JOB_HELD)
602 {
603 if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL)
604 attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME);
605
606 if (attr == NULL)
607 job->state->values[0].integer = IPP_JOB_PENDING;
608 else
609 SetJobHoldUntil(job->id, attr->values[0].string.text);
610 }
611 else if (job->state->values[0].integer == IPP_JOB_PROCESSING)
612 job->state->values[0].integer = IPP_JOB_PENDING;
613
614 /*
615 * Insert the job into the array, sorting by job priority and ID...
616 */
617
618 for (current = Jobs, prev = NULL;
619 current != NULL;
620 prev = current, current = current->next)
621 if (job->priority > current->priority)
622 break;
623 else if (job->priority == current->priority && job->id < current->id)
624 break;
625
626 job->next = current;
627 if (prev != NULL)
628 prev->next = job;
629 else
630 Jobs = job;
631
632 NumJobs ++;
633 }
634
635 /*
636 * Read all the d##### files...
637 */
638
639 rewinddir(dir);
640
641 while ((dent = readdir(dir)) != NULL)
642 if (NAMLEN(dent) > 7 && dent->d_name[0] == 'd')
643 {
644 /*
645 * Find the job...
646 */
647
648 jobid = atoi(dent->d_name + 1);
649 fileid = atoi(dent->d_name + 7);
650
651 snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->d_name);
652
653 if ((job = FindJob(jobid)) == NULL)
654 {
655 LogMessage(L_ERROR, "LoadAllJobs: Orphaned print file \"%s\"!",
656 filename);
657 unlink(filename);
658 continue;
659 }
660
661 if (fileid > job->num_files)
662 {
663 if (job->num_files == 0)
664 filetypes = (mime_type_t **)calloc(sizeof(mime_type_t *), fileid);
665 else
666 filetypes = (mime_type_t **)realloc(job->filetypes,
667 sizeof(mime_type_t *) * fileid);
668
669 if (filetypes == NULL)
670 {
671 LogMessage(L_ERROR, "LoadAllJobs: Ran out of memory for job file types!");
672 continue;
673 }
674
675 job->filetypes = filetypes;
676 job->num_files = fileid;
677 }
678
679 job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename);
680
681 if (job->filetypes[fileid - 1] == NULL)
682 job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application",
683 "vnd.cups-raw");
684 }
685
686 closedir(dir);
687
688 /*
689 * Clean out old jobs as needed...
690 */
691
692 CleanJobs();
693
694 /*
695 * Check to see if we need to start any jobs...
696 */
697
698 CheckJobs();
699 }
700
701
702 /*
703 * 'MoveJob()' - Move the specified job to a different destination.
704 */
705
706 void
707 MoveJob(int id, /* I - Job ID */
708 const char *dest) /* I - Destination */
709 {
710 job_t *current;/* Current job */
711 ipp_attribute_t *attr; /* job-printer-uri attribute */
712 printer_t *p; /* Destination printer or class */
713
714
715 if ((p = FindPrinter(dest)) == NULL)
716 p = FindClass(dest);
717
718 if (p == NULL)
719 return;
720
721 for (current = Jobs; current != NULL; current = current->next)
722 if (current->id == id)
723 {
724 if (current->state->values[0].integer >= IPP_JOB_PROCESSING)
725 break;
726
727 strncpy(current->dest, dest, sizeof(current->dest) - 1);
728
729 if ((attr = ippFindAttribute(current->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL)
730 {
731 free(attr->values[0].string.text);
732 attr->values[0].string.text = strdup(p->uri);
733 }
734
735 SaveJob(current->id);
736
737 return;
738 }
739 }
740
741
742 /*
743 * 'ReleaseJob()' - Release the specified job.
744 */
745
746 void
747 ReleaseJob(int id) /* I - Job ID */
748 {
749 job_t *job; /* Job data */
750
751
752 LogMessage(L_DEBUG, "ReleaseJob: id = %d", id);
753
754 if ((job = FindJob(id)) == NULL)
755 return;
756
757 if (job->state->values[0].integer == IPP_JOB_HELD)
758 {
759 DEBUG_puts("ReleaseJob: setting state to pending...");
760
761 job->state->values[0].integer = IPP_JOB_PENDING;
762 SaveJob(id);
763 CheckJobs();
764 }
765 }
766
767
768 /*
769 * 'RestartJob()' - Restart the specified job.
770 */
771
772 void
773 RestartJob(int id) /* I - Job ID */
774 {
775 job_t *job; /* Job data */
776
777
778 if ((job = FindJob(id)) == NULL)
779 return;
780
781 if (job->state->values[0].integer == IPP_JOB_STOPPED || JobFiles)
782 {
783 job->state->values[0].integer = IPP_JOB_PENDING;
784 SaveJob(id);
785 CheckJobs();
786 }
787 }
788
789
790 /*
791 * 'SaveJob()' - Save a job to disk.
792 */
793
794 void
795 SaveJob(int id) /* I - Job ID */
796 {
797 job_t *job; /* Pointer to job */
798 char filename[1024]; /* Job control filename */
799
800
801 if ((job = FindJob(id)) == NULL)
802 return;
803
804 snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, id);
805 ipp_write_file(filename, job->attrs);
806 }
807
808
809 /*
810 * 'SetJobHoldUntil()' - Set the hold time for a job...
811 */
812
813 void
814 SetJobHoldUntil(int id, /* I - Job ID */
815 const char *when) /* I - When to resume */
816 {
817 job_t *job; /* Pointer to job */
818 time_t curtime; /* Current time */
819 struct tm *curdate; /* Current date */
820 int hour; /* Hold hour */
821 int minute; /* Hold minute */
822 int second; /* Hold second */
823
824
825 LogMessage(L_DEBUG, "SetJobHoldUntil(%d, \"%s\")", id, when);
826
827 if ((job = FindJob(id)) == NULL)
828 return;
829
830 second = 0;
831
832 if (strcmp(when, "indefinite") == 0)
833 {
834 /*
835 * Hold indefinitely...
836 */
837
838 job->hold_until = 0;
839 }
840 else if (strcmp(when, "day-time") == 0)
841 {
842 /*
843 * Hold to 6am the next morning unless local time is < 6pm.
844 */
845
846 curtime = time(NULL);
847 curdate = localtime(&curtime);
848
849 if (curdate->tm_hour < 18)
850 job->hold_until = curtime;
851 else
852 job->hold_until = curtime +
853 ((29 - curdate->tm_hour) * 60 + 59 -
854 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
855 }
856 else if (strcmp(when, "evening") == 0 || strcmp(when, "night") == 0)
857 {
858 /*
859 * Hold to 6pm unless local time is > 6pm or < 6am.
860 */
861
862 curtime = time(NULL);
863 curdate = localtime(&curtime);
864
865 if (curdate->tm_hour < 6 || curdate->tm_hour >= 18)
866 job->hold_until = curtime;
867 else
868 job->hold_until = curtime +
869 ((17 - curdate->tm_hour) * 60 + 59 -
870 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
871 }
872 else if (strcmp(when, "second-shift") == 0)
873 {
874 /*
875 * Hold to 4pm unless local time is > 4pm.
876 */
877
878 curtime = time(NULL);
879 curdate = localtime(&curtime);
880
881 if (curdate->tm_hour >= 16)
882 job->hold_until = curtime;
883 else
884 job->hold_until = curtime +
885 ((15 - curdate->tm_hour) * 60 + 59 -
886 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
887 }
888 else if (strcmp(when, "third-shift") == 0)
889 {
890 /*
891 * Hold to 12am unless local time is < 8am.
892 */
893
894 curtime = time(NULL);
895 curdate = localtime(&curtime);
896
897 if (curdate->tm_hour < 8)
898 job->hold_until = curtime;
899 else
900 job->hold_until = curtime +
901 ((23 - curdate->tm_hour) * 60 + 59 -
902 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
903 }
904 else if (strcmp(when, "weekend") == 0)
905 {
906 /*
907 * Hold to weekend unless we are in the weekend.
908 */
909
910 curtime = time(NULL);
911 curdate = localtime(&curtime);
912
913 if (curdate->tm_wday == 0 || curdate->tm_wday == 6)
914 job->hold_until = curtime;
915 else
916 job->hold_until = curtime +
917 (((5 - curdate->tm_wday) * 24 +
918 (17 - curdate->tm_hour)) * 60 + 59 -
919 curdate->tm_min) * 60 + 60 - curdate->tm_sec;
920 }
921 else if (sscanf(when, "%d:%d:%d", &hour, &minute, &second) >= 2)
922 {
923 /*
924 * Hold to specified GMT time (HH:MM or HH:MM:SS)...
925 */
926
927 curtime = time(NULL);
928 curdate = gmtime(&curtime);
929
930 job->hold_until = curtime +
931 ((hour - curdate->tm_hour) * 60 + minute -
932 curdate->tm_min) * 60 + second - curdate->tm_sec;
933
934 /*
935 * Hold until next day as needed...
936 */
937
938 if (job->hold_until < curtime)
939 job->hold_until += 24 * 60 * 60 * 60;
940 }
941
942 LogMessage(L_DEBUG, "SetJobHoldUntil: hold_until = %d", job->hold_until);
943 }
944
945
946 /*
947 * 'SetJobPriority()' - Set the priority of a job, moving it up/down in the
948 * list as needed.
949 */
950
951 void
952 SetJobPriority(int id, /* I - Job ID */
953 int priority) /* I - New priority (0 to 100) */
954 {
955 job_t *job, /* Job to change */
956 *current, /* Current job */
957 *prev; /* Previous job */
958 ipp_attribute_t *attr; /* Job attribute */
959
960
961 /*
962 * Find the job...
963 */
964
965 for (current = Jobs, prev = NULL;
966 current != NULL;
967 prev = current, current = current->next)
968 if (current->id == id)
969 break;
970
971 if (current == NULL)
972 return;
973
974 /*
975 * Set the new priority...
976 */
977
978 job = current;
979 job->priority = priority;
980
981 if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) != NULL)
982 attr->values[0].integer = priority;
983 else
984 ippAddInteger(job->attrs, IPP_TAG_JOB, IPP_TAG_INTEGER, "job-priority",
985 priority);
986
987 SaveJob(job->id);
988
989 /*
990 * See if we need to do any sorting...
991 */
992
993 if ((prev == NULL || job->priority < prev->priority) &&
994 (job->next == NULL || job->next->priority < job->priority))
995 return;
996
997 /*
998 * Remove the job from the list, and then insert it where it belongs...
999 */
1000
1001 if (prev == NULL)
1002 Jobs = job->next;
1003 else
1004 prev->next = job->next;
1005
1006 for (current = Jobs, prev = NULL;
1007 current != NULL;
1008 prev = current, current = current->next)
1009 if (job->priority > current->priority)
1010 break;
1011
1012 job->next = current;
1013 if (prev != NULL)
1014 prev->next = job;
1015 else
1016 Jobs = job;
1017 }
1018
1019
1020 /*
1021 * 'StartJob()' - Start a print job.
1022 */
1023
1024 void
1025 StartJob(int id, /* I - Job ID */
1026 printer_t *printer) /* I - Printer to print job */
1027 {
1028 job_t *current; /* Current job */
1029 int i; /* Looping var */
1030 int slot; /* Pipe slot */
1031 int num_filters; /* Number of filters for job */
1032 mime_filter_t *filters; /* Filters for job */
1033 char method[255], /* Method for output */
1034 *optptr; /* Pointer to options */
1035 ipp_attribute_t *attr; /* Current attribute */
1036 int pid; /* Process ID of new filter process */
1037 int banner_page; /* 1 if banner page, 0 otherwise */
1038 int statusfds[2], /* Pipes used between the filters and scheduler */
1039 filterfds[2][2];/* Pipes used between the filters */
1040 char *argv[8], /* Filter command-line arguments */
1041 filename[1024], /* Job filename */
1042 command[1024], /* Full path to filter/backend command */
1043 jobid[255], /* Job ID string */
1044 title[IPP_MAX_NAME],
1045 /* Job title string */
1046 copies[255], /* # copies string */
1047 options[16384], /* Full list of options */
1048 *envp[20], /* Environment variables */
1049 path[1024], /* PATH environment variable */
1050 language[255], /* LANG environment variable */
1051 charset[255], /* CHARSET environment variable */
1052 classification[1024], /* CLASSIFICATION environmeent variable */
1053 content_type[255],/* CONTENT_TYPE environment variable */
1054 device_uri[1024],/* DEVICE_URI environment variable */
1055 ppd[1024], /* PPD environment variable */
1056 printer_name[255],/* PRINTER environment variable */
1057 root[1024], /* CUPS_SERVERROOT environment variable */
1058 cache[255], /* RIP_MAX_CACHE environment variable */
1059 tmpdir[1024], /* TMPDIR environment variable */
1060 ldpath[1024], /* LD_LIBRARY_PATH environment variable */
1061 datadir[1024], /* CUPS_DATADIR environment variable */
1062 fontpath[1050]; /* CUPS_FONTPATH environment variable */
1063
1064
1065 LogMessage(L_DEBUG, "StartJob(%d, %08x)", id, printer);
1066
1067 for (current = Jobs; current != NULL; current = current->next)
1068 if (current->id == id)
1069 break;
1070
1071 if (current == NULL)
1072 return;
1073
1074 LogMessage(L_DEBUG, "StartJob() id = %d, file = %d/%d", id,
1075 current->current_file, current->num_files);
1076
1077 if (current->num_files == 0)
1078 {
1079 LogMessage(L_ERROR, "Job ID %d has no files! Cancelling it!", id);
1080 CancelJob(id, 0);
1081 return;
1082 }
1083
1084 /*
1085 * Figure out what filters are required to convert from
1086 * the source to the destination type...
1087 */
1088
1089 num_filters = 0;
1090 current->cost = 0;
1091
1092 if (printer->type & CUPS_PRINTER_REMOTE)
1093 {
1094 /*
1095 * Remote jobs go directly to the remote job...
1096 */
1097
1098 filters = NULL;
1099 }
1100 else
1101 {
1102 /*
1103 * Local jobs get filtered...
1104 */
1105
1106 filters = mimeFilter(MimeDatabase, current->filetypes[current->current_file],
1107 printer->filetype, &num_filters);
1108
1109 if (num_filters == 0)
1110 {
1111 LogMessage(L_ERROR, "Unable to convert file %d to printable format for job %d!",
1112 current->current_file, current->id);
1113 current->current_file ++;
1114
1115 if (current->current_file == current->num_files)
1116 CancelJob(current->id, 0);
1117
1118 return;
1119 }
1120
1121 /*
1122 * Remove NULL ("-") filters...
1123 */
1124
1125 for (i = 0; i < num_filters;)
1126 if (strcmp(filters[i].filter, "-") == 0)
1127 {
1128 num_filters --;
1129 if (i < num_filters)
1130 memcpy(filters + i, filters + i + 1,
1131 (num_filters - i) * sizeof(mime_filter_t));
1132 }
1133 else
1134 i ++;
1135
1136 if (num_filters == 0)
1137 {
1138 free(filters);
1139 filters = NULL;
1140 }
1141 else
1142 {
1143 /*
1144 * Compute filter cost...
1145 */
1146
1147 for (i = 0; i < num_filters; i ++)
1148 current->cost += filters[i].cost;
1149 }
1150 }
1151
1152 /*
1153 * See if the filter cost is too high...
1154 */
1155
1156 if ((FilterLevel + current->cost) > FilterLimit && FilterLevel > 0 &&
1157 FilterLimit > 0)
1158 {
1159 /*
1160 * Don't print this job quite yet...
1161 */
1162
1163 if (filters != NULL)
1164 free(filters);
1165
1166 LogMessage(L_INFO, "Holding job %d because filter limit has been reached.",
1167 id);
1168 LogMessage(L_DEBUG, "StartJob: id = %d, file = %d, "
1169 "cost = %d, level = %d, limit = %d",
1170 id, current->current_file, current->cost, FilterLevel,
1171 FilterLimit);
1172 return;
1173 }
1174
1175 FilterLevel += current->cost;
1176
1177 /*
1178 * Update the printer and job state to "processing"...
1179 */
1180
1181 current->state->values[0].integer = IPP_JOB_PROCESSING;
1182 current->status = 0;
1183 current->printer = printer;
1184 printer->job = current;
1185 SetPrinterState(printer, IPP_PRINTER_PROCESSING);
1186
1187 if (current->current_file == 0)
1188 set_time(current, "time-at-processing");
1189
1190 /*
1191 * Determine if we are printing a banner page or not...
1192 */
1193
1194 if (current->job_sheets == NULL)
1195 LogMessage(L_DEBUG, "No job-sheets attribute.");
1196 else if (current->job_sheets->num_values == 1)
1197 LogMessage(L_DEBUG, "job-sheets=%s",
1198 current->job_sheets->values[0].string.text);
1199 else
1200 LogMessage(L_DEBUG, "job-sheets=%s,%s",
1201 current->job_sheets->values[0].string.text,
1202 current->job_sheets->values[1].string.text);
1203
1204 if (printer->type & CUPS_PRINTER_REMOTE)
1205 banner_page = 0;
1206 else if (current->job_sheets == NULL)
1207 banner_page = 0;
1208 else if (strcasecmp(current->job_sheets->values[0].string.text, "none") != 0 &&
1209 current->current_file == 0)
1210 banner_page = 1;
1211 else if (current->job_sheets->num_values > 1 &&
1212 strcasecmp(current->job_sheets->values[1].string.text, "none") != 0 &&
1213 current->current_file == (current->num_files - 1))
1214 banner_page = 1;
1215 else
1216 banner_page = 0;
1217
1218 LogMessage(L_DEBUG, "banner_page = %d", banner_page);
1219
1220 /*
1221 * Building the options string is harder than it needs to be, but
1222 * for the moment we need to pass strings for command-line args and
1223 * not IPP attribute pointers... :)
1224 */
1225
1226 optptr = options;
1227 *optptr = '\0';
1228
1229 snprintf(title, sizeof(title), "%s-%d", printer->name, current->id);
1230 strcpy(copies, "1");
1231
1232 for (attr = current->attrs->attrs; attr != NULL; attr = attr->next)
1233 {
1234 if (strcmp(attr->name, "copies") == 0 &&
1235 attr->value_tag == IPP_TAG_INTEGER)
1236 {
1237 /*
1238 * Don't use the # copies attribute if we are printing the job sheets...
1239 */
1240
1241 if (!banner_page)
1242 sprintf(copies, "%d", attr->values[0].integer);
1243 }
1244 else if (strcmp(attr->name, "job-name") == 0 &&
1245 (attr->value_tag == IPP_TAG_NAME ||
1246 attr->value_tag == IPP_TAG_NAMELANG))
1247 {
1248 strncpy(title, attr->values[0].string.text, sizeof(title) - 1);
1249 title[sizeof(title) - 1] = '\0';
1250 }
1251 else if (attr->group_tag == IPP_TAG_JOB)
1252 {
1253 /*
1254 * Filter out other unwanted attributes...
1255 */
1256
1257 if (attr->value_tag == IPP_TAG_MIMETYPE ||
1258 attr->value_tag == IPP_TAG_NAMELANG ||
1259 attr->value_tag == IPP_TAG_TEXTLANG ||
1260 attr->value_tag == IPP_TAG_URI ||
1261 attr->value_tag == IPP_TAG_URISCHEME)
1262 continue;
1263
1264 if (strncmp(attr->name, "time-", 5) == 0)
1265 continue;
1266
1267 if (strncmp(attr->name, "job-", 4) == 0 &&
1268 !(printer->type & CUPS_PRINTER_REMOTE))
1269 continue;
1270
1271 if (strncmp(attr->name, "job-", 4) == 0 &&
1272 strcmp(attr->name, "job-billing") != 0 &&
1273 strcmp(attr->name, "job-sheets") != 0 &&
1274 strcmp(attr->name, "job-hold-until") != 0 &&
1275 strcmp(attr->name, "job-priority") != 0)
1276 continue;
1277
1278 if (strcmp(attr->name, "page-label") == 0 &&
1279 banner_page)
1280 continue;
1281
1282 /*
1283 * Otherwise add them to the list...
1284 */
1285
1286 if (optptr > options)
1287 strncat(optptr, " ", sizeof(options) - (optptr - options) - 1);
1288
1289 if (attr->value_tag != IPP_TAG_BOOLEAN)
1290 {
1291 strncat(optptr, attr->name, sizeof(options) - (optptr - options) - 1);
1292 strncat(optptr, "=", sizeof(options) - (optptr - options) - 1);
1293 }
1294
1295 for (i = 0; i < attr->num_values; i ++)
1296 {
1297 if (i)
1298 strncat(optptr, ",", sizeof(options) - (optptr - options) - 1);
1299
1300 optptr += strlen(optptr);
1301
1302 switch (attr->value_tag)
1303 {
1304 case IPP_TAG_INTEGER :
1305 case IPP_TAG_ENUM :
1306 snprintf(optptr, sizeof(options) - (optptr - options) - 1,
1307 "%d", attr->values[i].integer);
1308 break;
1309
1310 case IPP_TAG_BOOLEAN :
1311 if (!attr->values[i].boolean)
1312 strncat(optptr, "no", sizeof(options) - (optptr - options) - 1);
1313
1314 case IPP_TAG_NOVALUE :
1315 strncat(optptr, attr->name,
1316 sizeof(options) - (optptr - options) - 1);
1317 break;
1318
1319 case IPP_TAG_RANGE :
1320 snprintf(optptr, sizeof(options) - (optptr - options) - 1,
1321 "%d-%d", attr->values[i].range.lower,
1322 attr->values[i].range.upper);
1323 break;
1324
1325 case IPP_TAG_RESOLUTION :
1326 snprintf(optptr, sizeof(options) - (optptr - options) - 1,
1327 "%dx%d%s", attr->values[i].resolution.xres,
1328 attr->values[i].resolution.yres,
1329 attr->values[i].resolution.units == IPP_RES_PER_INCH ?
1330 "dpi" : "dpc");
1331 break;
1332
1333 case IPP_TAG_STRING :
1334 case IPP_TAG_TEXT :
1335 case IPP_TAG_NAME :
1336 case IPP_TAG_KEYWORD :
1337 case IPP_TAG_CHARSET :
1338 case IPP_TAG_LANGUAGE :
1339 if (strchr(attr->values[i].string.text, ' ') != NULL ||
1340 strchr(attr->values[i].string.text, '\t') != NULL ||
1341 strchr(attr->values[i].string.text, '\n') != NULL)
1342 {
1343 strncat(optptr, "\'", sizeof(options) - (optptr - options) - 1);
1344 strncat(optptr, attr->values[i].string.text,
1345 sizeof(options) - (optptr - options) - 1);
1346 strncat(optptr, "\'", sizeof(options) - (optptr - options) - 1);
1347 }
1348 else
1349 strncat(optptr, attr->values[i].string.text,
1350 sizeof(options) - (optptr - options) - 1);
1351 break;
1352
1353 default :
1354 break; /* anti-compiler-warning-code */
1355 }
1356 }
1357
1358 optptr += strlen(optptr);
1359 }
1360 }
1361
1362 /*
1363 * Build the command-line arguments for the filters. Each filter
1364 * has 6 or 7 arguments:
1365 *
1366 * argv[0] = printer
1367 * argv[1] = job ID
1368 * argv[2] = username
1369 * argv[3] = title
1370 * argv[4] = # copies
1371 * argv[5] = options
1372 * argv[6] = filename (optional; normally stdin)
1373 *
1374 * This allows legacy printer drivers that use the old System V
1375 * printing interface to be used by CUPS.
1376 */
1377
1378 sprintf(jobid, "%d", current->id);
1379 snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot,
1380 current->id, current->current_file + 1);
1381
1382 argv[0] = printer->name;
1383 argv[1] = jobid;
1384 argv[2] = current->username;
1385 argv[3] = title;
1386 argv[4] = copies;
1387 argv[5] = options;
1388 argv[6] = filename;
1389 argv[7] = NULL;
1390
1391 LogMessage(L_DEBUG, "StartJob: argv = \"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
1392 argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
1393
1394 /*
1395 * Create environment variable strings for the filters...
1396 */
1397
1398 attr = ippFindAttribute(current->attrs, "attributes-natural-language",
1399 IPP_TAG_LANGUAGE);
1400 snprintf(language, sizeof(language), "LANG=%s", attr->values[0].string.text);
1401
1402 attr = ippFindAttribute(current->attrs, "document-format",
1403 IPP_TAG_MIMETYPE);
1404 if (attr != NULL &&
1405 (optptr = strstr(attr->values[0].string.text, "charset=")) != NULL)
1406 snprintf(charset, sizeof(charset), "CHARSET=%s", optptr + 8);
1407 else
1408 {
1409 attr = ippFindAttribute(current->attrs, "attributes-charset",
1410 IPP_TAG_CHARSET);
1411 snprintf(charset, sizeof(charset), "CHARSET=%s",
1412 attr->values[0].string.text);
1413 }
1414
1415 snprintf(path, sizeof(path), "PATH=%s/filter:/bin:/usr/bin", ServerBin);
1416 snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
1417 current->filetypes[current->current_file]->super,
1418 current->filetypes[current->current_file]->type);
1419 snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", printer->device_uri);
1420 snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot, printer->name);
1421 snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name);
1422 snprintf(cache, sizeof(cache), "RIP_MAX_CACHE=%s", RIPCache);
1423 snprintf(root, sizeof(root), "CUPS_SERVERROOT=%s", ServerRoot);
1424 snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
1425 snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir);
1426 snprintf(fontpath, sizeof(fontpath), "CUPS_FONTPATH=%s", FontPath);
1427 if (Classification[0] && !banner_page)
1428 {
1429 if ((attr = ippFindAttribute(current->attrs, "job-sheets",
1430 IPP_TAG_NAME)) == NULL)
1431 snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1432 Classification);
1433 else if (attr->num_values > 1 &&
1434 strcmp(attr->values[1].string.text, "none") != 0)
1435 snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1436 attr->values[1].string.text);
1437 else
1438 snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
1439 attr->values[0].string.text);
1440 }
1441 else
1442 classification[0] = '\0';
1443 if (getenv("LD_LIBRARY_PATH") != NULL)
1444 snprintf(ldpath, sizeof(ldpath), "LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
1445 else
1446 ldpath[0] = '\0';
1447
1448 envp[0] = path;
1449 envp[1] = "SOFTWARE=CUPS/1.1";
1450 envp[2] = "USER=root";
1451 envp[3] = charset;
1452 envp[4] = language;
1453 envp[5] = TZ;
1454 envp[6] = ppd;
1455 envp[7] = root;
1456 envp[8] = cache;
1457 envp[9] = tmpdir;
1458 envp[10] = content_type;
1459 envp[11] = device_uri;
1460 envp[12] = printer_name;
1461 envp[13] = datadir;
1462 envp[14] = fontpath;
1463 envp[15] = ldpath;
1464 envp[16] = classification;
1465 envp[17] = NULL;
1466
1467 LogMessage(L_DEBUG, "StartJob: envp = \"%s\",\"%s\",\"%s\",\"%s\","
1468 "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\","
1469 "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
1470 envp[0], envp[1], envp[2], envp[3], envp[4],
1471 envp[5], envp[6], envp[7], envp[8], envp[9],
1472 envp[10], envp[11], envp[12], envp[13], envp[14],
1473 envp[15], envp[16]);
1474
1475 current->current_file ++;
1476
1477 /*
1478 * Make sure we have a buffer to read status info into...
1479 */
1480
1481 if (current->buffer == NULL)
1482 {
1483 LogMessage(L_DEBUG2, "UpdateJob: Allocating status buffer...");
1484
1485 if ((current->buffer = malloc(JOB_BUFFER_SIZE)) == NULL)
1486 {
1487 LogMessage(L_EMERG, "Unable to allocate memory for job status buffer - %s",
1488 strerror(errno));
1489 CancelJob(current->id, 0);
1490 return;
1491 }
1492
1493 current->bufused = 0;
1494 }
1495
1496 /*
1497 * Now create processes for all of the filters...
1498 */
1499
1500 if (pipe(statusfds))
1501 {
1502 LogMessage(L_ERROR, "Unable to create job status pipes - %s.",
1503 strerror(errno));
1504 snprintf(printer->state_message, sizeof(printer->state_message),
1505 "Unable to create status pipes - %s.", strerror(errno));
1506 return;
1507 }
1508
1509 LogMessage(L_DEBUG, "StartJob: statusfds = %d, %d",
1510 statusfds[0], statusfds[1]);
1511
1512 current->pipe = statusfds[0];
1513 current->status = 0;
1514 memset(current->procs, 0, sizeof(current->procs));
1515
1516 filterfds[1][0] = open("/dev/null", O_RDONLY);
1517 filterfds[1][1] = -1;
1518
1519 LogMessage(L_DEBUG, "StartJob: filterfds[%d] = %d, %d", 1, filterfds[1][0],
1520 filterfds[1][1]);
1521
1522 for (i = 0, slot = 0; i < num_filters; i ++)
1523 {
1524 if (filters[i].filter[0] != '/')
1525 snprintf(command, sizeof(command), "%s/filter/%s", ServerBin,
1526 filters[i].filter);
1527 else
1528 {
1529 strncpy(command, filters[i].filter, sizeof(command) - 1);
1530 command[sizeof(command) - 1] = '\0';
1531 }
1532
1533 if (i < (num_filters - 1) ||
1534 strncmp(printer->device_uri, "file:", 5) != 0)
1535 pipe(filterfds[slot]);
1536 else
1537 {
1538 filterfds[slot][0] = -1;
1539 if (strncmp(printer->device_uri, "file:/dev/", 10) == 0)
1540 filterfds[slot][1] = open(printer->device_uri + 5,
1541 O_WRONLY | O_EXCL);
1542 else
1543 filterfds[slot][1] = open(printer->device_uri + 5,
1544 O_WRONLY | O_CREAT | O_TRUNC, 0600);
1545 }
1546
1547 LogMessage(L_DEBUG, "StartJob: filter = \"%s\"", command);
1548 LogMessage(L_DEBUG, "StartJob: filterfds[%d] = %d, %d",
1549 slot, filterfds[slot][0], filterfds[slot][1]);
1550
1551 pid = start_process(command, argv, envp, filterfds[!slot][0],
1552 filterfds[slot][1], statusfds[1], 0);
1553
1554 close(filterfds[!slot][0]);
1555 close(filterfds[!slot][1]);
1556
1557 if (pid == 0)
1558 {
1559 LogMessage(L_ERROR, "Unable to start filter \"%s\" - %s.",
1560 filters[i].filter, strerror(errno));
1561 snprintf(printer->state_message, sizeof(printer->state_message),
1562 "Unable to start filter \"%s\" - %s.",
1563 filters[i].filter, strerror(errno));
1564 return;
1565 }
1566
1567 current->procs[i] = pid;
1568
1569 LogMessage(L_INFO, "Started filter %s (PID %d) for job %d.",
1570 command, pid, current->id);
1571
1572 argv[6] = NULL;
1573 slot = !slot;
1574 }
1575
1576 if (filters != NULL)
1577 free(filters);
1578
1579 /*
1580 * Finally, pipe the final output into a backend process if needed...
1581 */
1582
1583 if (strncmp(printer->device_uri, "file:", 5) != 0)
1584 {
1585 sscanf(printer->device_uri, "%254[^:]", method);
1586 snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, method);
1587
1588 argv[0] = printer->device_uri;
1589
1590 filterfds[slot][0] = -1;
1591 filterfds[slot][1] = open("/dev/null", O_WRONLY);
1592
1593 LogMessage(L_DEBUG, "StartJob: backend = \"%s\"", command);
1594 LogMessage(L_DEBUG, "StartJob: filterfds[%d] = %d, %d",
1595 slot, filterfds[slot][0], filterfds[slot][1]);
1596
1597 pid = start_process(command, argv, envp, filterfds[!slot][0],
1598 filterfds[slot][1], statusfds[1], 1);
1599
1600 close(filterfds[!slot][0]);
1601 close(filterfds[!slot][1]);
1602
1603 if (pid == 0)
1604 {
1605 LogMessage(L_ERROR, "Unable to start backend \"%s\" - %s.",
1606 method, strerror(errno));
1607 snprintf(printer->state_message, sizeof(printer->state_message),
1608 "Unable to start backend \"%s\" - %s.", method, strerror(errno));
1609 return;
1610 }
1611 else
1612 {
1613 current->procs[i] = pid;
1614
1615 LogMessage(L_INFO, "Started backend %s (PID %d) for job %d.", command, pid,
1616 current->id);
1617 }
1618 }
1619 else
1620 {
1621 filterfds[slot][0] = -1;
1622 filterfds[slot][1] = -1;
1623
1624 close(filterfds[!slot][0]);
1625 close(filterfds[!slot][1]);
1626 }
1627
1628 close(filterfds[slot][0]);
1629 close(filterfds[slot][1]);
1630
1631 close(statusfds[1]);
1632
1633 LogMessage(L_DEBUG2, "StartJob: Adding fd %d to InputSet...", current->pipe);
1634
1635 FD_SET(current->pipe, &InputSet);
1636 }
1637
1638
1639 /*
1640 * 'StopAllJobs()' - Stop all print jobs.
1641 */
1642
1643 void
1644 StopAllJobs(void)
1645 {
1646 job_t *current; /* Current job */
1647
1648
1649 DEBUG_puts("StopAllJobs()");
1650
1651 for (current = Jobs; current != NULL; current = current->next)
1652 if (current->state->values[0].integer == IPP_JOB_PROCESSING)
1653 {
1654 StopJob(current->id);
1655 current->state->values[0].integer = IPP_JOB_PENDING;
1656 }
1657 }
1658
1659
1660 /*
1661 * 'StopJob()' - Stop a print job.
1662 */
1663
1664 void
1665 StopJob(int id) /* I - Job ID */
1666 {
1667 int i; /* Looping var */
1668 job_t *current; /* Current job */
1669
1670
1671 LogMessage(L_DEBUG, "StopJob: id = %d", id);
1672
1673 for (current = Jobs; current != NULL; current = current->next)
1674 if (current->id == id)
1675 {
1676 DEBUG_puts("StopJob: found job in list.");
1677
1678 if (current->state->values[0].integer == IPP_JOB_PROCESSING)
1679 {
1680 DEBUG_puts("StopJob: job state is \'processing\'.");
1681
1682 FilterLevel -= current->cost;
1683
1684 if (current->status < 0)
1685 SetPrinterState(current->printer, IPP_PRINTER_STOPPED);
1686 else if (current->printer->state != IPP_PRINTER_STOPPED)
1687 SetPrinterState(current->printer, IPP_PRINTER_IDLE);
1688
1689 LogMessage(L_DEBUG, "StopJob: printer state is %d", current->printer->state);
1690
1691 current->state->values[0].integer = IPP_JOB_STOPPED;
1692 current->printer->job = NULL;
1693 current->printer = NULL;
1694
1695 current->current_file --;
1696
1697 for (i = 0; current->procs[i]; i ++)
1698 if (current->procs[i] > 0)
1699 {
1700 kill(current->procs[i], SIGTERM);
1701 current->procs[i] = 0;
1702 }
1703
1704 if (current->pipe)
1705 {
1706 /*
1707 * Close the pipe and clear the input bit.
1708 */
1709
1710 LogMessage(L_DEBUG2, "StopJob: Removing fd %d from InputSet...",
1711 current->pipe);
1712
1713 close(current->pipe);
1714 FD_CLR(current->pipe, &InputSet);
1715 current->pipe = 0;
1716 }
1717
1718 if (current->buffer)
1719 {
1720 /*
1721 * Free the status buffer...
1722 */
1723
1724 LogMessage(L_DEBUG2, "StopJob: Freeing status buffer...");
1725
1726 free(current->buffer);
1727 current->buffer = NULL;
1728 current->bufused = 0;
1729 }
1730 }
1731 return;
1732 }
1733 }
1734
1735
1736 /*
1737 * 'UpdateJob()' - Read a status update from a job's filters.
1738 */
1739
1740 void
1741 UpdateJob(job_t *job) /* I - Job to check */
1742 {
1743 int bytes; /* Number of bytes read */
1744 int copies; /* Number of copies printed */
1745 char *lineptr, /* Pointer to end of line in buffer */
1746 *message; /* Pointer to message text */
1747 int loglevel; /* Log level for message */
1748
1749
1750 if ((bytes = read(job->pipe, job->buffer + job->bufused,
1751 JOB_BUFFER_SIZE - job->bufused - 1)) > 0)
1752 {
1753 job->bufused += bytes;
1754 job->buffer[job->bufused] = '\0';
1755 lineptr = strchr(job->buffer, '\n');
1756 }
1757 else if (bytes < 0 && errno == EINTR)
1758 return;
1759 else
1760 {
1761 lineptr = job->buffer + job->bufused;
1762 lineptr[1] = 0;
1763 }
1764
1765 while (lineptr != NULL)
1766 {
1767 /*
1768 * Terminate each line and process it...
1769 */
1770
1771 *lineptr++ = '\0';
1772
1773 /*
1774 * Figure out the logging level...
1775 */
1776
1777 if (strncmp(job->buffer, "EMERG:", 6) == 0)
1778 {
1779 loglevel = L_EMERG;
1780 message = job->buffer + 6;
1781 }
1782 else if (strncmp(job->buffer, "ALERT:", 6) == 0)
1783 {
1784 loglevel = L_ALERT;
1785 message = job->buffer + 6;
1786 }
1787 else if (strncmp(job->buffer, "CRIT:", 5) == 0)
1788 {
1789 loglevel = L_CRIT;
1790 message = job->buffer + 5;
1791 }
1792 else if (strncmp(job->buffer, "ERROR:", 6) == 0)
1793 {
1794 loglevel = L_ERROR;
1795 message = job->buffer + 6;
1796 }
1797 else if (strncmp(job->buffer, "WARNING:", 8) == 0)
1798 {
1799 loglevel = L_WARN;
1800 message = job->buffer + 8;
1801 }
1802 else if (strncmp(job->buffer, "NOTICE:", 6) == 0)
1803 {
1804 loglevel = L_NOTICE;
1805 message = job->buffer + 6;
1806 }
1807 else if (strncmp(job->buffer, "INFO:", 5) == 0)
1808 {
1809 loglevel = L_INFO;
1810 message = job->buffer + 5;
1811 }
1812 else if (strncmp(job->buffer, "DEBUG:", 6) == 0)
1813 {
1814 loglevel = L_DEBUG;
1815 message = job->buffer + 6;
1816 }
1817 else if (strncmp(job->buffer, "DEBUG2:", 7) == 0)
1818 {
1819 loglevel = L_DEBUG2;
1820 message = job->buffer + 7;
1821 }
1822 else if (strncmp(job->buffer, "PAGE:", 5) == 0)
1823 {
1824 loglevel = L_PAGE;
1825 message = job->buffer + 5;
1826 }
1827 else
1828 {
1829 loglevel = L_DEBUG;
1830 message = job->buffer;
1831 }
1832
1833 /*
1834 * Skip leading whitespace in the message...
1835 */
1836
1837 while (isspace(*message))
1838 message ++;
1839
1840 /*
1841 * Send it to the log file and printer state message as needed...
1842 */
1843
1844 if (loglevel == L_PAGE)
1845 {
1846 /*
1847 * Page message; send the message to the page_log file and update the
1848 * job sheet count...
1849 */
1850
1851 if (job->sheets != NULL)
1852 {
1853 if (!sscanf(message, "%*d%d", &copies))
1854 {
1855 job->sheets->values[0].integer ++;
1856
1857 if (job->printer->page_limit)
1858 UpdateQuota(job->printer, job->username, 1, 0);
1859 }
1860 else
1861 {
1862 job->sheets->values[0].integer += copies;
1863
1864 if (job->printer->page_limit)
1865 UpdateQuota(job->printer, job->username, copies, 0);
1866 }
1867 }
1868
1869 LogPage(job, message);
1870 }
1871 else
1872 {
1873 /*
1874 * Other status message; send it to the error_log file...
1875 */
1876
1877 if (loglevel != L_INFO)
1878 LogMessage(loglevel, "%s", message);
1879
1880 if ((loglevel == L_INFO && !job->status) ||
1881 loglevel < L_INFO)
1882 strncpy(job->printer->state_message, message,
1883 sizeof(job->printer->state_message) - 1);
1884 }
1885
1886 /*
1887 * Copy over the buffer data we've used up...
1888 */
1889
1890 strcpy(job->buffer, lineptr);
1891 job->bufused -= lineptr - job->buffer;
1892
1893 if (job->bufused < 0)
1894 job->bufused = 0;
1895
1896 lineptr = strchr(job->buffer, '\n');
1897 }
1898
1899 if (bytes <= 0)
1900 {
1901 LogMessage(L_DEBUG, "UpdateJob: job %d, file %d is complete.",
1902 job->id, job->current_file - 1);
1903
1904 if (job->pipe)
1905 {
1906 /*
1907 * Close the pipe and clear the input bit.
1908 */
1909
1910 LogMessage(L_DEBUG2, "UpdateJob: Removing fd %d from InputSet...",
1911 job->pipe);
1912
1913 close(job->pipe);
1914 FD_CLR(job->pipe, &InputSet);
1915 job->pipe = 0;
1916 }
1917
1918 if (job->status < 0)
1919 {
1920 /*
1921 * Backend had errors; stop it...
1922 */
1923
1924 StopJob(job->id);
1925 job->state->values[0].integer = IPP_JOB_PENDING;
1926 SaveJob(job->id);
1927 }
1928 else if (job->status > 0)
1929 {
1930 /*
1931 * Filter had errors; cancel it...
1932 */
1933
1934 if (job->current_file < job->num_files)
1935 StartJob(job->id, job->printer);
1936 else
1937 {
1938 CancelJob(job->id, 0);
1939
1940 if (JobHistory)
1941 {
1942 job->state->values[0].integer = IPP_JOB_ABORTED;
1943 SaveJob(job->id);
1944 }
1945
1946 CheckJobs();
1947 }
1948 }
1949 else
1950 {
1951 /*
1952 * Job printed successfully; cancel it...
1953 */
1954
1955 if (job->current_file < job->num_files)
1956 {
1957 FilterLevel -= job->cost;
1958 StartJob(job->id, job->printer);
1959 }
1960 else
1961 {
1962 CancelJob(job->id, 0);
1963
1964 if (JobHistory)
1965 {
1966 job->state->values[0].integer = IPP_JOB_COMPLETED;
1967 SaveJob(job->id);
1968 }
1969
1970 CheckJobs();
1971 }
1972 }
1973 }
1974 }
1975
1976
1977 /*
1978 * 'ipp_read_file()' - Read an IPP request from a file.
1979 */
1980
1981 static ipp_state_t /* O - State */
1982 ipp_read_file(const char *filename, /* I - File to read from */
1983 ipp_t *ipp) /* I - Request to read into */
1984 {
1985 int fd; /* File descriptor for file */
1986 int n; /* Length of data */
1987 unsigned char buffer[8192], /* Data buffer */
1988 *bufptr; /* Pointer into buffer */
1989 ipp_attribute_t *attr; /* Current attribute */
1990 ipp_tag_t tag; /* Current tag */
1991
1992
1993 /*
1994 * Open the file if possible...
1995 */
1996
1997 if (filename == NULL || ipp == NULL)
1998 return (IPP_ERROR);
1999
2000 if ((fd = open(filename, O_RDONLY)) == -1)
2001 return (IPP_ERROR);
2002
2003 /*
2004 * Read the IPP request...
2005 */
2006
2007 ipp->state = IPP_IDLE;
2008
2009 switch (ipp->state)
2010 {
2011 default :
2012 break; /* anti-compiler-warning-code */
2013
2014 case IPP_IDLE :
2015 ipp->state ++; /* Avoid common problem... */
2016
2017 case IPP_HEADER :
2018 /*
2019 * Get the request header...
2020 */
2021
2022 if ((n = read(fd, buffer, 8)) < 8)
2023 {
2024 DEBUG_printf(("ipp_read_file: Unable to read header (%d bytes read)!\n", n));
2025 close(fd);
2026 return (n == 0 ? IPP_IDLE : IPP_ERROR);
2027 }
2028
2029 /*
2030 * Verify the major version number...
2031 */
2032
2033 if (buffer[0] != 1)
2034 {
2035 DEBUG_printf(("ipp_read_file: version number (%d.%d) is bad.\n", buffer[0],
2036 buffer[1]));
2037 close(fd);
2038 return (IPP_ERROR);
2039 }
2040
2041 /*
2042 * Then copy the request header over...
2043 */
2044
2045 ipp->request.any.version[0] = buffer[0];
2046 ipp->request.any.version[1] = buffer[1];
2047 ipp->request.any.op_status = (buffer[2] << 8) | buffer[3];
2048 ipp->request.any.request_id = (((((buffer[4] << 8) | buffer[5]) << 8) |
2049 buffer[6]) << 8) | buffer[7];
2050
2051 ipp->state = IPP_ATTRIBUTE;
2052 ipp->current = NULL;
2053 ipp->curtag = IPP_TAG_ZERO;
2054
2055 case IPP_ATTRIBUTE :
2056 while (read(fd, buffer, 1) > 0)
2057 {
2058 /*
2059 * Read this attribute...
2060 */
2061
2062 tag = (ipp_tag_t)buffer[0];
2063
2064 if (tag == IPP_TAG_END)
2065 {
2066 /*
2067 * No more attributes left...
2068 */
2069
2070 DEBUG_puts("ipp_read_file: IPP_TAG_END!");
2071
2072 ipp->state = IPP_DATA;
2073 break;
2074 }
2075 else if (tag < IPP_TAG_UNSUPPORTED_VALUE)
2076 {
2077 /*
2078 * Group tag... Set the current group and continue...
2079 */
2080
2081 if (ipp->curtag == tag)
2082 ippAddSeparator(ipp);
2083
2084 ipp->curtag = tag;
2085 ipp->current = NULL;
2086 DEBUG_printf(("ipp_read_file: group tag = %x\n", tag));
2087 continue;
2088 }
2089
2090 DEBUG_printf(("ipp_read_file: value tag = %x\n", tag));
2091
2092 /*
2093 * Get the name...
2094 */
2095
2096 if (read(fd, buffer, 2) < 2)
2097 {
2098 DEBUG_puts("ipp_read_file: unable to read name length!");
2099 close(fd);
2100 return (IPP_ERROR);
2101 }
2102
2103 n = (buffer[0] << 8) | buffer[1];
2104
2105 DEBUG_printf(("ipp_read_file: name length = %d\n", n));
2106
2107 if (n == 0)
2108 {
2109 /*
2110 * More values for current attribute...
2111 */
2112
2113 if (ipp->current == NULL)
2114 {
2115 close(fd);
2116 return (IPP_ERROR);
2117 }
2118
2119 attr = ipp->current;
2120
2121 /*
2122 * Finally, reallocate the attribute array as needed...
2123 */
2124
2125 if ((attr->num_values % IPP_MAX_VALUES) == 0)
2126 {
2127 ipp_attribute_t *temp, /* Pointer to new buffer */
2128 *ptr; /* Pointer in attribute list */
2129
2130
2131 /*
2132 * Reallocate memory...
2133 */
2134
2135 if ((temp = realloc(attr, sizeof(ipp_attribute_t) +
2136 (attr->num_values + IPP_MAX_VALUES - 1) *
2137 sizeof(ipp_value_t))) == NULL)
2138 {
2139 close(fd);
2140 return (IPP_ERROR);
2141 }
2142
2143 /*
2144 * Reset pointers in the list...
2145 */
2146
2147 for (ptr = ipp->attrs; ptr && ptr->next != attr; ptr = ptr->next);
2148
2149 if (ptr)
2150 ptr->next = temp;
2151 else
2152 ipp->attrs = temp;
2153
2154 attr = ipp->current = ipp->last = temp;
2155 }
2156 }
2157 else
2158 {
2159 /*
2160 * New attribute; read the name and add it...
2161 */
2162
2163 if (read(fd, buffer, n) < n)
2164 {
2165 DEBUG_puts("ipp_read_file: unable to read name!");
2166 close(fd);
2167 return (IPP_ERROR);
2168 }
2169
2170 buffer[n] = '\0';
2171 DEBUG_printf(("ipp_read_file: name = \'%s\'\n", buffer));
2172
2173 attr = ipp->current = _ipp_add_attr(ipp, IPP_MAX_VALUES);
2174
2175 attr->group_tag = ipp->curtag;
2176 attr->value_tag = tag;
2177 attr->name = strdup((char *)buffer);
2178 attr->num_values = 0;
2179 }
2180
2181 if (read(fd, buffer, 2) < 2)
2182 {
2183 DEBUG_puts("ipp_read_file: unable to read value length!");
2184 close(fd);
2185 return (IPP_ERROR);
2186 }
2187
2188 n = (buffer[0] << 8) | buffer[1];
2189 DEBUG_printf(("ipp_read_file: value length = %d\n", n));
2190
2191 switch (tag)
2192 {
2193 case IPP_TAG_INTEGER :
2194 case IPP_TAG_ENUM :
2195 if (read(fd, buffer, 4) < 4)
2196 {
2197 close(fd);
2198 return (IPP_ERROR);
2199 }
2200
2201 n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
2202 buffer[3];
2203
2204 attr->values[attr->num_values].integer = n;
2205 break;
2206 case IPP_TAG_BOOLEAN :
2207 if (read(fd, buffer, 1) < 1)
2208 {
2209 close(fd);
2210 return (IPP_ERROR);
2211 }
2212
2213 attr->values[attr->num_values].boolean = buffer[0];
2214 break;
2215 case IPP_TAG_TEXT :
2216 case IPP_TAG_NAME :
2217 case IPP_TAG_KEYWORD :
2218 case IPP_TAG_STRING :
2219 case IPP_TAG_URI :
2220 case IPP_TAG_URISCHEME :
2221 case IPP_TAG_CHARSET :
2222 case IPP_TAG_LANGUAGE :
2223 case IPP_TAG_MIMETYPE :
2224 if (read(fd, buffer, n) < n)
2225 {
2226 close(fd);
2227 return (IPP_ERROR);
2228 }
2229
2230 buffer[n] = '\0';
2231 DEBUG_printf(("ipp_read_file: value = \'%s\'\n", buffer));
2232
2233 attr->values[attr->num_values].string.text = strdup((char *)buffer);
2234 break;
2235 case IPP_TAG_DATE :
2236 if (read(fd, buffer, 11) < 11)
2237 {
2238 close(fd);
2239 return (IPP_ERROR);
2240 }
2241
2242 memcpy(attr->values[attr->num_values].date, buffer, 11);
2243 break;
2244 case IPP_TAG_RESOLUTION :
2245 if (read(fd, buffer, 9) < 9)
2246 {
2247 close(fd);
2248 return (IPP_ERROR);
2249 }
2250
2251 attr->values[attr->num_values].resolution.xres =
2252 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
2253 buffer[3];
2254 attr->values[attr->num_values].resolution.yres =
2255 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
2256 buffer[7];
2257 attr->values[attr->num_values].resolution.units =
2258 (ipp_res_t)buffer[8];
2259 break;
2260 case IPP_TAG_RANGE :
2261 if (read(fd, buffer, 8) < 8)
2262 {
2263 close(fd);
2264 return (IPP_ERROR);
2265 }
2266
2267 attr->values[attr->num_values].range.lower =
2268 (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) |
2269 buffer[3];
2270 attr->values[attr->num_values].range.upper =
2271 (((((buffer[4] << 8) | buffer[5]) << 8) | buffer[6]) << 8) |
2272 buffer[7];
2273 break;
2274 case IPP_TAG_TEXTLANG :
2275 case IPP_TAG_NAMELANG :
2276 if (read(fd, buffer, n) < n)
2277 return (IPP_ERROR);
2278
2279 bufptr = buffer;
2280
2281 /*
2282 * text-with-language and name-with-language are composite
2283 * values:
2284 *
2285 * charset-length
2286 * charset
2287 * text-length
2288 * text
2289 */
2290
2291 n = (bufptr[0] << 8) | bufptr[1];
2292
2293 attr->values[attr->num_values].string.charset = calloc(n + 1, 1);
2294
2295 memcpy(attr->values[attr->num_values].string.charset,
2296 bufptr + 2, n);
2297
2298 bufptr += 2 + n;
2299 n = (bufptr[0] << 8) | bufptr[1];
2300
2301 attr->values[attr->num_values].string.text = calloc(n + 1, 1);
2302
2303 memcpy(attr->values[attr->num_values].string.text,
2304 bufptr + 2, n);
2305
2306 break;
2307
2308 default : /* Other unsupported values */
2309 attr->values[attr->num_values].unknown.length = n;
2310 if (n > 0)
2311 {
2312 attr->values[attr->num_values].unknown.data = malloc(n);
2313 if (read(fd, attr->values[attr->num_values].unknown.data, n) < n)
2314 return (IPP_ERROR);
2315 }
2316 else
2317 attr->values[attr->num_values].unknown.data = NULL;
2318 break;
2319 }
2320
2321 attr->num_values ++;
2322 }
2323 break;
2324
2325 case IPP_DATA :
2326 break;
2327 }
2328
2329 /*
2330 * Close the file and return...
2331 */
2332
2333 close(fd);
2334
2335 return (ipp->state);
2336 }
2337
2338
2339 /*
2340 * 'ipp_write_file()' - Write an IPP request to a file.
2341 */
2342
2343 static ipp_state_t /* O - State */
2344 ipp_write_file(const char *filename, /* I - File to write to */
2345 ipp_t *ipp) /* I - Request to write */
2346 {
2347 int fd; /* File descriptor */
2348 int i; /* Looping var */
2349 int n; /* Length of data */
2350 unsigned char buffer[8192], /* Data buffer */
2351 *bufptr; /* Pointer into buffer */
2352 ipp_attribute_t *attr; /* Current attribute */
2353
2354
2355 /*
2356 * Open the file if possible...
2357 */
2358
2359 if (filename == NULL || ipp == NULL)
2360 return (IPP_ERROR);
2361
2362 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) == -1)
2363 return (IPP_ERROR);
2364
2365 fchmod(fd, 0600);
2366 fchown(fd, User, Group);
2367
2368 /*
2369 * Write the IPP request...
2370 */
2371
2372 ipp->state = IPP_IDLE;
2373
2374 switch (ipp->state)
2375 {
2376 default :
2377 break; /* anti-compiler-warning-code */
2378
2379 case IPP_IDLE :
2380 ipp->state ++; /* Avoid common problem... */
2381
2382 case IPP_HEADER :
2383 /*
2384 * Send the request header...
2385 */
2386
2387 bufptr = buffer;
2388
2389 *bufptr++ = ipp->request.any.version[0];
2390 *bufptr++ = ipp->request.any.version[1];
2391 *bufptr++ = ipp->request.any.op_status >> 8;
2392 *bufptr++ = ipp->request.any.op_status;
2393 *bufptr++ = ipp->request.any.request_id >> 24;
2394 *bufptr++ = ipp->request.any.request_id >> 16;
2395 *bufptr++ = ipp->request.any.request_id >> 8;
2396 *bufptr++ = ipp->request.any.request_id;
2397
2398 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2399 {
2400 DEBUG_puts("ipp_write_file: Could not write IPP header...");
2401 close(fd);
2402 return (IPP_ERROR);
2403 }
2404
2405 ipp->state = IPP_ATTRIBUTE;
2406 ipp->current = ipp->attrs;
2407 ipp->curtag = IPP_TAG_ZERO;
2408
2409 case IPP_ATTRIBUTE :
2410 while (ipp->current != NULL)
2411 {
2412 /*
2413 * Write this attribute...
2414 */
2415
2416 bufptr = buffer;
2417 attr = ipp->current;
2418
2419 ipp->current = ipp->current->next;
2420
2421 if (ipp->curtag != attr->group_tag)
2422 {
2423 /*
2424 * Send a group operation tag...
2425 */
2426
2427 ipp->curtag = attr->group_tag;
2428
2429 if (attr->group_tag == IPP_TAG_ZERO)
2430 continue;
2431
2432 DEBUG_printf(("ipp_write_file: wrote group tag = %x\n", attr->group_tag));
2433 *bufptr++ = attr->group_tag;
2434 }
2435
2436 if ((n = strlen(attr->name)) > (sizeof(buffer) - 3))
2437 return (IPP_ERROR);
2438
2439 DEBUG_printf(("ipp_write_file: writing value tag = %x\n", attr->value_tag));
2440 DEBUG_printf(("ipp_write_file: writing name = %d, \'%s\'\n", n, attr->name));
2441
2442 *bufptr++ = attr->value_tag;
2443 *bufptr++ = n >> 8;
2444 *bufptr++ = n;
2445 memcpy(bufptr, attr->name, n);
2446 bufptr += n;
2447
2448 switch (attr->value_tag)
2449 {
2450 case IPP_TAG_INTEGER :
2451 case IPP_TAG_ENUM :
2452 for (i = 0; i < attr->num_values; i ++)
2453 {
2454 if ((sizeof(buffer) - (bufptr - buffer)) < 9)
2455 {
2456 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2457 {
2458 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2459 return (IPP_ERROR);
2460 }
2461
2462 bufptr = buffer;
2463 }
2464
2465 if (i)
2466 {
2467 /*
2468 * Arrays and sets are done by sending additional
2469 * values with a zero-length name...
2470 */
2471
2472 *bufptr++ = attr->value_tag;
2473 *bufptr++ = 0;
2474 *bufptr++ = 0;
2475 }
2476
2477 *bufptr++ = 0;
2478 *bufptr++ = 4;
2479 *bufptr++ = attr->values[i].integer >> 24;
2480 *bufptr++ = attr->values[i].integer >> 16;
2481 *bufptr++ = attr->values[i].integer >> 8;
2482 *bufptr++ = attr->values[i].integer;
2483 }
2484 break;
2485
2486 case IPP_TAG_BOOLEAN :
2487 for (i = 0; i < attr->num_values; i ++)
2488 {
2489 if ((sizeof(buffer) - (bufptr - buffer)) < 6)
2490 {
2491 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2492 {
2493 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2494 return (IPP_ERROR);
2495 }
2496
2497 bufptr = buffer;
2498 }
2499
2500 if (i)
2501 {
2502 /*
2503 * Arrays and sets are done by sending additional
2504 * values with a zero-length name...
2505 */
2506
2507 *bufptr++ = attr->value_tag;
2508 *bufptr++ = 0;
2509 *bufptr++ = 0;
2510 }
2511
2512 *bufptr++ = 0;
2513 *bufptr++ = 1;
2514 *bufptr++ = attr->values[i].boolean;
2515 }
2516 break;
2517
2518 case IPP_TAG_TEXT :
2519 case IPP_TAG_NAME :
2520 case IPP_TAG_KEYWORD :
2521 case IPP_TAG_STRING :
2522 case IPP_TAG_URI :
2523 case IPP_TAG_URISCHEME :
2524 case IPP_TAG_CHARSET :
2525 case IPP_TAG_LANGUAGE :
2526 case IPP_TAG_MIMETYPE :
2527 for (i = 0; i < attr->num_values; i ++)
2528 {
2529 if (i)
2530 {
2531 /*
2532 * Arrays and sets are done by sending additional
2533 * values with a zero-length name...
2534 */
2535
2536 DEBUG_printf(("ipp_write_file: writing value tag = %x\n",
2537 attr->value_tag));
2538 DEBUG_printf(("ipp_write_file: writing name = 0, \'\'\n"));
2539
2540 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
2541 {
2542 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2543 {
2544 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2545 return (IPP_ERROR);
2546 }
2547
2548 bufptr = buffer;
2549 }
2550
2551 *bufptr++ = attr->value_tag;
2552 *bufptr++ = 0;
2553 *bufptr++ = 0;
2554 }
2555
2556 n = strlen(attr->values[i].string.text);
2557
2558 if (n > sizeof(buffer))
2559 return (IPP_ERROR);
2560
2561 DEBUG_printf(("ipp_write_file: writing string = %d, \'%s\'\n", n,
2562 attr->values[i].string.text));
2563
2564 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
2565 {
2566 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2567 {
2568 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2569 close(fd);
2570 return (IPP_ERROR);
2571 }
2572
2573 bufptr = buffer;
2574 }
2575
2576 *bufptr++ = n >> 8;
2577 *bufptr++ = n;
2578 memcpy(bufptr, attr->values[i].string.text, n);
2579 bufptr += n;
2580 }
2581 break;
2582
2583 case IPP_TAG_DATE :
2584 for (i = 0; i < attr->num_values; i ++)
2585 {
2586 if ((sizeof(buffer) - (bufptr - buffer)) < 16)
2587 {
2588 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2589 {
2590 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2591 return (IPP_ERROR);
2592 }
2593
2594 bufptr = buffer;
2595 }
2596
2597 if (i)
2598 {
2599 /*
2600 * Arrays and sets are done by sending additional
2601 * values with a zero-length name...
2602 */
2603
2604 *bufptr++ = attr->value_tag;
2605 *bufptr++ = 0;
2606 *bufptr++ = 0;
2607 }
2608
2609 *bufptr++ = 0;
2610 *bufptr++ = 11;
2611 memcpy(bufptr, attr->values[i].date, 11);
2612 bufptr += 11;
2613 }
2614 break;
2615
2616 case IPP_TAG_RESOLUTION :
2617 for (i = 0; i < attr->num_values; i ++)
2618 {
2619 if ((sizeof(buffer) - (bufptr - buffer)) < 14)
2620 {
2621 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2622 {
2623 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2624 return (IPP_ERROR);
2625 }
2626
2627 bufptr = buffer;
2628 }
2629
2630 if (i)
2631 {
2632 /*
2633 * Arrays and sets are done by sending additional
2634 * values with a zero-length name...
2635 */
2636
2637 *bufptr++ = attr->value_tag;
2638 *bufptr++ = 0;
2639 *bufptr++ = 0;
2640 }
2641
2642 *bufptr++ = 0;
2643 *bufptr++ = 9;
2644 *bufptr++ = attr->values[i].resolution.xres >> 24;
2645 *bufptr++ = attr->values[i].resolution.xres >> 16;
2646 *bufptr++ = attr->values[i].resolution.xres >> 8;
2647 *bufptr++ = attr->values[i].resolution.xres;
2648 *bufptr++ = attr->values[i].resolution.yres >> 24;
2649 *bufptr++ = attr->values[i].resolution.yres >> 16;
2650 *bufptr++ = attr->values[i].resolution.yres >> 8;
2651 *bufptr++ = attr->values[i].resolution.yres;
2652 *bufptr++ = attr->values[i].resolution.units;
2653 }
2654 break;
2655
2656 case IPP_TAG_RANGE :
2657 for (i = 0; i < attr->num_values; i ++)
2658 {
2659 if ((sizeof(buffer) - (bufptr - buffer)) < 13)
2660 {
2661 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2662 {
2663 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2664 return (IPP_ERROR);
2665 }
2666
2667 bufptr = buffer;
2668 }
2669
2670 if (i)
2671 {
2672 /*
2673 * Arrays and sets are done by sending additional
2674 * values with a zero-length name...
2675 */
2676
2677 *bufptr++ = attr->value_tag;
2678 *bufptr++ = 0;
2679 *bufptr++ = 0;
2680 }
2681
2682 *bufptr++ = 0;
2683 *bufptr++ = 8;
2684 *bufptr++ = attr->values[i].range.lower >> 24;
2685 *bufptr++ = attr->values[i].range.lower >> 16;
2686 *bufptr++ = attr->values[i].range.lower >> 8;
2687 *bufptr++ = attr->values[i].range.lower;
2688 *bufptr++ = attr->values[i].range.upper >> 24;
2689 *bufptr++ = attr->values[i].range.upper >> 16;
2690 *bufptr++ = attr->values[i].range.upper >> 8;
2691 *bufptr++ = attr->values[i].range.upper;
2692 }
2693 break;
2694
2695 case IPP_TAG_TEXTLANG :
2696 case IPP_TAG_NAMELANG :
2697 for (i = 0; i < attr->num_values; i ++)
2698 {
2699 if (i)
2700 {
2701 /*
2702 * Arrays and sets are done by sending additional
2703 * values with a zero-length name...
2704 */
2705
2706 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
2707 {
2708 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2709 {
2710 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2711 return (IPP_ERROR);
2712 }
2713
2714 bufptr = buffer;
2715 }
2716
2717 *bufptr++ = attr->value_tag;
2718 *bufptr++ = 0;
2719 *bufptr++ = 0;
2720 }
2721
2722 n = strlen(attr->values[i].string.charset) +
2723 strlen(attr->values[i].string.text) +
2724 4;
2725
2726 if (n > sizeof(buffer))
2727 return (IPP_ERROR);
2728
2729 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
2730 {
2731 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2732 {
2733 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2734 return (IPP_ERROR);
2735 }
2736
2737 bufptr = buffer;
2738 }
2739
2740 /* Length of entire value */
2741 *bufptr++ = n >> 8;
2742 *bufptr++ = n;
2743
2744 /* Length of charset */
2745 n = strlen(attr->values[i].string.charset);
2746 *bufptr++ = n >> 8;
2747 *bufptr++ = n;
2748
2749 /* Charset */
2750 memcpy(bufptr, attr->values[i].string.charset, n);
2751 bufptr += n;
2752
2753 /* Length of text */
2754 n = strlen(attr->values[i].string.text);
2755 *bufptr++ = n >> 8;
2756 *bufptr++ = n;
2757
2758 /* Text */
2759 memcpy(bufptr, attr->values[i].string.text, n);
2760 bufptr += n;
2761 }
2762 break;
2763
2764 default :
2765 for (i = 0; i < attr->num_values; i ++)
2766 {
2767 if (i)
2768 {
2769 /*
2770 * Arrays and sets are done by sending additional
2771 * values with a zero-length name...
2772 */
2773
2774 if ((sizeof(buffer) - (bufptr - buffer)) < 3)
2775 {
2776 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2777 {
2778 DEBUG_puts("ippWrite: Could not write IPP attribute...");
2779 return (IPP_ERROR);
2780 }
2781
2782 bufptr = buffer;
2783 }
2784
2785 *bufptr++ = attr->value_tag;
2786 *bufptr++ = 0;
2787 *bufptr++ = 0;
2788 }
2789
2790 n = attr->values[i].unknown.length;
2791
2792 if (n > sizeof(buffer))
2793 return (IPP_ERROR);
2794
2795 if ((sizeof(buffer) - (bufptr - buffer)) < (n + 2))
2796 {
2797 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2798 {
2799 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2800 return (IPP_ERROR);
2801 }
2802
2803 bufptr = buffer;
2804 }
2805
2806 /* Length of unknown value */
2807 *bufptr++ = n >> 8;
2808 *bufptr++ = n;
2809
2810 /* Value */
2811 if (n > 0)
2812 {
2813 memcpy(bufptr, attr->values[i].unknown.data, n);
2814 bufptr += n;
2815 }
2816 }
2817 break;
2818 }
2819
2820 /*
2821 * Write the data out...
2822 */
2823
2824 if (write(fd, (char *)buffer, bufptr - buffer) < 0)
2825 {
2826 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2827 close(fd);
2828 return (IPP_ERROR);
2829 }
2830
2831 DEBUG_printf(("ipp_write_file: wrote %d bytes\n", bufptr - buffer));
2832 }
2833
2834 if (ipp->current == NULL)
2835 {
2836 /*
2837 * Done with all of the attributes; add the end-of-attributes tag...
2838 */
2839
2840 buffer[0] = IPP_TAG_END;
2841 if (write(fd, (char *)buffer, 1) < 0)
2842 {
2843 DEBUG_puts("ipp_write_file: Could not write IPP end-tag...");
2844 close(fd);
2845 return (IPP_ERROR);
2846 }
2847
2848 ipp->state = IPP_DATA;
2849 }
2850 break;
2851
2852 case IPP_DATA :
2853 break;
2854 }
2855
2856 /*
2857 * Close the file and return...
2858 */
2859
2860 close(fd);
2861
2862 return (ipp->state);
2863 }
2864
2865
2866 /*
2867 * 'set_time()' - Set one of the "time-at-xyz" attributes...
2868 */
2869
2870 static void
2871 set_time(job_t *job, /* I - Job to update */
2872 const char *name) /* I - Name of attribute */
2873 {
2874 ipp_attribute_t *attr; /* Time attribute */
2875
2876
2877 if ((attr = ippFindAttribute(job->attrs, name, IPP_TAG_ZERO)) != NULL)
2878 {
2879 attr->value_tag = IPP_TAG_INTEGER;
2880 attr->values[0].integer = time(NULL);
2881 }
2882 }
2883
2884
2885 /*
2886 * 'start_process()' - Start a background process.
2887 */
2888
2889 static int /* O - Process ID or 0 */
2890 start_process(const char *command, /* I - Full path to command */
2891 char *argv[], /* I - Command-line arguments */
2892 char *envp[], /* I - Environment */
2893 int infd, /* I - Standard input file descriptor */
2894 int outfd, /* I - Standard output file descriptor */
2895 int errfd, /* I - Standard error file descriptor */
2896 int root) /* I - Run as root? */
2897 {
2898 int fd; /* Looping var */
2899 int pid; /* Process ID */
2900
2901
2902 LogMessage(L_DEBUG, "start_process(\"%s\", %08x, %08x, %d, %d, %d)",
2903 command, argv, envp, infd, outfd, errfd);
2904
2905 if ((pid = fork()) == 0)
2906 {
2907 /*
2908 * Child process goes here...
2909 *
2910 * Update stdin/stdout/stderr as needed...
2911 */
2912
2913 close(0);
2914 dup(infd);
2915 close(1);
2916 dup(outfd);
2917 if (errfd > 2)
2918 {
2919 close(2);
2920 dup(errfd);
2921 }
2922
2923 /*
2924 * Close extra file descriptors...
2925 */
2926
2927 for (fd = 3; fd < MaxFDs; fd ++)
2928 close(fd);
2929
2930 /*
2931 * Change user to something "safe"...
2932 */
2933
2934 if (!root && getuid() == 0)
2935 {
2936 /*
2937 * Running as root, so change to non-priviledged user...
2938 */
2939
2940 if (setgid(Group))
2941 exit(errno);
2942
2943 if (setuid(User))
2944 exit(errno);
2945 }
2946
2947 /*
2948 * Reset group membership to just the main one we belong to.
2949 */
2950
2951 setgroups(0, NULL);
2952
2953 /*
2954 * Change umask to restrict permissions on created files...
2955 */
2956
2957 umask(077);
2958
2959 /*
2960 * Execute the command; if for some reason this doesn't work,
2961 * return the error code...
2962 */
2963
2964 execve(command, argv, envp);
2965
2966 perror(command);
2967
2968 exit(errno);
2969 }
2970 else if (pid < 0)
2971 {
2972 /*
2973 * Error - couldn't fork a new process!
2974 */
2975
2976 LogMessage(L_ERROR, "Unable to fork %s - %s.", command, strerror(errno));
2977
2978 return (0);
2979 }
2980
2981 return (pid);
2982 }
2983
2984
2985 /*
2986 * End of "$Id: job.c,v 1.139 2001/11/09 17:19:43 mike Exp $".
2987 */