]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cupsfilter.c
Import CUPS 1.4svn r7023 into easysw/current.
[thirdparty/cups.git] / scheduler / cupsfilter.c
1 /*
2 * "$Id: cupsfilter.c 6879 2007-08-29 20:26:50Z mike $"
3 *
4 * CUPS filtering program for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 * main() - Main entry for the test program.
18 * compare_pids() - Compare two filter PIDs...
19 * escape_options() - Convert an options array to a string.
20 * exec_filter() - Execute a single filter.
21 * exec_filters() - Execute filters for the given file and options.
22 * get_job_file() - Get the specified job file.
23 * open_pipe() - Create a pipe which is closed on exec.
24 * read_cupsd_conf() - Read the cupsd.conf file to get the filter settings.
25 * set_string() - Copy and set a string.
26 * usage() - Show program usage...
27 */
28
29 /*
30 * Include necessary headers...
31 */
32
33 #include <cups/cups.h>
34 #include <cups/i18n.h>
35 #include <cups/string.h>
36 #include <errno.h>
37 #include "mime.h"
38 #include <stdlib.h>
39 #include <limits.h>
40 #include <unistd.h>
41 #include <fcntl.h>
42 #include <signal.h>
43 #include <sys/wait.h>
44 #if defined(__APPLE__)
45 # include <libgen.h>
46 #endif /* __APPLE__ */
47
48
49 /*
50 * Local globals...
51 */
52
53 static char *DataDir = NULL;/* CUPS_DATADIR environment variable */
54 static char *FontPath = NULL;
55 /* CUPS_FONTPATH environment variable */
56 static mime_filter_t GZIPFilter = /* gziptoany filter */
57 {
58 NULL, /* Source type */
59 NULL, /* Destination type */
60 0, /* Cost */
61 "gziptoany" /* Filter program to run */
62 };
63 static char *Path = NULL; /* PATH environment variable */
64 static char *ServerBin = NULL;
65 /* CUPS_SERVERBIN environment variable */
66 static char *ServerRoot = NULL;
67 /* CUPS_SERVERROOT environment variable */
68 static char *RIPCache = NULL;
69 /* RIP_CACHE environment variable */
70 static char TempFile[1024] = "";
71 /* Temporary file */
72
73
74 /*
75 * Local functions...
76 */
77
78 static int compare_pids(mime_filter_t *a, mime_filter_t *b);
79 static char *escape_options(int num_options, cups_option_t *options);
80 static int exec_filter(const char *filter, char **argv, char **envp,
81 int infd, int outfd);
82 static int exec_filters(cups_array_t *filters, const char *infile,
83 const char *outfile, const char *ppdfile,
84 const char *printer, const char *user,
85 const char *title, int num_options,
86 cups_option_t *options);
87 static void get_job_file(const char *job);
88 static int open_pipe(int *fds);
89 static int read_cupsd_conf(const char *filename);
90 static void set_string(char **s, const char *val);
91 static void sighandler(int sig);
92 static void usage(const char *command, const char *opt);
93
94
95 /*
96 * 'main()' - Main entry for the test program.
97 */
98
99 int /* O - Exit status */
100 main(int argc, /* I - Number of command-line args */
101 char *argv[]) /* I - Command-line arguments */
102 {
103 int i; /* Looping vars */
104 const char *command, /* Command name */
105 *opt; /* Current option */
106 char *srctype, /* Source type */
107 *dsttype, /* Destination type */
108 super[MIME_MAX_SUPER], /* Super-type name */
109 type[MIME_MAX_TYPE]; /* Type name */
110 int compression; /* Compression of file */
111 int cost; /* Cost of filters */
112 mime_t *mime; /* MIME database */
113 char *infile, /* File to filter */
114 *outfile; /* File to create */
115 char cupsdconf[1024]; /* cupsd.conf file */
116 const char *server_root; /* CUPS_SERVERROOT environment variable */
117 mime_type_t *src, /* Source type */
118 *dst; /* Destination type */
119 cups_array_t *filters; /* Filters for the file */
120 int num_options; /* Number of options */
121 cups_option_t *options; /* Options */
122 const char *ppdfile; /* PPD file */
123 const char *title, /* Title string */
124 *user; /* Username */
125 int removeppd, /* Remove PPD file */
126 removeinfile; /* Remove input file */
127 int status; /* Execution status */
128
129
130 /*
131 * Setup defaults...
132 */
133
134 if ((command = strrchr(argv[0], '/')) != NULL)
135 command ++;
136 else
137 command = argv[0];
138
139 mime = NULL;
140 srctype = NULL;
141 dsttype = "application/pdf";
142 infile = NULL;
143 outfile = NULL;
144 num_options = 0;
145 options = NULL;
146 ppdfile = NULL;
147 title = NULL;
148 user = cupsUser();
149 removeppd = 0;
150 removeinfile = 0;
151
152 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
153 server_root = CUPS_SERVERROOT;
154
155 snprintf(cupsdconf, sizeof(cupsdconf), "%s/cupsd.conf", server_root);
156
157 /*
158 * Process command-line arguments...
159 */
160
161 _cupsSetLocale(argv);
162
163 for (i = 1; i < argc; i ++)
164 if (argv[i][0] == '-')
165 {
166 for (opt = argv[i] + 1; *opt; opt ++)
167 switch (*opt)
168 {
169 case '-' : /* Next argument is a filename... */
170 i ++;
171 if (i < argc && !infile)
172 infile = argv[i];
173 else
174 usage(command, opt);
175 break;
176
177 case 'a' : /* Specify option... */
178 i ++;
179 if (i < argc)
180 num_options = cupsParseOptions(argv[i], num_options, &options);
181 else
182 usage(command, opt);
183 break;
184
185 case 'c' : /* Specify cupsd.conf file location... */
186 i ++;
187 if (i < argc)
188 {
189 if (!strcmp(command, "convert"))
190 num_options = cupsAddOption("copies", argv[i], num_options,
191 &options);
192 else
193 strlcpy(cupsdconf, argv[i], sizeof(cupsdconf));
194 }
195 else
196 usage(command, opt);
197 break;
198
199 case 'D' : /* Delete input file after conversion */
200 removeinfile = 1;
201 break;
202
203 case 'f' : /* Specify input file... */
204 i ++;
205 if (i < argc && !infile)
206 infile = argv[i];
207 else
208 usage(command, opt);
209 break;
210
211 case 'i' : /* Specify source MIME type... */
212 i ++;
213 if (i < argc)
214 {
215 if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
216 usage(command, opt);
217
218 srctype = argv[i];
219 }
220 else
221 usage(command, opt);
222 break;
223
224 case 'j' : /* Get job file or specify destination MIME type... */
225 if (strcmp(command, "convert"))
226 {
227 i ++;
228 if (i < argc)
229 {
230 get_job_file(argv[i]);
231 infile = TempFile;
232 }
233 else
234 usage(command, opt);
235
236 break;
237 }
238
239 case 'm' : /* Specify destination MIME type... */
240 i ++;
241 if (i < argc)
242 {
243 if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
244 usage(command, opt);
245
246 dsttype = argv[i];
247 }
248 else
249 usage(command, opt);
250 break;
251
252 case 'n' : /* Specify number of copies... */
253 i ++;
254 if (i < argc)
255 num_options = cupsAddOption("copies", argv[i], num_options,
256 &options);
257 else
258 usage(command, opt);
259 break;
260
261 case 'o' : /* Specify option(s) or output filename */
262 i ++;
263 if (i < argc)
264 {
265 if (!strcmp(command, "convert"))
266 {
267 if (outfile)
268 usage(command, NULL);
269 else
270 outfile = argv[i];
271 }
272 else
273 num_options = cupsParseOptions(argv[i], num_options,
274 &options);
275 }
276 else
277 usage(command, opt);
278 break;
279
280 case 'p' : /* Specify PPD file... */
281 case 'P' : /* Specify PPD file... */
282 i ++;
283 if (i < argc)
284 ppdfile = argv[i];
285 else
286 usage(command, opt);
287 break;
288
289 case 't' : /* Specify title... */
290 case 'J' : /* Specify title... */
291 i ++;
292 if (i < argc)
293 title = argv[i];
294 else
295 usage(command, opt);
296 break;
297
298 case 'u' : /* Delete PPD file after conversion */
299 removeinfile = 1;
300 break;
301
302 case 'U' : /* Specify username... */
303 i ++;
304 if (i < argc)
305 user = argv[i];
306 else
307 usage(command, opt);
308 break;
309
310 default : /* Something we don't understand... */
311 usage(command, opt);
312 break;
313 }
314 }
315 else if (!infile)
316 {
317 if (strcmp(command, "convert"))
318 infile = argv[i];
319 else
320 {
321 _cupsLangPuts(stderr,
322 _("convert: Use the -f option to specify a file to "
323 "convert.\n"));
324 usage(command, NULL);
325 }
326 }
327 else
328 {
329 _cupsLangPuts(stderr,
330 _("cupsfilter: Only one filename can be specified!\n"));
331 usage(command, NULL);
332 }
333
334 if (!infile && !srctype)
335 usage(command, NULL);
336
337 if (!title)
338 {
339 if (!infile)
340 title = "(stdin)";
341 else if ((title = strrchr(infile, '/')) != NULL)
342 title ++;
343 else
344 title = infile;
345 }
346
347 /*
348 * Load the cupsd.conf file and create the MIME database...
349 */
350
351 if (read_cupsd_conf(cupsdconf))
352 return (1);
353
354 if ((mime = mimeLoad(ServerRoot, Path)) == NULL)
355 {
356 _cupsLangPrintf(stderr,
357 _("%s: Unable to read MIME database from \"%s\"!\n"),
358 command, ServerRoot);
359 return (1);
360 }
361
362 /*
363 * Get the source and destination types...
364 */
365
366 if (srctype)
367 {
368 sscanf(srctype, "%15[^/]/%255s", super, type);
369 if ((src = mimeType(mime, super, type)) == NULL)
370 {
371 _cupsLangPrintf(stderr,
372 _("%s: Unknown source MIME type %s/%s!\n"),
373 command, super, type);
374 return (1);
375 }
376 }
377 else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
378 {
379 _cupsLangPrintf(stderr,
380 _("%s: Unable to determine MIME type of \"%s\"!\n"),
381 command, infile);
382 return (1);
383 }
384
385 sscanf(dsttype, "%15[^/]/%255s", super, type);
386 if ((dst = mimeType(mime, super, type)) == NULL)
387 {
388 _cupsLangPrintf(stderr,
389 _("%s: Unknown destination MIME type %s/%s!\n"),
390 command, super, type);
391 return (1);
392 }
393
394 /*
395 * Figure out how to filter the file...
396 */
397
398 if (src == dst)
399 {
400 /*
401 * Special case - no filtering needed...
402 */
403
404 filters = cupsArrayNew(NULL, NULL);
405 cupsArrayAdd(filters, &GZIPFilter);
406 }
407 else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
408 {
409 _cupsLangPrintf(stderr,
410 _("%s: No filter to convert from %s/%s to %s/%s!\n"),
411 command, src->super, src->type, dst->super, dst->type);
412 return (1);
413 }
414 else if (compression)
415 cupsArrayInsert(filters, &GZIPFilter);
416
417 /*
418 * Do it!
419 */
420
421 status = exec_filters(filters, infile, outfile, ppdfile,
422 !strcmp(command, "convert") ? "tofile" : "cupsfilter",
423 user, title, num_options, options);
424
425 /*
426 * Remove files as needed, then exit...
427 */
428
429 if (TempFile[0])
430 unlink(TempFile);
431
432 if (removeppd && ppdfile)
433 unlink(ppdfile);
434
435 if (removeinfile && infile)
436 unlink(infile);
437
438 return (status);
439 }
440
441
442 /*
443 * 'compare_pids()' - Compare two filter PIDs...
444 */
445
446 static int /* O - Result of comparison */
447 compare_pids(mime_filter_t *a, /* I - First filter */
448 mime_filter_t *b) /* I - Second filter */
449 {
450 /*
451 * Because we're particularly lazy, we store the process ID in the "cost"
452 * variable...
453 */
454
455 return (a->cost - b->cost);
456 }
457
458
459 /*
460 * 'escape_options()' - Convert an options array to a string.
461 */
462
463 static char * /* O - Option string */
464 escape_options(
465 int num_options, /* I - Number of options */
466 cups_option_t *options) /* I - Options */
467 {
468 int i; /* Looping var */
469 cups_option_t *option; /* Current option */
470 int bytes; /* Number of bytes needed */
471 char *s, /* Option string */
472 *sptr, /* Pointer into string */
473 *vptr; /* Pointer into value */
474
475
476 /*
477 * Figure out the worst-case number of bytes we need for the option string.
478 */
479
480 for (i = num_options, option = options, bytes = 1; i > 0; i --, option ++)
481 bytes += 2 * (strlen(option->name) + strlen(option->value)) + 2;
482
483 s = malloc(bytes);
484
485 /*
486 * Copy the options to the string...
487 */
488
489 for (i = num_options, option = options, sptr = s; i > 0; i --, option ++)
490 {
491 if (!strcmp(option->name, "copies"))
492 continue;
493
494 if (sptr > s)
495 *sptr++ = ' ';
496
497 strcpy(sptr, option->name);
498 sptr += strlen(sptr);
499 *sptr++ = '=';
500
501 for (vptr = option->value; *vptr;)
502 {
503 if (strchr("\\ \t\n", *vptr))
504 *sptr++ = '\\';
505
506 *sptr++ = *vptr++;
507 }
508 }
509
510 *sptr = '\0';
511
512 return (s);
513 }
514
515
516 /*
517 * 'exec_filter()' - Execute a single filter.
518 */
519
520 static int /* O - Process ID or -1 on error */
521 exec_filter(const char *filter, /* I - Filter to execute */
522 char **argv, /* I - Argument list */
523 char **envp, /* I - Environment list */
524 int infd, /* I - Stdin file descriptor */
525 int outfd) /* I - Stdout file descriptor */
526 {
527 int pid; /* Process ID */
528 #if defined(__APPLE__)
529 char processPath[1024], /* CFProcessPath environment variable */
530 linkpath[1024]; /* Link path for symlinks... */
531 int linkbytes; /* Bytes for link path */
532
533
534 /*
535 * Add special voodoo magic for MacOS X - this allows MacOS X
536 * programs to access their bundle resources properly...
537 */
538
539 if ((linkbytes = readlink(filter, linkpath, sizeof(linkpath) - 1)) > 0)
540 {
541 /*
542 * Yes, this is a symlink to the actual program, nul-terminate and
543 * use it...
544 */
545
546 linkpath[linkbytes] = '\0';
547
548 if (linkpath[0] == '/')
549 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
550 linkpath);
551 else
552 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
553 dirname((char *)filter), linkpath);
554 }
555 else
556 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", filter);
557
558 envp[0] = processPath; /* Replace <CFProcessPath> string */
559 #endif /* __APPLE__ */
560
561 if ((pid = fork()) == 0)
562 {
563 /*
564 * Child process goes here...
565 *
566 * Update stdin/stdout/stderr as needed...
567 */
568
569 if (infd != 0)
570 {
571 close(0);
572 if (infd > 0)
573 dup(infd);
574 else
575 open("/dev/null", O_RDONLY);
576 }
577
578 if (outfd != 1)
579 {
580 close(1);
581 if (outfd > 0)
582 dup(outfd);
583 else
584 open("/dev/null", O_WRONLY);
585 }
586
587 close(3);
588 open("/dev/null", O_RDWR);
589 fcntl(3, F_SETFL, O_NDELAY);
590
591 close(4);
592 open("/dev/null", O_RDWR);
593 fcntl(4, F_SETFL, O_NDELAY);
594
595 /*
596 * Execute command...
597 */
598
599 execve(filter, argv, envp);
600
601 perror(filter);
602
603 exit(errno);
604 }
605
606 return (pid);
607 }
608
609
610 /*
611 * 'exec_filters()' - Execute filters for the given file and options.
612 */
613
614 static int /* O - 0 on success, 1 on error */
615 exec_filters(cups_array_t *filters, /* I - Array of filters to run */
616 const char *infile, /* I - File to filter */
617 const char *outfile, /* I - File to create */
618 const char *ppdfile, /* I - PPD file, if any */
619 const char *printer, /* I - Printer name */
620 const char *user, /* I - Username */
621 const char *title, /* I - Job title */
622 int num_options, /* I - Number of filter options */
623 cups_option_t *options) /* I - Filter options */
624 {
625 int i; /* Looping var */
626 const char *argv[8], /* Command-line arguments */
627 *envp[11], /* Environment variables */
628 *temp; /* Temporary string */
629 char *optstr, /* Filter options */
630 cups_datadir[1024], /* CUPS_DATADIR */
631 cups_fontpath[1024], /* CUPS_FONTPATH */
632 cups_serverbin[1024], /* CUPS_SERVERBIN */
633 cups_serverroot[1024], /* CUPS_SERVERROOT */
634 lang[1024], /* LANG */
635 path[1024], /* PATH */
636 ppd[1024], /* PPD */
637 rip_cache[1024], /* RIP_CACHE */
638 userenv[1024], /* USER */
639 program[1024]; /* Program to run */
640 mime_filter_t *filter, /* Current filter */
641 *next; /* Next filter */
642 int current, /* Current filter */
643 filterfds[2][2], /* Pipes for filters */
644 pid, /* Process ID of filter */
645 status, /* Exit status */
646 retval; /* Return value */
647 cups_array_t *pids; /* Executed filters array */
648 mime_filter_t key; /* Search key for filters */
649 cups_lang_t *language; /* Current language */
650
651
652 /*
653 * Setup the filter environment and command-line...
654 */
655
656 optstr = escape_options(num_options, options);
657
658 snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
659 snprintf(cups_fontpath, sizeof(cups_fontpath), "CUPS_FONTPATH=%s", FontPath);
660 snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s",
661 ServerBin);
662 snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s",
663 ServerRoot);
664 language = cupsLangDefault();
665 snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
666 snprintf(path, sizeof(path), "PATH=%s", Path);
667 if (ppdfile)
668 snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile);
669 else if ((temp = getenv("PPD")) != NULL)
670 snprintf(ppd, sizeof(ppd), "PPD=%s", temp);
671 else
672 #ifdef __APPLE__
673 if (!access("/System/Library/Frameworks/ApplicationServices.framework/"
674 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
675 "Resources/English.lproj/Generic.ppd", 0))
676 strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
677 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
678 "Resources/English.lproj/Generic.ppd", sizeof(ppd));
679 else
680 strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
681 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
682 "Resources/Generic.ppd", sizeof(ppd));
683 #else
684 snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir);
685 #endif /* __APPLE__ */
686 snprintf(rip_cache, sizeof(rip_cache), "RIP_CACHE=%s", RIPCache);
687 snprintf(userenv, sizeof(userenv), "USER=%s", user);
688
689 argv[0] = (char *)printer;
690 argv[1] = "1";
691 argv[2] = user;
692 argv[3] = title;
693 argv[4] = cupsGetOption("copies", num_options, options);
694 argv[5] = optstr;
695 argv[6] = infile;
696 argv[7] = NULL;
697
698 if (!argv[4])
699 argv[4] = "1";
700
701 envp[0] = "<CFProcessPath>";
702 envp[1] = cups_datadir;
703 envp[2] = cups_fontpath;
704 envp[3] = cups_serverbin;
705 envp[4] = cups_serverroot;
706 envp[5] = lang;
707 envp[6] = path;
708 envp[7] = ppd;
709 envp[8] = rip_cache;
710 envp[9] = userenv;
711 envp[10] = NULL;
712
713 for (i = 0; argv[i]; i ++)
714 fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
715
716 for (i = 0; envp[i]; i ++)
717 fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]);
718
719 /*
720 * Execute all of the filters...
721 */
722
723 pids = cupsArrayNew((cups_array_func_t)compare_pids, NULL);
724 current = 0;
725 filterfds[0][0] = -1;
726 filterfds[0][1] = -1;
727 filterfds[1][0] = -1;
728 filterfds[1][1] = -1;
729
730 if (!infile)
731 filterfds[0][0] = 0;
732
733 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
734 filter;
735 filter = next, current = 1 - current)
736 {
737 next = (mime_filter_t *)cupsArrayNext(filters);
738
739 if (filter->filter[0] == '/')
740 strlcpy(program, filter->filter, sizeof(program));
741 else
742 snprintf(program, sizeof(program), "%s/filter/%s", ServerBin,
743 filter->filter);
744
745 if (filterfds[!current][1] > 1)
746 {
747 close(filterfds[1 - current][0]);
748 close(filterfds[1 - current][1]);
749
750 filterfds[1 - current][0] = -1;
751 filterfds[1 - current][0] = -1;
752 }
753
754 if (next)
755 open_pipe(filterfds[1 - current]);
756 else if (outfile)
757 {
758 filterfds[1 - current][1] = open(outfile, O_CREAT | O_TRUNC | O_WRONLY,
759 0666);
760
761 if (filterfds[1 - current][1] < 0)
762 fprintf(stderr, "ERROR: Unable to create \"%s\" - %s\n", outfile,
763 strerror(errno));
764 }
765 else
766 filterfds[1 - current][1] = 1;
767
768 pid = exec_filter(program, (char **)argv, (char **)envp,
769 filterfds[current][0], filterfds[1 - current][1]);
770
771 if (pid > 0)
772 {
773 fprintf(stderr, "INFO: %s (PID %d) started.\n", filter->filter, pid);
774
775 filter->cost = pid;
776 cupsArrayAdd(pids, filter);
777 }
778 else
779 break;
780
781 argv[6] = NULL;
782 }
783
784 /*
785 * Close remaining pipes...
786 */
787
788 if (filterfds[0][1] > 1)
789 {
790 close(filterfds[0][0]);
791 close(filterfds[0][1]);
792 }
793
794 if (filterfds[1][1] > 1)
795 {
796 close(filterfds[1][0]);
797 close(filterfds[1][1]);
798 }
799
800 /*
801 * Wait for the children to exit...
802 */
803
804 retval = 0;
805
806 while (cupsArrayCount(pids) > 0)
807 {
808 if ((pid = wait(&status)) < 0)
809 continue;
810
811 key.cost = pid;
812 if ((filter = (mime_filter_t *)cupsArrayFind(pids, &key)) != NULL)
813 {
814 cupsArrayRemove(pids, filter);
815
816 if (status)
817 {
818 if (WIFEXITED(status))
819 fprintf(stderr, "ERROR: %s (PID %d) stopped with status %d!\n",
820 filter->filter, pid, WEXITSTATUS(status));
821 else
822 fprintf(stderr, "ERROR: %s (PID %d) crashed on signal %d!\n",
823 filter->filter, pid, WTERMSIG(status));
824
825 retval = 1;
826 }
827 else
828 fprintf(stderr, "INFO: %s (PID %d) exited with no errors.\n",
829 filter->filter, pid);
830 }
831 }
832
833 return (retval);
834 }
835
836
837 /*
838 * 'get_job_file()' - Get the specified job file.
839 */
840
841 static void
842 get_job_file(const char *job) /* I - Job ID */
843 {
844 long jobid, /* Job ID */
845 docnum; /* Document number */
846 const char *jobptr; /* Pointer into job ID string */
847 char uri[1024]; /* job-uri */
848 http_t *http; /* Connection to server */
849 ipp_t *request; /* Request data */
850 int tempfd; /* Temporary file */
851
852
853 /*
854 * Get the job ID and document number, if any...
855 */
856
857 if ((jobptr = strrchr(job, '-')) != NULL)
858 jobptr ++;
859 else
860 jobptr = job;
861
862 jobid = strtol(jobptr, (char **)&jobptr, 10);
863
864 if (*jobptr == ',')
865 docnum = strtol(jobptr + 1, NULL, 10);
866 else
867 docnum = 1;
868
869 if (jobid < 1 || jobid > INT_MAX)
870 {
871 _cupsLangPrintf(stderr, _("cupsfilter: Invalid job ID %d!\n"), (int)jobid);
872 exit(1);
873 }
874
875 if (docnum < 1 || docnum > INT_MAX)
876 {
877 _cupsLangPrintf(stderr, _("cupsfilter: Invalid document number %d!\n"),
878 (int)docnum);
879 exit(1);
880 }
881
882 /*
883 * Ask the server for the document file...
884 */
885
886 if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
887 cupsEncryption())) == NULL)
888 {
889 _cupsLangPrintf(stderr, _("%s: Unable to connect to server\n"),
890 "cupsfilter");
891 exit(1);
892 }
893
894 request = ippNewRequest(CUPS_GET_DOCUMENT);
895
896 snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", (int)jobid);
897
898 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
899 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "document-number",
900 (int)docnum);
901
902 if ((tempfd = cupsTempFd(TempFile, sizeof(TempFile))) == -1)
903 {
904 _cupsLangPrintf(stderr,
905 _("cupsfilter: Unable to create temporary file: %s\n"),
906 strerror(errno));
907 httpClose(http);
908 exit(1);
909 }
910
911 signal(SIGTERM, sighandler);
912
913 ippDelete(cupsDoIORequest(http, request, "/", -1, tempfd));
914
915 close(tempfd);
916
917 httpClose(http);
918
919 if (cupsLastError() != IPP_OK)
920 {
921 _cupsLangPrintf(stderr, _("cupsfilter: Unable to get job file - %s\n"),
922 cupsLastErrorString());
923 unlink(TempFile);
924 exit(1);
925 }
926 }
927
928
929 /*
930 * 'open_pipe()' - Create a pipe which is closed on exec.
931 */
932
933 static int /* O - 0 on success, -1 on error */
934 open_pipe(int *fds) /* O - Pipe file descriptors (2) */
935 {
936 /*
937 * Create the pipe...
938 */
939
940 if (pipe(fds))
941 {
942 fds[0] = -1;
943 fds[1] = -1;
944
945 return (-1);
946 }
947
948 /*
949 * Set the "close on exec" flag on each end of the pipe...
950 */
951
952 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
953 {
954 close(fds[0]);
955 close(fds[1]);
956
957 fds[0] = -1;
958 fds[1] = -1;
959
960 return (-1);
961 }
962
963 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
964 {
965 close(fds[0]);
966 close(fds[1]);
967
968 fds[0] = -1;
969 fds[1] = -1;
970
971 return (-1);
972 }
973
974 /*
975 * Return 0 indicating success...
976 */
977
978 return (0);
979 }
980
981
982 /*
983 * 'read_cupsd_conf()' - Read the cupsd.conf file to get the filter settings.
984 */
985
986 static int /* O - 0 on success, 1 on error */
987 read_cupsd_conf(const char *filename) /* I - File to read */
988 {
989 cups_file_t *fp; /* cupsd.conf file */
990 const char *temp; /* Temporary string */
991 char line[1024], /* Line from file */
992 *ptr; /* Pointer into line */
993 int linenum; /* Current line number */
994
995
996 if ((temp = getenv("CUPS_DATADIR")) != NULL)
997 set_string(&DataDir, temp);
998 else
999 set_string(&DataDir, CUPS_DATADIR);
1000
1001 if ((temp = getenv("CUPS_FONTPATH")) != NULL)
1002 set_string(&FontPath, temp);
1003 else
1004 set_string(&FontPath, CUPS_FONTPATH);
1005
1006 set_string(&RIPCache, "8m");
1007
1008 if ((temp = getenv("CUPS_SERVERBIN")) != NULL)
1009 set_string(&ServerBin, temp);
1010 else
1011 set_string(&ServerBin, CUPS_SERVERBIN);
1012
1013 strlcpy(line, filename, sizeof(line));
1014 if ((ptr = strrchr(line, '/')) != NULL)
1015 *ptr = '\0';
1016 else
1017 getcwd(line, sizeof(line));
1018
1019 set_string(&ServerRoot, line);
1020
1021 if ((fp = cupsFileOpen(filename, "r")) != NULL)
1022 {
1023 linenum = 0;
1024
1025 while (cupsFileGetConf(fp, line, sizeof(line), &ptr, &linenum))
1026 {
1027 if (!strcasecmp(line, "DataDir"))
1028 set_string(&DataDir, ptr);
1029 else if (!strcasecmp(line, "FontPath"))
1030 set_string(&FontPath, ptr);
1031 else if (!strcasecmp(line, "RIPCache"))
1032 set_string(&RIPCache, ptr);
1033 else if (!strcasecmp(line, "ServerBin"))
1034 set_string(&ServerBin, ptr);
1035 else if (!strcasecmp(line, "ServerRoot"))
1036 set_string(&ServerRoot, ptr);
1037 }
1038
1039 cupsFileClose(fp);
1040 }
1041
1042 snprintf(line, sizeof(line),
1043 "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin/usr/bin",
1044 ServerBin);
1045 set_string(&Path, line);
1046
1047 return (0);
1048 }
1049
1050
1051 /*
1052 * 'set_string()' - Copy and set a string.
1053 */
1054
1055 static void
1056 set_string(char **s, /* O - Copy of string */
1057 const char *val) /* I - String to copy */
1058 {
1059 if (*s)
1060 free(*s);
1061
1062 *s = strdup(val);
1063 }
1064
1065
1066 /*
1067 * 'sighandler()' - Signal catcher for when we print from stdin...
1068 */
1069
1070 static void
1071 sighandler(int s) /* I - Signal number */
1072 {
1073 /*
1074 * Remove the temporary file we're using to print a job file...
1075 */
1076
1077 if (TempFile[0])
1078 unlink(TempFile);
1079
1080 /*
1081 * Exit...
1082 */
1083
1084 exit(s);
1085 }
1086
1087
1088 /*
1089 * 'usage()' - Show program usage...
1090 */
1091
1092 static void
1093 usage(const char *command, /* I - Command name */
1094 const char *opt) /* I - Incorrect option, if any */
1095 {
1096 if (opt)
1097 _cupsLangPrintf(stderr, _("%s: Unknown option '%c'!\n"), command, *opt);
1098
1099 if (!strcmp(command, "cupsfilter"))
1100 _cupsLangPuts(stdout,
1101 _("Usage: cupsfilter -m mime/type [ options ] filename\n"
1102 "\n"
1103 "Options:\n"
1104 "\n"
1105 " -c cupsd.conf Set cupsd.conf file to use\n"
1106 " -j job-id[,N] Filter file N from the specified job (default is file 1)\n"
1107 " -n copies Set number of copies\n"
1108 " -o name=value Set option(s)\n"
1109 " -p filename.ppd Set PPD file\n"
1110 " -t title Set title\n"));
1111 else
1112 _cupsLangPuts(stdout,
1113 _("Usage: convert [ options ]\n"
1114 "\n"
1115 "Options:\n"
1116 "\n"
1117 " -f filename Set file to be converted (otherwise stdin)\n"
1118 " -o filename Set file to be generated (otherwise stdout)\n"
1119 " -i mime/type Set input MIME type (otherwise auto-typed)\n"
1120 " -j mime/type Set output MIME type (otherwise application/pdf)\n"
1121 " -P filename.ppd Set PPD file\n"
1122 " -a 'name=value ...' Set option(s)\n"
1123 " -U username Set username for job\n"
1124 " -J title Set title\n"
1125 " -c copies Set number of copies\n"
1126 " -u Remove the PPD file when finished\n"
1127 " -D Remove the input file when finished\n"));
1128
1129 exit(1);
1130 }
1131
1132
1133 /*
1134 * End of "$Id: cupsfilter.c 6879 2007-08-29 20:26:50Z mike $".
1135 */