2 * "$Id: job.c,v 1.57 2000/03/21 04:03:35 mike Exp $"
4 * Job management routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2000 by Easy Software Products, all rights reserved.
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
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
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 destination
31 * FindJob() - Find the specified job.
32 * HoldJob() - Hold the specified job.
33 * LoadAllJobs() - Load all jobs from disk.
34 * LoadJob() - Load a job from disk.
35 * MoveJob() - Move the specified job to a different destination.
36 * ReleaseJob() - Release the specified job.
37 * RestartJob() - Restart the specified job.
38 * SaveJob() - Save a job to disk.
39 * SetJobPriority() - Set the priority of a job, moving it up/down in the
41 * StartJob() - Start a print job.
42 * StopAllJobs() - Stop all print jobs.
43 * StopJob() - Stop a print job.
44 * UpdateJob() - Read a status update from a job's filters.
45 * ValidateDest() - Validate a printer/class destination.
46 * ipp_read_file() - Read an IPP request from a file.
47 * ipp_write_file() - Write an IPP request to a file.
48 * start_process() - Start a background process.
52 * Include necessary headers...
62 static ipp_state_t
ipp_read_file(const char *filename
, ipp_t
*ipp
);
63 static ipp_state_t
ipp_write_file(const char *filename
, ipp_t
*ipp
);
64 static void set_time(job_t
*job
, const char *name
);
65 static int start_process(const char *command
, char *argv
[],
66 char *envp
[], int in
, int out
, int err
,
71 * 'AddJob()' - Add a new job to the job queue...
74 job_t
* /* O - New job record */
75 AddJob(int priority
, /* I - Job priority */
76 const char *dest
) /* I - Job destination */
78 job_t
*job
, /* New job record */
79 *current
, /* Current job in queue */
80 *prev
; /* Previous job in queue */
83 job
= calloc(sizeof(job_t
), 1);
85 job
->id
= NextJobId
++;
86 job
->priority
= priority
;
87 strncpy(job
->dest
, dest
, sizeof(job
->dest
) - 1);
91 for (current
= Jobs
, prev
= NULL
;
93 prev
= current
, current
= current
->next
)
94 if (job
->priority
> current
->priority
)
108 * 'CancelJob()' - Cancel the specified print job.
112 CancelJob(int id
) /* I - Job to cancel */
114 int i
; /* Looping var */
115 job_t
*current
, /* Current job */
116 *prev
; /* Previous job in list */
117 char filename
[1024]; /* Job filename */
120 DEBUG_printf(("CancelJob(%d)\n", id
));
122 for (current
= Jobs
, prev
= NULL
; current
!= NULL
; prev
= current
, current
= current
->next
)
123 if (current
->id
== id
)
126 * Stop any processes that are working on the current...
129 DEBUG_puts("CancelJob: found job in list.");
131 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
132 StopJob(current
->id
);
134 current
->state
->values
[0].integer
= IPP_JOB_CANCELLED
;
136 set_time(current
, "job-at-completion");
139 * Remove the print file for good if we aren't preserving jobs or
143 current
->current_file
= 0;
145 if (!JobHistory
|| !JobFiles
)
146 for (i
= 1; i
<= current
->num_files
; i
++)
148 snprintf(filename
, sizeof(filename
), "%s/d%05d-%03d", RequestRoot
,
156 * Save job state info...
159 SaveJob(current
->id
);
164 * Remove the job info file...
167 snprintf(filename
, sizeof(filename
), "%s/c%05d", RequestRoot
,
172 * Update pointers if we aren't preserving jobs...
176 Jobs
= current
->next
;
178 prev
->next
= current
->next
;
181 * Free all memory used...
184 if (current
->attrs
!= NULL
)
185 ippDelete(current
->attrs
);
187 free(current
->filetypes
);
198 * 'CancelJobs()' - Cancel all jobs on the given printer or class.
202 CancelJobs(const char *dest
) /* I - Destination to cancel */
204 job_t
*current
, /* Current job */
205 *prev
; /* Previous job in list */
208 for (current
= Jobs
, prev
= NULL
; current
!= NULL
; prev
= current
)
209 if (strcmp(current
->dest
, dest
) == 0)
212 * Cancel all jobs matching this destination...
215 CancelJob(current
->id
);
220 current
= prev
->next
;
223 current
= current
->next
;
230 * 'CheckJobs()' - Check the pending jobs and start any if the destination
237 job_t
*current
, /* Current job in queue */
238 *prev
; /* Previous job in queue */
239 printer_t
*printer
, /* Printer destination */
240 *pclass
; /* Printer class destination */
243 DEBUG_puts("CheckJobs()");
245 for (current
= Jobs
, prev
= NULL
; current
!= NULL
; prev
= current
)
247 DEBUG_printf(("CheckJobs: current->state->values[0].integer = %d\n",
248 current
->state
->values
[0].integer
));
251 * Start pending jobs if the destination is available...
254 if (current
->state
->values
[0].integer
== IPP_JOB_PENDING
)
256 DEBUG_printf(("CheckJobs: current->dest = \'%s\'\n", current
->dest
));
258 if ((pclass
= FindClass(current
->dest
)) != NULL
)
259 printer
= FindAvailablePrinter(current
->dest
);
261 printer
= FindPrinter(current
->dest
);
263 if (printer
!= NULL
&& (printer
->type
& CUPS_PRINTER_IMPLICIT
))
266 * Handle implicit classes...
270 printer
= FindAvailablePrinter(current
->dest
);
273 if (printer
== NULL
&& pclass
== NULL
)
276 * Whoa, the printer and/or class for this destination went away;
280 LogMessage(L_WARN
, "Printer/class %s has gone away; cancelling job %d!",
281 current
->dest
, current
->id
);
282 CancelJob(current
->id
);
287 current
= prev
->next
;
289 else if (printer
!= NULL
)
292 * See if the printer is available; if so, start the job...
295 DEBUG_printf(("CheckJobs: printer->state = %d\n", printer
->state
));
297 if (printer
->state
== IPP_PRINTER_IDLE
)
298 StartJob(current
->id
, printer
);
300 current
= current
->next
;
303 current
= current
->next
;
306 current
= current
->next
;
312 * 'FindJob()' - Find the specified job.
315 job_t
* /* O - Job data */
316 FindJob(int id
) /* I - Job ID */
318 job_t
*current
; /* Current job */
321 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
322 if (current
->id
== id
)
330 * 'HoldJob()' - Hold the specified job.
334 HoldJob(int id
) /* I - Job ID */
336 job_t
*job
; /* Job data */
339 if ((job
= FindJob(id
)) == NULL
)
342 if (job
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
345 job
->state
->values
[0].integer
= IPP_JOB_HELD
;
354 * 'LoadAllJobs()' - Load all jobs from disk.
360 DIR *dir
; /* Directory */
361 DIRENT
*dent
; /* Directory entry */
362 char filename
[1024]; /* Full filename of job file */
363 job_t
*job
, /* New job */
364 *current
, /* Current job */
365 *prev
; /* Previous job */
366 int jobid
, /* Current job ID */
367 fileid
; /* Current file ID */
368 ipp_attribute_t
*attr
; /* Job attribute */
369 char method
[HTTP_MAX_URI
],
370 /* Method portion of URI */
371 username
[HTTP_MAX_URI
],
372 /* Username portion of URI */
374 /* Host portion of URI */
375 resource
[HTTP_MAX_URI
];
376 /* Resource portion of URI */
377 int port
; /* Port portion of URI */
378 const char *dest
; /* Destination */
379 mime_type_t
**filetypes
; /* New filetypes array */
383 * First open the requests directory...
386 if ((dir
= opendir(RequestRoot
)) == NULL
)
390 * Read all the c##### files...
393 while ((dent
= readdir(dir
)) != NULL
)
394 if (NAMLEN(dent
) == 6 && dent
->d_name
[0] == 'c')
397 * Allocate memory for the job...
400 if ((job
= calloc(sizeof(job_t
), 1)) == NULL
)
402 LogMessage(L_ERROR
, "LoadAddJobs: Ran out of memory for jobs!");
407 if ((job
->attrs
= ippNew()) == NULL
)
410 LogMessage(L_ERROR
, "LoadAddJobs: Ran out of memory for job attributes!");
416 * Assign the job ID...
419 job
->id
= atoi(dent
->d_name
+ 1);
421 if (job
->id
>= NextJobId
)
422 NextJobId
= job
->id
+ 1;
425 * Load the job control file...
428 snprintf(filename
, sizeof(filename
), "%s/%s", RequestRoot
, dent
->d_name
);
429 if (ipp_read_file(filename
, job
->attrs
) != IPP_DATA
)
431 LogMessage(L_ERROR
, "LoadAllJobs: Unable to read job control file \"%s\"!",
433 ippDelete(job
->attrs
);
438 attr
= ippFindAttribute(job
->attrs
, "job-printer-uri", IPP_TAG_URI
);
439 httpSeparate(attr
->values
[0].string
.text
, method
, username
, host
,
442 if ((dest
= ValidateDest(resource
, &(job
->dtype
))) == NULL
)
444 LogMessage(L_ERROR
, "LoadAllJobs: Unable to queue job for destination \"%s\"!",
445 attr
->values
[0].string
.text
);
446 ippDelete(job
->attrs
);
451 strncpy(job
->dest
, dest
, sizeof(job
->dest
) - 1);
453 job
->state
= ippFindAttribute(job
->attrs
, "job-state", IPP_TAG_ENUM
);
455 attr
= ippFindAttribute(job
->attrs
, "job-priority", IPP_TAG_INTEGER
);
456 job
->priority
= attr
->values
[0].integer
;
458 attr
= ippFindAttribute(job
->attrs
, "job-name", IPP_TAG_NAME
);
459 strncpy(job
->title
, attr
->values
[0].string
.text
,
460 sizeof(job
->title
) - 1);
462 attr
= ippFindAttribute(job
->attrs
, "job-originating-user-name", IPP_TAG_NAME
);
463 strncpy(job
->username
, attr
->values
[0].string
.text
,
464 sizeof(job
->username
) - 1);
467 * Insert the job into the array, sorting by job priority and ID...
470 for (current
= Jobs
, prev
= NULL
;
472 prev
= current
, current
= current
->next
)
473 if (job
->priority
> current
->priority
)
475 else if (job
->priority
== current
->priority
&& job
->id
< current
->id
)
486 * Read all the d##### files...
491 while ((dent
= readdir(dir
)) != NULL
)
492 if (NAMLEN(dent
) > 7 && dent
->d_name
[0] == 'd')
498 jobid
= atoi(dent
->d_name
+ 1);
499 fileid
= atoi(dent
->d_name
+ 7);
501 snprintf(filename
, sizeof(filename
), "%s/%s", RequestRoot
, dent
->d_name
);
503 if ((job
= FindJob(jobid
)) == NULL
)
505 LogMessage(L_ERROR
, "LoadAddJobs: Orphaned print file \"%s\"!",
510 if (fileid
> job
->num_files
)
512 if (job
->num_files
== 0)
513 filetypes
= (mime_type_t
**)calloc(sizeof(mime_type_t
*), fileid
);
515 filetypes
= (mime_type_t
**)realloc(job
->filetypes
,
516 sizeof(mime_type_t
*) * fileid
);
518 if (filetypes
== NULL
)
520 LogMessage(L_ERROR
, "LoadAddJobs: Ran out of memory for job file types!");
524 job
->filetypes
= filetypes
;
525 job
->num_files
= fileid
;
528 job
->filetypes
[fileid
- 1] = mimeFileType(MimeDatabase
, filename
);
532 * Check to see if we need to start any jobs...
540 * 'MoveJob()' - Move the specified job to a different destination.
544 MoveJob(int id
, /* I - Job ID */
545 const char *dest
) /* I - Destination */
547 job_t
*current
; /* Current job */
550 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
551 if (current
->id
== id
)
553 if (current
->state
->values
[0].integer
== IPP_JOB_PENDING
)
554 strncpy(current
->dest
, dest
, sizeof(current
->dest
) - 1);
556 SaveJob(current
->id
);
564 * 'ReleaseJob()' - Release the specified job.
568 ReleaseJob(int id
) /* I - Job ID */
570 job_t
*job
; /* Job data */
573 if ((job
= FindJob(id
)) == NULL
)
576 if (job
->state
->values
[0].integer
== IPP_JOB_HELD
)
578 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
586 * 'RestartJob()' - Restart the specified job.
590 RestartJob(int id
) /* I - Job ID */
592 job_t
*job
; /* Job data */
595 if ((job
= FindJob(id
)) == NULL
)
598 if (job
->state
->values
[0].integer
> IPP_JOB_PROCESSING
&& JobFiles
)
600 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
608 * 'SaveJob()' - Save a job to disk.
612 SaveJob(int id
) /* I - Job ID */
614 job_t
*job
; /* Pointer to job */
615 char filename
[1024]; /* Job control filename */
618 if ((job
= FindJob(id
)) == NULL
)
621 snprintf(filename
, sizeof(filename
), "%s/c%05d", RequestRoot
, id
);
622 ipp_write_file(filename
, job
->attrs
);
627 * 'SetJobPriority()' - Set the priority of a job, moving it up/down in the
632 SetJobPriority(int id
, /* I - Job ID */
633 int priority
) /* I - New priority (0 to 100) */
635 job_t
*job
, /* Job to change */
636 *current
, /* Current job */
637 *prev
; /* Previous job */
638 ipp_attribute_t
*attr
; /* Job attribute */
645 for (current
= Jobs
, prev
= NULL
;
647 prev
= current
, current
= current
->next
)
648 if (current
->id
== id
)
655 * Set the new priority...
659 job
->priority
= priority
;
661 if ((attr
= ippFindAttribute(job
->attrs
, "job-priority", IPP_TAG_INTEGER
)) != NULL
)
662 attr
->values
[0].integer
= priority
;
664 ippAddInteger(job
->attrs
, IPP_TAG_JOB
, IPP_TAG_INTEGER
, "job-priority",
670 * See if we need to do any sorting...
673 if ((prev
== NULL
|| job
->priority
< prev
->priority
) &&
674 (job
->next
== NULL
|| job
->next
->priority
< job
->priority
))
678 * Remove the job from the list, and then insert it where it belongs...
684 prev
->next
= job
->next
;
686 for (current
= Jobs
, prev
= NULL
;
688 prev
= current
, current
= current
->next
)
689 if (job
->priority
> current
->priority
)
701 * 'StartJob()' - Start a print job.
705 StartJob(int id
, /* I - Job ID */
706 printer_t
*printer
) /* I - Printer to print job */
708 job_t
*current
; /* Current job */
709 int i
; /* Looping var */
710 int num_filters
; /* Number of filters for job */
711 mime_filter_t
*filters
; /* Filters for job */
712 char method
[255], /* Method for output */
713 *optptr
; /* Pointer to options */
714 ipp_attribute_t
*attr
; /* Current attribute */
715 int pid
; /* Process ID of new filter process */
716 int statusfds
[2], /* Pipes used between the filters and scheduler */
717 filterfds
[2][2];/* Pipes used between the filters */
718 char *argv
[8], /* Filter command-line arguments */
719 filename
[1024], /* Job filename */
720 command
[1024], /* Full path to filter/backend command */
721 jobid
[255], /* Job ID string */
723 /* Job title string */
724 copies
[255], /* # copies string */
725 options
[16384], /* Full list of options */
726 *envp
[15], /* Environment variables */
727 language
[255], /* LANG environment variable */
728 charset
[255], /* CHARSET environment variable */
729 content_type
[255],/* CONTENT_TYPE environment variable */
730 device_uri
[1024],/* DEVICE_URI environment variable */
731 ppd
[1024], /* PPD environment variable */
732 printer_name
[255],/* PRINTER environment variable */
733 root
[1024], /* SERVER_ROOT environment variable */
734 cache
[255], /* RIP_MAX_CACHE environment variable */
735 tmpdir
[1024]; /* TMPDIR environment variable */
738 DEBUG_printf(("StartJob(%d, %08x)\n", id
, printer
));
741 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
742 if (current
->id
== id
)
749 * Update the printer and job state to "processing"...
752 DEBUG_puts("StartJob: found job in list.");
754 current
->state
->values
[0].integer
= IPP_JOB_PROCESSING
;
756 current
->printer
= printer
;
757 printer
->job
= current
;
758 SetPrinterState(printer
, IPP_PRINTER_PROCESSING
);
760 set_time(current
, "job-at-processing");
763 * Figure out what filters are required to convert from
764 * the source to the destination type...
770 printf("Filtering from %s/%s to %s/%s...\n",
771 current
->filetype
->super
, current
->filetype
->type
,
772 printer
->filetype
->super
, printer
->filetype
->type
);
773 printf("num_filters = %d\n", MimeDatabase
->num_filters
);
774 for (i
= 0; i
< MimeDatabase
->num_filters
; i
++)
775 printf("filters[%d] = %s/%s to %s/%s using \"%s\" (cost %d)\n",
776 i
, MimeDatabase
->filters
[i
].src
->super
,
777 MimeDatabase
->filters
[i
].src
->type
,
778 MimeDatabase
->filters
[i
].dst
->super
,
779 MimeDatabase
->filters
[i
].dst
->type
,
780 MimeDatabase
->filters
[i
].filter
,
781 MimeDatabase
->filters
[i
].cost
);
784 if (printer
->type
& CUPS_PRINTER_REMOTE
)
787 * Remote jobs go directly to the remote job...
795 * Local jobs get filtered...
798 filters
= mimeFilter(MimeDatabase
, current
->filetypes
[current
->current_file
],
799 printer
->filetype
, &num_filters
);
801 if (num_filters
== 0)
803 LogMessage(L_ERROR
, "Unable to convert file to printable format for job %s-%d!",
804 printer
->name
, current
->id
);
805 CancelJob(current
->id
);
811 * Building the options string is harder than it needs to be, but
812 * for the moment we need to pass strings for command-line args and
813 * not IPP attribute pointers... :)
819 sprintf(title
, "%s-%d", printer
->name
, current
->id
);
822 for (attr
= current
->attrs
->attrs
; attr
!= NULL
; attr
= attr
->next
)
824 if (strcmp(attr
->name
, "copies") == 0 &&
825 attr
->value_tag
== IPP_TAG_INTEGER
)
826 sprintf(copies
, "%d", attr
->values
[0].integer
);
827 else if (strcmp(attr
->name
, "job-name") == 0 &&
828 (attr
->value_tag
== IPP_TAG_NAME
||
829 attr
->value_tag
== IPP_TAG_NAMELANG
))
830 strcpy(title
, attr
->values
[0].string
.text
);
831 else if (attr
->group_tag
== IPP_TAG_JOB
&&
832 (optptr
- options
) < (sizeof(options
) - 128))
834 if (attr
->value_tag
== IPP_TAG_MIMETYPE
||
835 attr
->value_tag
== IPP_TAG_NAMELANG
||
836 attr
->value_tag
== IPP_TAG_TEXTLANG
||
837 attr
->value_tag
== IPP_TAG_URI
||
838 attr
->value_tag
== IPP_TAG_URISCHEME
)
841 if (optptr
> options
)
844 if (attr
->value_tag
!= IPP_TAG_BOOLEAN
)
846 strcat(optptr
, attr
->name
);
850 for (i
= 0; i
< attr
->num_values
; i
++)
855 optptr
+= strlen(optptr
);
857 switch (attr
->value_tag
)
859 case IPP_TAG_INTEGER
:
861 sprintf(optptr
, "%d", attr
->values
[i
].integer
);
864 case IPP_TAG_BOOLEAN
:
865 if (!attr
->values
[i
].boolean
)
866 strcat(optptr
, "no");
868 case IPP_TAG_NOVALUE
:
869 strcat(optptr
, attr
->name
);
873 sprintf(optptr
, "%d-%d", attr
->values
[i
].range
.lower
,
874 attr
->values
[i
].range
.upper
);
877 case IPP_TAG_RESOLUTION
:
878 sprintf(optptr
, "%dx%d%s", attr
->values
[i
].resolution
.xres
,
879 attr
->values
[i
].resolution
.yres
,
880 attr
->values
[i
].resolution
.units
== IPP_RES_PER_INCH
?
884 case IPP_TAG_STRING
:
887 case IPP_TAG_KEYWORD
:
888 case IPP_TAG_CHARSET
:
889 case IPP_TAG_LANGUAGE
:
890 if (strchr(attr
->values
[i
].string
.text
, ' ') != NULL
||
891 strchr(attr
->values
[i
].string
.text
, '\t') != NULL
||
892 strchr(attr
->values
[i
].string
.text
, '\n') != NULL
)
894 strcat(optptr
, "\'");
895 strcat(optptr
, attr
->values
[i
].string
.text
);
896 strcat(optptr
, "\'");
899 strcat(optptr
, attr
->values
[i
].string
.text
);
903 break; /* anti-compiler-warning-code */
907 optptr
+= strlen(optptr
);
912 * Build the command-line arguments for the filters. Each filter
913 * has 6 or 7 arguments:
921 * argv[6] = filename (optional; normally stdin)
923 * This allows legacy printer drivers that use the old System V
924 * printing interface to be used by CUPS.
927 sprintf(jobid
, "%d", current
->id
);
928 sprintf(filename
, "%s/d%05d-%03d", RequestRoot
, current
->id
,
929 current
->current_file
+ 1);
931 argv
[0] = printer
->name
;
933 argv
[2] = current
->username
;
940 DEBUG_printf(("StartJob: args = \'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\',\'%s\'\n",
941 argv
[0], argv
[1], argv
[2], argv
[3], argv
[4], argv
[5], argv
[6]));
944 * Create environment variable strings for the filters...
947 attr
= ippFindAttribute(current
->attrs
, "attributes-natural-language",
949 sprintf(language
, "LANG=%s", attr
->values
[0].string
.text
);
951 attr
= ippFindAttribute(current
->attrs
, "document-format",
953 if ((optptr
= strstr(attr
->values
[0].string
.text
, "charset=")) != NULL
)
954 sprintf(charset
, "CHARSET=%s", optptr
+ 8);
957 attr
= ippFindAttribute(current
->attrs
, "attributes-charset",
959 sprintf(charset
, "CHARSET=%s", attr
->values
[0].string
.text
);
962 sprintf(content_type
, "CONTENT_TYPE=%s/%s",
963 current
->filetypes
[current
->current_file
]->super
,
964 current
->filetypes
[current
->current_file
]->type
);
965 sprintf(device_uri
, "DEVICE_URI=%s", printer
->device_uri
);
966 sprintf(ppd
, "PPD=%s/ppd/%s.ppd", ServerRoot
, printer
->name
);
967 sprintf(printer_name
, "PRINTER=%s", printer
->name
);
968 sprintf(cache
, "RIP_MAX_CACHE=%s", RIPCache
);
969 sprintf(root
, "SERVER_ROOT=%s", ServerRoot
);
970 sprintf(tmpdir
, "TMPDIR=%s", TempDir
);
972 envp
[0] = "PATH=/bin:/usr/bin";
973 envp
[1] = "SOFTWARE=CUPS/1.1";
975 envp
[3] = "USER=root";
983 envp
[11] = content_type
;
984 envp
[12] = device_uri
;
985 envp
[13] = printer_name
;
998 DEBUG_puts(envp
[10]);
999 DEBUG_puts(envp
[11]);
1000 DEBUG_puts(envp
[12]);
1001 DEBUG_puts(envp
[13]);
1003 current
->current_file
++;
1006 * Now create processes for all of the filters...
1009 if (pipe(statusfds
))
1011 LogMessage(L_ERROR
, "StartJob: unable to create status pipes - %s.",
1013 StopPrinter(printer
);
1014 sprintf(printer
->state_message
, "Unable to create status pipes - %s.",
1019 DEBUG_printf(("statusfds = %d, %d\n", statusfds
[0], statusfds
[1]));
1021 current
->pipe
= statusfds
[0];
1022 current
->status
= 0;
1023 memset(current
->procs
, 0, sizeof(current
->procs
));
1025 if (num_filters
> 0 && strcmp(filters
[num_filters
- 1].filter
, "-") == 0)
1028 filterfds
[1][0] = open("/dev/null", O_RDONLY
);
1029 filterfds
[1][1] = -1;
1030 DEBUG_printf(("filterfds[%d] = %d, %d\n", 1, filterfds
[1][0],
1033 for (i
= 0; i
< num_filters
; i
++)
1038 if (filters
[i
].filter
[0] != '/')
1039 sprintf(command
, "%s/filter/%s", ServerBin
, filters
[i
].filter
);
1041 strcpy(command
, filters
[i
].filter
);
1043 DEBUG_printf(("%s: %s %s %s %s %s %s %s\n", command
, argv
[0],
1044 argv
[1], argv
[2], argv
[3], argv
[4], argv
[5], argv
[6]));
1046 if (i
< (num_filters
- 1) ||
1047 strncmp(printer
->device_uri
, "file:", 5) != 0)
1048 pipe(filterfds
[i
& 1]);
1051 filterfds
[i
& 1][0] = -1;
1052 if (strncmp(printer
->device_uri
, "file:/dev/", 10) == 0)
1053 filterfds
[i
& 1][1] = open(printer
->device_uri
+ 5,
1056 filterfds
[i
& 1][1] = open(printer
->device_uri
+ 5,
1057 O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
1060 DEBUG_printf(("filterfds[%d] = %d, %d\n", i
& 1, filterfds
[i
& 1][0],
1061 filterfds
[i
& 1][1]));
1063 pid
= start_process(command
, argv
, envp
, filterfds
[!(i
& 1)][0],
1064 filterfds
[i
& 1][1], statusfds
[1], 0);
1066 close(filterfds
[!(i
& 1)][0]);
1067 close(filterfds
[!(i
& 1)][1]);
1071 LogMessage(L_ERROR
, "Unable to start filter \"%s\" - %s.",
1072 filters
[i
].filter
, strerror(errno
));
1073 StopPrinter(current
->printer
);
1074 sprintf(printer
->state_message
, "Unable to start filter \"%s\" - %s.",
1075 filters
[i
].filter
, strerror(errno
));
1080 current
->procs
[i
] = pid
;
1082 LogMessage(L_DEBUG
, "Started %s (PID %d) for job %d.", command
, pid
,
1087 if (filters
!= NULL
)
1091 * Finally, pipe the final output into a backend process if needed...
1094 if (strncmp(printer
->device_uri
, "file:", 5) != 0)
1096 sscanf(printer
->device_uri
, "%254[^:]", method
);
1097 sprintf(command
, "%s/backend/%s", ServerBin
, method
);
1099 argv
[0] = printer
->device_uri
;
1103 DEBUG_printf(("%s: %s %s %s %s %s %s %s\n", command
, argv
[0],
1104 argv
[1], argv
[2], argv
[3], argv
[4], argv
[5], argv
[6]));
1106 filterfds
[i
& 1][0] = -1;
1107 filterfds
[i
& 1][1] = open("/dev/null", O_WRONLY
);
1109 DEBUG_printf(("filterfds[%d] = %d, %d\n", i
& 1, filterfds
[i
& 1][0],
1110 filterfds
[i
& 1][1]));
1112 pid
= start_process(command
, argv
, envp
, filterfds
[!(i
& 1)][0],
1113 filterfds
[i
& 1][1], statusfds
[1], 1);
1115 close(filterfds
[!(i
& 1)][0]);
1116 close(filterfds
[!(i
& 1)][1]);
1120 LogMessage(L_ERROR
, "Unable to start backend \"%s\" - %s.",
1121 method
, strerror(errno
));
1122 StopPrinter(current
->printer
);
1123 sprintf(printer
->state_message
, "Unable to start backend \"%s\" - %s.",
1124 method
, strerror(errno
));
1129 current
->procs
[i
] = pid
;
1131 LogMessage(L_DEBUG
, "Started %s (PID %d) for job %d.", command
, pid
,
1137 filterfds
[i
& 1][0] = -1;
1138 filterfds
[i
& 1][1] = -1;
1140 close(filterfds
[!(i
& 1)][0]);
1141 close(filterfds
[!(i
& 1)][1]);
1144 close(filterfds
[i
& 1][0]);
1145 close(filterfds
[i
& 1][1]);
1147 close(statusfds
[1]);
1149 FD_SET(current
->pipe
, &InputSet
);
1154 * 'StopAllJobs()' - Stop all print jobs.
1160 job_t
*current
; /* Current job */
1163 DEBUG_puts(("StopAllJobs()\n", id
));
1165 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1166 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1168 StopJob(current
->id
);
1169 current
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1175 * 'StopJob()' - Stop a print job.
1179 StopJob(int id
) /* I - Job ID */
1181 int i
; /* Looping var */
1182 job_t
*current
; /* Current job */
1185 DEBUG_printf(("StopJob(%d)\n", id
));
1187 for (current
= Jobs
; current
!= NULL
; current
= current
->next
)
1188 if (current
->id
== id
)
1190 DEBUG_puts("StopJob: found job in list.");
1192 if (current
->state
->values
[0].integer
== IPP_JOB_PROCESSING
)
1194 DEBUG_puts("StopJob: job state is \'processing\'.");
1196 if (current
->status
< 0)
1197 SetPrinterState(current
->printer
, IPP_PRINTER_STOPPED
);
1199 SetPrinterState(current
->printer
, IPP_PRINTER_IDLE
);
1201 DEBUG_printf(("StopJob: printer state is %d\n", current
->printer
->state
));
1203 current
->state
->values
[0].integer
= IPP_JOB_STOPPED
;
1204 current
->printer
->job
= NULL
;
1205 current
->printer
= NULL
;
1207 current
->current_file
--;
1209 for (i
= 0; current
->procs
[i
]; i
++)
1210 if (current
->procs
[i
] > 0)
1212 kill(current
->procs
[i
], SIGTERM
);
1213 current
->procs
[i
] = 0;
1218 close(current
->pipe
);
1219 FD_CLR(current
->pipe
, &InputSet
);
1229 * 'UpdateJob()' - Read a status update from a job's filters.
1233 UpdateJob(job_t
*job
) /* I - Job to check */
1235 int bytes
; /* Number of bytes read */
1236 char *lineptr
, /* Pointer to end of line in buffer */
1237 *message
; /* Pointer to message text */
1238 int loglevel
; /* Log level for message */
1239 static int bufused
= 0; /* Amount of buffer used */
1240 static char buffer
[8192]; /* Data buffer */
1243 if ((bytes
= read(job
->pipe
, buffer
+ bufused
, sizeof(buffer
) - bufused
- 1)) > 0)
1246 buffer
[bufused
] = '\0';
1248 while ((lineptr
= strchr(buffer
, '\n')) != NULL
)
1251 * Terminate each line and process it...
1257 * Figure out the logging level...
1260 if (strncmp(buffer
, "ERROR:", 6) == 0)
1263 message
= buffer
+ 6;
1265 else if (strncmp(buffer
, "WARNING:", 8) == 0)
1268 message
= buffer
+ 8;
1270 else if (strncmp(buffer
, "INFO:", 5) == 0)
1273 message
= buffer
+ 5;
1275 else if (strncmp(buffer
, "DEBUG:", 6) == 0)
1278 message
= buffer
+ 6;
1280 else if (strncmp(buffer
, "PAGE:", 5) == 0)
1283 message
= buffer
+ 5;
1292 * Skip leading whitespace in the message...
1295 while (isspace(*message
))
1299 * Send it to the log file and printer state message as needed...
1302 if (loglevel
== L_PAGE
)
1305 * Page message; send the message to the page_log file...
1308 LogPage(job
, message
);
1313 * Other status message; send it to the error_log file...
1316 if (loglevel
!= L_INFO
)
1317 LogMessage(loglevel
, "%s", message
);
1319 if ((loglevel
== L_INFO
&& !job
->status
) ||
1321 strncpy(job
->printer
->state_message
, message
,
1322 sizeof(job
->printer
->state_message
) - 1);
1326 * Update the input buffer...
1329 strcpy(buffer
, lineptr
);
1330 bufused
-= lineptr
- buffer
;
1335 DEBUG_printf(("UpdateJob: job %d is complete.\n", job
->id
));
1337 if (job
->status
< 0)
1340 * Backend had errors; stop it...
1344 job
->state
->values
[0].integer
= IPP_JOB_PENDING
;
1346 else if (job
->status
> 0)
1349 * Filter had errors; cancel it...
1352 if (job
->current_file
< job
->num_files
)
1353 StartJob(job
->id
, job
->printer
);
1359 job
->state
->values
[0].integer
= IPP_JOB_ABORTED
;
1367 * Job printed successfully; cancel it...
1370 if (job
->current_file
< job
->num_files
)
1371 StartJob(job
->id
, job
->printer
);
1377 job
->state
->values
[0].integer
= IPP_JOB_COMPLETED
;
1387 * 'ValidateDest()' - Validate a printer/class destination.
1390 const char * /* O - Printer or class name */
1391 ValidateDest(const char *resource
, /* I - Resource name */
1392 cups_ptype_t
*dtype
) /* O - Type (printer or class) */
1394 if (strncmp(resource
, "/classes/", 9) == 0)
1397 * Print to a class...
1400 *dtype
= CUPS_PRINTER_CLASS
;
1402 if (FindClass(resource
+ 9) == NULL
)
1405 return (resource
+ 9);
1407 else if (strncmp(resource
, "/printers/", 10) == 0)
1410 * Print to a specific printer...
1413 *dtype
= (cups_ptype_t
)0;
1415 if (FindPrinter(resource
+ 10) == NULL
)
1417 *dtype
= CUPS_PRINTER_CLASS
;
1419 if (FindClass(resource
+ 10) == NULL
)
1423 return (resource
+ 10);
1431 * 'ipp_read_file()' - Read an IPP request from a file.
1434 static ipp_state_t
/* O - State */
1435 ipp_read_file(const char *filename
, /* I - File to read from */
1436 ipp_t
*ipp
) /* I - Request to read into */
1438 int fd
; /* File descriptor for file */
1439 int n
; /* Length of data */
1440 unsigned char buffer
[8192], /* Data buffer */
1441 *bufptr
; /* Pointer into buffer */
1442 ipp_attribute_t
*attr
; /* Current attribute */
1443 ipp_tag_t tag
; /* Current tag */
1447 * Open the file if possible...
1450 if (filename
== NULL
|| ipp
== NULL
)
1453 if ((fd
= open(filename
, O_RDONLY
)) == -1)
1457 * Read the IPP request...
1460 ipp
->state
= IPP_IDLE
;
1465 break; /* anti-compiler-warning-code */
1468 ipp
->state
++; /* Avoid common problem... */
1472 * Get the request header...
1475 if ((n
= read(fd
, buffer
, 8)) < 8)
1477 DEBUG_printf(("ipp_read_file: Unable to read header (%d bytes read)!\n", n
));
1479 return (n
== 0 ? IPP_IDLE
: IPP_ERROR
);
1483 * Verify the major version number...
1488 DEBUG_printf(("ipp_read_file: version number (%d.%d) is bad.\n", buffer
[0],
1495 * Then copy the request header over...
1498 ipp
->request
.any
.version
[0] = buffer
[0];
1499 ipp
->request
.any
.version
[1] = buffer
[1];
1500 ipp
->request
.any
.op_status
= (buffer
[2] << 8) | buffer
[3];
1501 ipp
->request
.any
.request_id
= (((((buffer
[4] << 8) | buffer
[5]) << 8) |
1502 buffer
[6]) << 8) | buffer
[7];
1504 ipp
->state
= IPP_ATTRIBUTE
;
1505 ipp
->current
= NULL
;
1506 ipp
->curtag
= IPP_TAG_ZERO
;
1508 case IPP_ATTRIBUTE
:
1509 while (read(fd
, buffer
, 1) > 0)
1512 * Read this attribute...
1515 tag
= (ipp_tag_t
)buffer
[0];
1517 if (tag
== IPP_TAG_END
)
1520 * No more attributes left...
1523 DEBUG_puts("ipp_read_file: IPP_TAG_END!");
1525 ipp
->state
= IPP_DATA
;
1528 else if (tag
< IPP_TAG_UNSUPPORTED_VALUE
)
1531 * Group tag... Set the current group and continue...
1534 if (ipp
->curtag
== tag
)
1535 ippAddSeparator(ipp
);
1538 ipp
->current
= NULL
;
1539 DEBUG_printf(("ipp_read_file: group tag = %x\n", tag
));
1543 DEBUG_printf(("ipp_read_file: value tag = %x\n", tag
));
1549 if (read(fd
, buffer
, 2) < 2)
1551 DEBUG_puts("ipp_read_file: unable to read name length!");
1556 n
= (buffer
[0] << 8) | buffer
[1];
1558 DEBUG_printf(("ipp_read_file: name length = %d\n", n
));
1563 * More values for current attribute...
1566 if (ipp
->current
== NULL
)
1572 attr
= ipp
->current
;
1574 if (attr
->num_values
>= IPP_MAX_VALUES
)
1583 * New attribute; read the name and add it...
1586 if (read(fd
, buffer
, n
) < n
)
1588 DEBUG_puts("ipp_read_file: unable to read name!");
1594 DEBUG_printf(("ipp_read_file: name = \'%s\'\n", buffer
));
1596 attr
= ipp
->current
= _ipp_add_attr(ipp
, IPP_MAX_VALUES
);
1598 attr
->group_tag
= ipp
->curtag
;
1599 attr
->value_tag
= tag
;
1600 attr
->name
= strdup((char *)buffer
);
1601 attr
->num_values
= 0;
1604 if (read(fd
, buffer
, 2) < 2)
1606 DEBUG_puts("ipp_read_file: unable to read value length!");
1611 n
= (buffer
[0] << 8) | buffer
[1];
1612 DEBUG_printf(("ipp_read_file: value length = %d\n", n
));
1616 case IPP_TAG_INTEGER
:
1618 if (read(fd
, buffer
, 4) < 4)
1624 n
= (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1627 attr
->values
[attr
->num_values
].integer
= n
;
1629 case IPP_TAG_BOOLEAN
:
1630 if (read(fd
, buffer
, 1) < 1)
1636 attr
->values
[attr
->num_values
].boolean
= buffer
[0];
1640 case IPP_TAG_KEYWORD
:
1641 case IPP_TAG_STRING
:
1643 case IPP_TAG_URISCHEME
:
1644 case IPP_TAG_CHARSET
:
1645 case IPP_TAG_LANGUAGE
:
1646 case IPP_TAG_MIMETYPE
:
1647 if (read(fd
, buffer
, n
) < n
)
1654 DEBUG_printf(("ipp_read_file: value = \'%s\'\n", buffer
));
1656 attr
->values
[attr
->num_values
].string
.text
= strdup((char *)buffer
);
1659 if (read(fd
, buffer
, 11) < 11)
1665 memcpy(attr
->values
[attr
->num_values
].date
, buffer
, 11);
1667 case IPP_TAG_RESOLUTION
:
1668 if (read(fd
, buffer
, 9) < 9)
1674 attr
->values
[attr
->num_values
].resolution
.xres
=
1675 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1677 attr
->values
[attr
->num_values
].resolution
.yres
=
1678 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
1680 attr
->values
[attr
->num_values
].resolution
.units
=
1681 (ipp_res_t
)buffer
[8];
1683 case IPP_TAG_RANGE
:
1684 if (read(fd
, buffer
, 8) < 8)
1690 attr
->values
[attr
->num_values
].range
.lower
=
1691 (((((buffer
[0] << 8) | buffer
[1]) << 8) | buffer
[2]) << 8) |
1693 attr
->values
[attr
->num_values
].range
.upper
=
1694 (((((buffer
[4] << 8) | buffer
[5]) << 8) | buffer
[6]) << 8) |
1697 case IPP_TAG_TEXTLANG
:
1698 case IPP_TAG_NAMELANG
:
1699 if (read(fd
, buffer
, n
) < n
)
1705 * text-with-language and name-with-language are composite
1714 n
= (bufptr
[0] << 8) | bufptr
[1];
1716 attr
->values
[attr
->num_values
].string
.charset
= calloc(n
+ 1, 1);
1718 memcpy(attr
->values
[attr
->num_values
].string
.charset
,
1722 n
= (bufptr
[0] << 8) | bufptr
[1];
1724 attr
->values
[attr
->num_values
].string
.text
= calloc(n
+ 1, 1);
1726 memcpy(attr
->values
[attr
->num_values
].string
.text
,
1731 default : /* Other unsupported values */
1732 attr
->values
[attr
->num_values
].unknown
.length
= n
;
1735 attr
->values
[attr
->num_values
].unknown
.data
= malloc(n
);
1736 if (read(fd
, attr
->values
[attr
->num_values
].unknown
.data
, n
) < n
)
1740 attr
->values
[attr
->num_values
].unknown
.data
= NULL
;
1744 attr
->num_values
++;
1753 * Close the file and return...
1758 return (ipp
->state
);
1763 * 'ipp_write_file()' - Write an IPP request to a file.
1766 static ipp_state_t
/* O - State */
1767 ipp_write_file(const char *filename
, /* I - File to write to */
1768 ipp_t
*ipp
) /* I - Request to write */
1770 int fd
; /* File descriptor */
1771 int i
; /* Looping var */
1772 int n
; /* Length of data */
1773 unsigned char buffer
[8192], /* Data buffer */
1774 *bufptr
; /* Pointer into buffer */
1775 ipp_attribute_t
*attr
; /* Current attribute */
1779 * Open the file if possible...
1782 if (filename
== NULL
|| ipp
== NULL
)
1785 if ((fd
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0640)) == -1)
1789 fchown(fd
, User
, Group
);
1792 * Write the IPP request...
1795 ipp
->state
= IPP_IDLE
;
1800 break; /* anti-compiler-warning-code */
1803 ipp
->state
++; /* Avoid common problem... */
1807 * Send the request header...
1812 *bufptr
++ = ipp
->request
.any
.version
[0];
1813 *bufptr
++ = ipp
->request
.any
.version
[1];
1814 *bufptr
++ = ipp
->request
.any
.op_status
>> 8;
1815 *bufptr
++ = ipp
->request
.any
.op_status
;
1816 *bufptr
++ = ipp
->request
.any
.request_id
>> 24;
1817 *bufptr
++ = ipp
->request
.any
.request_id
>> 16;
1818 *bufptr
++ = ipp
->request
.any
.request_id
>> 8;
1819 *bufptr
++ = ipp
->request
.any
.request_id
;
1821 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
1823 DEBUG_puts("ipp_write_file: Could not write IPP header...");
1828 ipp
->state
= IPP_ATTRIBUTE
;
1829 ipp
->current
= ipp
->attrs
;
1830 ipp
->curtag
= IPP_TAG_ZERO
;
1832 case IPP_ATTRIBUTE
:
1833 while (ipp
->current
!= NULL
)
1836 * Write this attribute...
1840 attr
= ipp
->current
;
1842 ipp
->current
= ipp
->current
->next
;
1844 if (ipp
->curtag
!= attr
->group_tag
)
1847 * Send a group operation tag...
1850 ipp
->curtag
= attr
->group_tag
;
1852 if (attr
->group_tag
== IPP_TAG_ZERO
)
1855 DEBUG_printf(("ipp_write_file: wrote group tag = %x\n", attr
->group_tag
));
1856 *bufptr
++ = attr
->group_tag
;
1859 n
= strlen(attr
->name
);
1861 DEBUG_printf(("ipp_write_file: writing value tag = %x\n", attr
->value_tag
));
1862 DEBUG_printf(("ipp_write_file: writing name = %d, \'%s\'\n", n
, attr
->name
));
1864 *bufptr
++ = attr
->value_tag
;
1867 memcpy(bufptr
, attr
->name
, n
);
1870 switch (attr
->value_tag
)
1872 case IPP_TAG_INTEGER
:
1874 for (i
= 0; i
< attr
->num_values
; i
++)
1879 * Arrays and sets are done by sending additional
1880 * values with a zero-length name...
1883 *bufptr
++ = attr
->value_tag
;
1890 *bufptr
++ = attr
->values
[i
].integer
>> 24;
1891 *bufptr
++ = attr
->values
[i
].integer
>> 16;
1892 *bufptr
++ = attr
->values
[i
].integer
>> 8;
1893 *bufptr
++ = attr
->values
[i
].integer
;
1897 case IPP_TAG_BOOLEAN
:
1898 for (i
= 0; i
< attr
->num_values
; i
++)
1903 * Arrays and sets are done by sending additional
1904 * values with a zero-length name...
1907 *bufptr
++ = attr
->value_tag
;
1914 *bufptr
++ = attr
->values
[i
].boolean
;
1920 case IPP_TAG_KEYWORD
:
1921 case IPP_TAG_STRING
:
1923 case IPP_TAG_URISCHEME
:
1924 case IPP_TAG_CHARSET
:
1925 case IPP_TAG_LANGUAGE
:
1926 case IPP_TAG_MIMETYPE
:
1927 for (i
= 0; i
< attr
->num_values
; i
++)
1932 * Arrays and sets are done by sending additional
1933 * values with a zero-length name...
1936 DEBUG_printf(("ipp_write_file: writing value tag = %x\n",
1938 DEBUG_printf(("ipp_write_file: writing name = 0, \'\'\n"));
1940 *bufptr
++ = attr
->value_tag
;
1945 n
= strlen(attr
->values
[i
].string
.text
);
1947 DEBUG_printf(("ipp_write_file: writing string = %d, \'%s\'\n", n
,
1948 attr
->values
[i
].string
.text
));
1950 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
1952 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
1954 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
1964 memcpy(bufptr
, attr
->values
[i
].string
.text
, n
);
1970 for (i
= 0; i
< attr
->num_values
; i
++)
1975 * Arrays and sets are done by sending additional
1976 * values with a zero-length name...
1979 *bufptr
++ = attr
->value_tag
;
1986 memcpy(bufptr
, attr
->values
[i
].date
, 11);
1991 case IPP_TAG_RESOLUTION
:
1992 for (i
= 0; i
< attr
->num_values
; i
++)
1997 * Arrays and sets are done by sending additional
1998 * values with a zero-length name...
2001 *bufptr
++ = attr
->value_tag
;
2008 *bufptr
++ = attr
->values
[i
].resolution
.xres
>> 24;
2009 *bufptr
++ = attr
->values
[i
].resolution
.xres
>> 16;
2010 *bufptr
++ = attr
->values
[i
].resolution
.xres
>> 8;
2011 *bufptr
++ = attr
->values
[i
].resolution
.xres
;
2012 *bufptr
++ = attr
->values
[i
].resolution
.yres
>> 24;
2013 *bufptr
++ = attr
->values
[i
].resolution
.yres
>> 16;
2014 *bufptr
++ = attr
->values
[i
].resolution
.yres
>> 8;
2015 *bufptr
++ = attr
->values
[i
].resolution
.yres
;
2016 *bufptr
++ = attr
->values
[i
].resolution
.units
;
2020 case IPP_TAG_RANGE
:
2021 for (i
= 0; i
< attr
->num_values
; i
++)
2026 * Arrays and sets are done by sending additional
2027 * values with a zero-length name...
2030 *bufptr
++ = attr
->value_tag
;
2037 *bufptr
++ = attr
->values
[i
].range
.lower
>> 24;
2038 *bufptr
++ = attr
->values
[i
].range
.lower
>> 16;
2039 *bufptr
++ = attr
->values
[i
].range
.lower
>> 8;
2040 *bufptr
++ = attr
->values
[i
].range
.lower
;
2041 *bufptr
++ = attr
->values
[i
].range
.upper
>> 24;
2042 *bufptr
++ = attr
->values
[i
].range
.upper
>> 16;
2043 *bufptr
++ = attr
->values
[i
].range
.upper
>> 8;
2044 *bufptr
++ = attr
->values
[i
].range
.upper
;
2048 case IPP_TAG_TEXTLANG
:
2049 case IPP_TAG_NAMELANG
:
2050 for (i
= 0; i
< attr
->num_values
; i
++)
2055 * Arrays and sets are done by sending additional
2056 * values with a zero-length name...
2059 *bufptr
++ = attr
->value_tag
;
2064 n
= strlen(attr
->values
[i
].string
.charset
) +
2065 strlen(attr
->values
[i
].string
.text
) +
2068 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2070 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2072 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2079 /* Length of entire value */
2083 /* Length of charset */
2084 n
= strlen(attr
->values
[i
].string
.charset
);
2089 memcpy(bufptr
, attr
->values
[i
].string
.charset
, n
);
2092 /* Length of text */
2093 n
= strlen(attr
->values
[i
].string
.text
);
2098 memcpy(bufptr
, attr
->values
[i
].string
.text
, n
);
2104 for (i
= 0; i
< attr
->num_values
; i
++)
2109 * Arrays and sets are done by sending additional
2110 * values with a zero-length name...
2113 *bufptr
++ = attr
->value_tag
;
2118 n
= attr
->values
[i
].unknown
.length
;
2120 if ((sizeof(buffer
) - (bufptr
- buffer
)) < (n
+ 2))
2122 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2124 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2131 /* Length of unknown value */
2138 memcpy(bufptr
, attr
->values
[i
].unknown
.data
, n
);
2146 * Write the data out...
2149 if (write(fd
, (char *)buffer
, bufptr
- buffer
) < 0)
2151 DEBUG_puts("ipp_write_file: Could not write IPP attribute...");
2156 DEBUG_printf(("ipp_write_file: wrote %d bytes\n", bufptr
- buffer
));
2159 if (ipp
->current
== NULL
)
2162 * Done with all of the attributes; add the end-of-attributes tag...
2165 buffer
[0] = IPP_TAG_END
;
2166 if (write(fd
, (char *)buffer
, 1) < 0)
2168 DEBUG_puts("ipp_write_file: Could not write IPP end-tag...");
2173 ipp
->state
= IPP_DATA
;
2182 * Close the file and return...
2187 return (ipp
->state
);
2192 * 'set_time()' - Set one of the "job-time-at-xyz" attributes...
2196 set_time(job_t
*job
, /* I - Job to update */
2197 const char *name
) /* I - Name of attribute */
2199 ipp_attribute_t
*attr
; /* Time attribute */
2202 if ((attr
= ippFindAttribute(job
->attrs
, name
, IPP_TAG_NOVALUE
)) != NULL
)
2204 attr
->value_tag
= IPP_TAG_INTEGER
;
2205 attr
->values
[0].integer
= time(NULL
) - StartTime
;
2207 else if ((attr
= ippFindAttribute(job
->attrs
, name
, IPP_TAG_INTEGER
)) != NULL
)
2208 attr
->values
[0].integer
= time(NULL
) - StartTime
;
2213 * 'start_process()' - Start a background process.
2216 static int /* O - Process ID or 0 */
2217 start_process(const char *command
, /* I - Full path to command */
2218 char *argv
[], /* I - Command-line arguments */
2219 char *envp
[], /* I - Environment */
2220 int infd
, /* I - Standard input file descriptor */
2221 int outfd
, /* I - Standard output file descriptor */
2222 int errfd
, /* I - Standard error file descriptor */
2223 int root
) /* I - Run as root? */
2225 int fd
; /* Looping var */
2226 int pid
; /* Process ID */
2229 DEBUG_printf(("start_process(\"%s\", %08x, %08x, %d, %d, %d)\n",
2230 command
, argv
, envp
, infd
, outfd
, errfd
));
2232 if ((pid
= fork()) == 0)
2235 * Child process goes here...
2237 * Update stdin/stdout/stderr as needed...
2251 * Close extra file descriptors...
2254 for (fd
= 3; fd
< 1024; fd
++)
2258 * Change user to something "safe"...
2268 * Execute the command; if for some reason this doesn't work,
2269 * return the error code...
2272 execve(command
, argv
, envp
);
2281 * Error - couldn't fork a new process!
2284 DEBUG_printf(("StartJob: unable to fork() %s - %s.\n", command
,
2295 * End of "$Id: job.c,v 1.57 2000/03/21 04:03:35 mike Exp $".