]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/cupsfilter.c
6dc7e34330c495857c4a46e0175fd28d25aae10d
2 * Filtering program for CUPS.
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * which should have been included with this file. If this file is
11 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * Include necessary headers...
18 #include <cups/cups-private.h>
19 #include <cups/file-private.h>
20 #include <cups/ppd-private.h>
27 #if defined(__APPLE__)
29 #endif /* __APPLE__ */
36 static char *DataDir
= NULL
;/* CUPS_DATADIR environment variable */
37 static char *FontPath
= NULL
;
38 /* CUPS_FONTPATH environment variable */
39 static mime_filter_t GZIPFilter
= /* gziptoany filter */
41 NULL
, /* Source type */
42 NULL
, /* Destination type */
44 "gziptoany" /* Filter program to run */
46 static char *Path
= NULL
; /* PATH environment variable */
47 static char *ServerBin
= NULL
;
48 /* CUPS_SERVERBIN environment variable */
49 static char *ServerRoot
= NULL
;
50 /* CUPS_SERVERROOT environment variable */
51 static char *RIPCache
= NULL
;
52 /* RIP_MAX_CACHE environment variable */
53 static char TempFile
[1024] = "";
61 static void add_printer_filter(const char *command
, mime_t
*mime
,
62 mime_type_t
*printer_type
,
64 static mime_type_t
*add_printer_filters(const char *command
,
65 mime_t
*mime
, const char *printer
,
67 mime_type_t
**prefilter_type
);
68 static void check_cb(void *context
, _cups_fc_result_t result
,
70 static int compare_pids(mime_filter_t
*a
, mime_filter_t
*b
);
71 static char *escape_options(int num_options
, cups_option_t
*options
);
72 static int exec_filter(const char *filter
, char **argv
,
73 char **envp
, int infd
, int outfd
);
74 static int exec_filters(mime_type_t
*srctype
,
75 cups_array_t
*filters
, const char *infile
,
76 const char *outfile
, const char *ppdfile
,
77 const char *printer
, const char *user
,
78 const char *title
, int num_options
,
79 cups_option_t
*options
);
80 static void get_job_file(const char *job
);
81 static int open_pipe(int *fds
);
82 static int read_cups_files_conf(const char *filename
);
83 static void set_string(char **s
, const char *val
);
84 static void sighandler(int sig
);
85 static void usage(const char *opt
) __attribute__((noreturn
));
89 * 'main()' - Main entry for the test program.
92 int /* O - Exit status */
93 main(int argc
, /* I - Number of command-line args */
94 char *argv
[]) /* I - Command-line arguments */
96 int i
, /* Looping vars */
97 list_filters
= 0; /* Just list the filters? */
98 const char *command
, /* Command name */
99 *opt
, /* Current option */
100 *printer
; /* Printer name */
101 mime_type_t
*printer_type
, /* Printer MIME type */
102 *prefilter_type
; /* Printer prefilter MIME type */
103 char *srctype
, /* Source type */
104 *dsttype
, /* Destination type */
105 super
[MIME_MAX_SUPER
], /* Super-type name */
106 type
[MIME_MAX_TYPE
]; /* Type name */
107 int compression
; /* Compression of file */
108 int cost
; /* Cost of filters */
109 mime_t
*mime
; /* MIME database */
110 char mimedir
[1024]; /* MIME directory */
111 char *infile
, /* File to filter */
112 *outfile
; /* File to create */
113 char cupsfilesconf
[1024]; /* cups-files.conf file */
114 const char *server_root
; /* CUPS_SERVERROOT environment variable */
115 mime_type_t
*src
, /* Source type */
116 *dst
; /* Destination type */
117 cups_array_t
*filters
; /* Filters for the file */
118 int num_options
; /* Number of options */
119 cups_option_t
*options
; /* Options */
120 const char *ppdfile
; /* PPD file */
121 const char *title
, /* Title string */
122 *user
; /* Username */
123 int all_filters
, /* Use all filters */
124 removeppd
, /* Remove PPD file */
125 removeinfile
; /* Remove input file */
126 int status
; /* Execution status */
133 if ((command
= strrchr(argv
[0], '/')) != NULL
)
138 printer
= !strcmp(command
, "convert") ? "tofile" : "cupsfilter";
142 dsttype
= "application/pdf";
154 if ((server_root
= getenv("CUPS_SERVERROOT")) == NULL
)
155 server_root
= CUPS_SERVERROOT
;
157 snprintf(cupsfilesconf
, sizeof(cupsfilesconf
), "%s/cups-files.conf", server_root
);
160 * Process command-line arguments...
163 _cupsSetLocale(argv
);
165 for (i
= 1; i
< argc
; i
++)
167 if (argv
[i
][0] == '-')
169 if (!strcmp(argv
[i
], "--list-filters"))
173 else if (!strcmp(argv
[i
], "--"))
176 if (i
< argc
&& !infile
)
183 for (opt
= argv
[i
] + 1; *opt
; opt
++)
187 case 'a' : /* Specify option... */
190 num_options
= cupsParseOptions(argv
[i
], num_options
, &options
);
195 case 'c' : /* Specify cups-files.conf file location... */
199 if (!strcmp(command
, "convert"))
200 num_options
= cupsAddOption("copies", argv
[i
], num_options
, &options
);
202 strlcpy(cupsfilesconf
, argv
[i
], sizeof(cupsfilesconf
));
208 case 'd' : /* Specify the real printer name */
216 case 'D' : /* Delete input file after conversion */
220 case 'e' : /* Use every filter from the PPD file */
224 case 'f' : /* Specify input file... */
226 if (i
< argc
&& !infile
)
232 case 'i' : /* Specify source MIME type... */
236 if (sscanf(argv
[i
], "%15[^/]/%255s", super
, type
) != 2)
245 case 'j' : /* Get job file or specify destination MIME type... */
246 if (strcmp(command
, "convert"))
251 get_job_file(argv
[i
]);
260 case 'm' : /* Specify destination MIME type... */
264 if (sscanf(argv
[i
], "%15[^/]/%255s", super
, type
) != 2)
273 case 'n' : /* Specify number of copies... */
276 num_options
= cupsAddOption("copies", argv
[i
], num_options
, &options
);
281 case 'o' : /* Specify option(s) or output filename */
285 if (!strcmp(command
, "convert"))
293 num_options
= cupsParseOptions(argv
[i
], num_options
, &options
);
299 case 'p' : /* Specify PPD file... */
300 case 'P' : /* Specify PPD file... */
308 case 't' : /* Specify title... */
309 case 'J' : /* Specify title... */
317 case 'u' : /* Delete PPD file after conversion */
321 case 'U' : /* Specify username... */
329 default : /* Something we don't understand... */
338 if (strcmp(command
, "convert"))
345 _cupsLangPuts(stderr
,
346 _("cupsfilter: Only one filename can be specified."));
351 if (!infile
&& !srctype
)
358 else if ((title
= strrchr(infile
, '/')) != NULL
)
365 * Load the cups-files.conf file and create the MIME database...
368 if (read_cups_files_conf(cupsfilesconf
))
371 snprintf(mimedir
, sizeof(mimedir
), "%s/mime", DataDir
);
373 mime
= mimeLoadTypes(NULL
, mimedir
);
374 mime
= mimeLoadTypes(mime
, ServerRoot
);
375 mime
= mimeLoadFilters(mime
, mimedir
, Path
);
376 mime
= mimeLoadFilters(mime
, ServerRoot
, Path
);
380 _cupsLangPrintf(stderr
,
381 _("%s: Unable to read MIME database from \"%s\" or "
383 command
, mimedir
, ServerRoot
);
387 prefilter_type
= NULL
;
390 printer_type
= add_printer_filters(command
, mime
, printer
, ppdfile
,
393 printer_type
= mimeType(mime
, "application", "vnd.cups-postscript");
396 * Get the source and destination types...
401 /* sscanf return value already checked above */
402 sscanf(srctype
, "%15[^/]/%255s", super
, type
);
403 if ((src
= mimeType(mime
, super
, type
)) == NULL
)
405 _cupsLangPrintf(stderr
,
406 _("%s: Unknown source MIME type %s/%s."),
407 command
, super
, type
);
411 else if ((src
= mimeFileType(mime
, infile
, infile
, &compression
)) == NULL
)
413 _cupsLangPrintf(stderr
,
414 _("%s: Unable to determine MIME type of \"%s\"."),
419 /* sscanf return value already checked above */
420 sscanf(dsttype
, "%15[^/]/%255s", super
, type
);
421 if (!_cups_strcasecmp(super
, "printer"))
423 else if ((dst
= mimeType(mime
, super
, type
)) == NULL
)
425 _cupsLangPrintf(stderr
,
426 _("%s: Unknown destination MIME type %s/%s."),
427 command
, super
, type
);
432 * Figure out how to filter the file...
438 * Special case - no filtering needed...
441 filters
= cupsArrayNew(NULL
, NULL
);
442 cupsArrayAdd(filters
, &GZIPFilter
);
443 GZIPFilter
.src
= src
;
444 GZIPFilter
.dst
= dst
;
446 else if ((filters
= mimeFilter(mime
, src
, dst
, &cost
)) == NULL
)
448 _cupsLangPrintf(stderr
,
449 _("%s: No filter to convert from %s/%s to %s/%s."),
450 command
, src
->super
, src
->type
, dst
->super
, dst
->type
);
453 else if (compression
)
454 cupsArrayInsert(filters
, &GZIPFilter
);
462 mime_filter_t
*filter
, /* Current filter */
463 *prefilter
; /* Current pre-filter */
464 cups_array_t
*prefilters
= cupsArrayNew(NULL
, NULL
);
465 /* New filters array */
468 for (filter
= (mime_filter_t
*)cupsArrayFirst(filters
);
470 filter
= (mime_filter_t
*)cupsArrayNext(filters
))
472 if ((prefilter
= mimeFilterLookup(mime
, filter
->src
,
473 prefilter_type
)) != NULL
)
474 cupsArrayAdd(prefilters
, prefilter
);
476 cupsArrayAdd(prefilters
, filter
);
479 cupsArrayDelete(filters
);
480 filters
= prefilters
;
489 mime_filter_t
*filter
; /* Current filter */
491 for (filter
= (mime_filter_t
*)cupsArrayFirst(filters
);
493 filter
= (mime_filter_t
*)cupsArrayNext(filters
))
494 if (strcmp(filter
->filter
, "-"))
495 _cupsLangPuts(stdout
, filter
->filter
);
505 status
= exec_filters(src
, filters
, infile
, outfile
, ppdfile
, printer
, user
,
506 title
, num_options
, options
);
510 * Remove files as needed, then exit...
516 if (removeppd
&& ppdfile
)
519 if (removeinfile
&& infile
)
527 * 'add_printer_filter()' - Add a single filters from a PPD file.
532 const char *command
, /* I - Command name */
533 mime_t
*mime
, /* I - MIME database */
534 mime_type_t
*filtertype
, /* I - Printer or prefilter MIME type */
535 const char *filter
) /* I - Filter to add */
537 char super
[MIME_MAX_SUPER
], /* Super-type for filter */
538 type
[MIME_MAX_TYPE
], /* Type for filter */
539 dsuper
[MIME_MAX_SUPER
], /* Destination super-type for filter */
540 dtype
[MIME_MAX_TYPE
], /* Destination type for filter */
541 dest
[MIME_MAX_SUPER
+ MIME_MAX_TYPE
+ 2],
542 /* Destination super/type */
543 program
[1024]; /* Program/filter name */
544 int cost
; /* Cost of filter */
545 size_t maxsize
= 0; /* Maximum supported file size */
546 mime_type_t
*temptype
, /* MIME type looping var */
547 *desttype
; /* Destination MIME type */
548 mime_filter_t
*filterptr
; /* MIME filter */
552 * Parse the filter string; it should be in one of the following formats:
554 * source/type cost program
555 * source/type cost maxsize(nnnn) program
556 * source/type dest/type cost program
557 * source/type dest/type cost maxsize(nnnn) program
560 if (sscanf(filter
, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
561 super
, type
, dsuper
, dtype
, &cost
, program
) == 6)
563 snprintf(dest
, sizeof(dest
), "%s/%s/%s", filtertype
->type
, dsuper
, dtype
);
565 if ((desttype
= mimeType(mime
, "printer", dest
)) == NULL
)
566 desttype
= mimeAddType(mime
, "printer", dest
);
570 if (sscanf(filter
, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super
, type
, &cost
,
573 desttype
= filtertype
;
577 _cupsLangPrintf(stderr
, _("%s: Invalid filter string \"%s\"."), command
,
583 if (!strncmp(program
, "maxsize(", 8))
585 char *ptr
; /* Pointer into maxsize(nnnn) program */
587 maxsize
= (size_t)strtoll(program
+ 8, &ptr
, 10);
591 printf("testmime: Invalid filter string \"%s\".\n", filter
);
596 while (_cups_isspace(*ptr
))
599 _cups_strcpy(program
, ptr
);
603 * See if the filter program exists; if not, stop the printer and flag
607 if (strcmp(program
, "-"))
609 char filename
[1024]; /* Full path to program */
611 if (program
[0] == '/')
612 strlcpy(filename
, program
, sizeof(filename
));
614 snprintf(filename
, sizeof(filename
), "%s/filter/%s", ServerBin
, program
);
616 if (_cupsFileCheck(filename
, _CUPS_FILE_CHECK_PROGRAM
, !geteuid(), check_cb
,
622 * Add the filter to the MIME database, supporting wildcards as needed...
625 for (temptype
= mimeFirstType(mime
);
627 temptype
= mimeNextType(mime
))
628 if (((super
[0] == '*' && _cups_strcasecmp(temptype
->super
, "printer")) ||
629 !_cups_strcasecmp(temptype
->super
, super
)) &&
630 (type
[0] == '*' || !_cups_strcasecmp(temptype
->type
, type
)))
632 if (desttype
!= filtertype
)
634 filterptr
= mimeAddFilter(mime
, temptype
, desttype
, cost
, program
);
636 if (!mimeFilterLookup(mime
, desttype
, filtertype
))
637 mimeAddFilter(mime
, desttype
, filtertype
, 0, "-");
640 filterptr
= mimeAddFilter(mime
, temptype
, filtertype
, cost
, program
);
643 filterptr
->maxsize
= maxsize
;
649 * 'add_printer_filters()' - Add filters from a PPD file.
652 static mime_type_t
* /* O - Printer type or NULL on error */
654 const char *command
, /* I - Command name */
655 mime_t
*mime
, /* I - MIME database */
656 const char *printer
, /* I - Printer name */
657 const char *ppdfile
, /* I - PPD file */
658 mime_type_t
**prefilter_type
) /* O - Prefilter type */
660 ppd_file_t
*ppd
; /* PPD file data */
661 _ppd_cache_t
*pc
; /* Cache data for PPD */
662 const char *value
; /* Filter definition value */
663 mime_type_t
*printer_type
; /* Printer filter type */
666 if ((ppd
= _ppdOpenFile(ppdfile
, _PPD_LOCALIZATION_NONE
)) == NULL
)
668 ppd_status_t status
; /* PPD load status */
669 int linenum
; /* Line number */
671 status
= ppdLastError(&linenum
);
672 _cupsLangPrintf(stderr
, _("%s: Unable to open PPD file: %s on line %d."),
673 command
, ppdErrorString(status
), linenum
);
677 pc
= _ppdCacheCreateWithPPD(ppd
);
681 printer_type
= mimeAddType(mime
, "printer", printer
);
682 *prefilter_type
= NULL
;
686 for (value
= (const char *)cupsArrayFirst(pc
->filters
);
688 value
= (const char *)cupsArrayNext(pc
->filters
))
689 add_printer_filter(command
, mime
, printer_type
, value
);
693 add_printer_filter(command
, mime
, printer_type
,
694 "application/vnd.cups-raw 0 -");
695 add_printer_filter(command
, mime
, printer_type
,
696 "application/vnd.cups-postscript 0 -");
701 *prefilter_type
= mimeAddType(mime
, "prefilter", printer
);
703 for (value
= (const char *)cupsArrayFirst(pc
->prefilters
);
705 value
= (const char *)cupsArrayNext(pc
->prefilters
))
706 add_printer_filter(command
, mime
, *prefilter_type
, value
);
709 return (printer_type
);
714 * 'check_cb()' - Callback function for _cupsFileCheck.
718 check_cb(void *context
, /* I - Context (command name) */
719 _cups_fc_result_t result
, /* I - Result of check */
720 const char *message
) /* I - Localized message */
724 _cupsLangPrintf(stderr
, _("%s: %s"), (char *)context
, message
);
729 * 'compare_pids()' - Compare two filter PIDs...
732 static int /* O - Result of comparison */
733 compare_pids(mime_filter_t
*a
, /* I - First filter */
734 mime_filter_t
*b
) /* I - Second filter */
737 * Because we're particularly lazy, we store the process ID in the "cost"
741 return (a
->cost
- b
->cost
);
746 * 'escape_options()' - Convert an options array to a string.
749 static char * /* O - Option string */
751 int num_options
, /* I - Number of options */
752 cups_option_t
*options
) /* I - Options */
754 int i
; /* Looping var */
755 cups_option_t
*option
; /* Current option */
756 size_t bytes
; /* Number of bytes needed */
757 char *s
, /* Option string */
758 *sptr
, /* Pointer into string */
759 *vptr
; /* Pointer into value */
763 * Figure out the worst-case number of bytes we need for the option string.
766 for (i
= num_options
, option
= options
, bytes
= 1; i
> 0; i
--, option
++)
767 bytes
+= 2 * (strlen(option
->name
) + strlen(option
->value
)) + 2;
769 if ((s
= malloc(bytes
)) == NULL
)
773 * Copy the options to the string...
776 for (i
= num_options
, option
= options
, sptr
= s
; i
> 0; i
--, option
++)
778 if (!strcmp(option
->name
, "copies"))
784 strlcpy(sptr
, option
->name
, bytes
- (size_t)(sptr
- s
));
785 sptr
+= strlen(sptr
);
788 for (vptr
= option
->value
; *vptr
;)
790 if (strchr("\\ \t\n", *vptr
))
804 * 'exec_filter()' - Execute a single filter.
807 static int /* O - Process ID or -1 on error */
808 exec_filter(const char *filter
, /* I - Filter to execute */
809 char **argv
, /* I - Argument list */
810 char **envp
, /* I - Environment list */
811 int infd
, /* I - Stdin file descriptor */
812 int outfd
) /* I - Stdout file descriptor */
814 int pid
, /* Process ID */
815 fd
; /* Temporary file descriptor */
816 #if defined(__APPLE__)
817 char processPath
[1024], /* CFProcessPath environment variable */
818 linkpath
[1024]; /* Link path for symlinks... */
819 int linkbytes
; /* Bytes for link path */
823 * Add special voodoo magic for MacOS X - this allows MacOS X
824 * programs to access their bundle resources properly...
827 if ((linkbytes
= readlink(filter
, linkpath
, sizeof(linkpath
) - 1)) > 0)
830 * Yes, this is a symlink to the actual program, nul-terminate and
834 linkpath
[linkbytes
] = '\0';
836 if (linkpath
[0] == '/')
837 snprintf(processPath
, sizeof(processPath
), "CFProcessPath=%s",
840 snprintf(processPath
, sizeof(processPath
), "CFProcessPath=%s/%s",
841 dirname((char *)filter
), linkpath
);
844 snprintf(processPath
, sizeof(processPath
), "CFProcessPath=%s", filter
);
846 envp
[0] = processPath
; /* Replace <CFProcessPath> string */
847 #endif /* __APPLE__ */
849 if ((pid
= fork()) == 0)
852 * Child process goes here...
854 * Update stdin/stdout/stderr as needed...
860 infd
= open("/dev/null", O_RDONLY
);
872 outfd
= open("/dev/null", O_WRONLY
);
881 if ((fd
= open("/dev/null", O_RDWR
)) > 3)
886 fcntl(3, F_SETFL
, O_NDELAY
);
888 if ((fd
= open("/dev/null", O_RDWR
)) > 4)
893 fcntl(4, F_SETFL
, O_NDELAY
);
899 execve(filter
, argv
, envp
);
911 * 'exec_filters()' - Execute filters for the given file and options.
914 static int /* O - 0 on success, 1 on error */
915 exec_filters(mime_type_t
*srctype
, /* I - Source type */
916 cups_array_t
*filters
, /* I - Array of filters to run */
917 const char *infile
, /* I - File to filter */
918 const char *outfile
, /* I - File to create */
919 const char *ppdfile
, /* I - PPD file, if any */
920 const char *printer
, /* I - Printer name */
921 const char *user
, /* I - Username */
922 const char *title
, /* I - Job title */
923 int num_options
, /* I - Number of filter options */
924 cups_option_t
*options
) /* I - Filter options */
926 int i
; /* Looping var */
927 const char *argv
[8], /* Command-line arguments */
928 *envp
[17], /* Environment variables */
929 *temp
; /* Temporary string */
930 char *optstr
, /* Filter options */
931 content_type
[1024], /* CONTENT_TYPE */
932 cups_datadir
[1024], /* CUPS_DATADIR */
933 cups_fontpath
[1024], /* CUPS_FONTPATH */
934 cups_serverbin
[1024], /* CUPS_SERVERBIN */
935 cups_serverroot
[1024], /* CUPS_SERVERROOT */
936 final_content_type
[1024] = "",
937 /* FINAL_CONTENT_TYPE */
938 lang
[1024], /* LANG */
939 path
[1024], /* PATH */
941 printer_info
[255], /* PRINTER_INFO env variable */
942 printer_location
[255], /* PRINTER_LOCATION env variable */
943 printer_name
[255], /* PRINTER env variable */
944 rip_max_cache
[1024], /* RIP_MAX_CACHE */
945 userenv
[1024], /* USER */
946 program
[1024]; /* Program to run */
947 mime_filter_t
*filter
, /* Current filter */
948 *next
; /* Next filter */
949 int current
, /* Current filter */
950 filterfds
[2][2], /* Pipes for filters */
951 pid
, /* Process ID of filter */
952 status
, /* Exit status */
953 retval
; /* Return value */
954 cups_array_t
*pids
; /* Executed filters array */
955 mime_filter_t key
; /* Search key for filters */
956 cups_lang_t
*language
; /* Current language */
957 cups_dest_t
*dest
; /* Destination information */
961 * Figure out the final content type...
964 for (filter
= (mime_filter_t
*)cupsArrayLast(filters
);
965 filter
&& filter
->dst
;
966 filter
= (mime_filter_t
*)cupsArrayPrev(filters
))
967 if (strcmp(filter
->dst
->super
, "printer"))
970 if (filter
&& filter
->dst
)
972 const char *ptr
; /* Pointer in type name */
974 if ((ptr
= strchr(filter
->dst
->type
, '/')) != NULL
)
975 snprintf(final_content_type
, sizeof(final_content_type
),
976 "FINAL_CONTENT_TYPE=%s", ptr
+ 1);
978 snprintf(final_content_type
, sizeof(final_content_type
),
979 "FINAL_CONTENT_TYPE=%s/%s", filter
->dst
->super
,
984 * Remove NULL ("-") filters...
987 for (filter
= (mime_filter_t
*)cupsArrayFirst(filters
);
989 filter
= (mime_filter_t
*)cupsArrayNext(filters
))
990 if (!strcmp(filter
->filter
, "-"))
991 cupsArrayRemove(filters
, filter
);
994 * Setup the filter environment and command-line...
997 optstr
= escape_options(num_options
, options
);
999 snprintf(content_type
, sizeof(content_type
), "CONTENT_TYPE=%s/%s",
1000 srctype
->super
, srctype
->type
);
1001 snprintf(cups_datadir
, sizeof(cups_datadir
), "CUPS_DATADIR=%s", DataDir
);
1002 snprintf(cups_fontpath
, sizeof(cups_fontpath
), "CUPS_FONTPATH=%s", FontPath
);
1003 snprintf(cups_serverbin
, sizeof(cups_serverbin
), "CUPS_SERVERBIN=%s",
1005 snprintf(cups_serverroot
, sizeof(cups_serverroot
), "CUPS_SERVERROOT=%s",
1007 language
= cupsLangDefault();
1008 snprintf(lang
, sizeof(lang
), "LANG=%s.UTF8", language
->language
);
1009 snprintf(path
, sizeof(path
), "PATH=%s", Path
);
1011 snprintf(ppd
, sizeof(ppd
), "PPD=%s", ppdfile
);
1012 else if ((temp
= getenv("PPD")) != NULL
)
1013 snprintf(ppd
, sizeof(ppd
), "PPD=%s", temp
);
1016 if (!access("/System/Library/Frameworks/ApplicationServices.framework/"
1017 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
1018 "Resources/English.lproj/Generic.ppd", 0))
1019 strlcpy(ppd
, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
1020 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
1021 "Resources/English.lproj/Generic.ppd", sizeof(ppd
));
1023 strlcpy(ppd
, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
1024 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
1025 "Resources/Generic.ppd", sizeof(ppd
));
1027 snprintf(ppd
, sizeof(ppd
), "PPD=%s/model/laserjet.ppd", DataDir
);
1028 #endif /* __APPLE__ */
1029 snprintf(rip_max_cache
, sizeof(rip_max_cache
), "RIP_MAX_CACHE=%s", RIPCache
);
1030 snprintf(userenv
, sizeof(userenv
), "USER=%s", user
);
1033 (dest
= cupsGetNamedDest(CUPS_HTTP_DEFAULT
, printer
, NULL
)) != NULL
)
1035 if ((temp
= cupsGetOption("printer-info", dest
->num_options
,
1036 dest
->options
)) != NULL
)
1037 snprintf(printer_info
, sizeof(printer_info
), "PRINTER_INFO=%s", temp
);
1039 snprintf(printer_info
, sizeof(printer_info
), "PRINTER_INFO=%s", printer
);
1041 if ((temp
= cupsGetOption("printer-location", dest
->num_options
,
1042 dest
->options
)) != NULL
)
1043 snprintf(printer_location
, sizeof(printer_location
),
1044 "PRINTER_LOCATION=%s", temp
);
1046 strlcpy(printer_location
, "PRINTER_LOCATION=Unknown",
1047 sizeof(printer_location
));
1051 snprintf(printer_info
, sizeof(printer_info
), "PRINTER_INFO=%s",
1052 printer
? printer
: "Unknown");
1053 strlcpy(printer_location
, "PRINTER_LOCATION=Unknown",
1054 sizeof(printer_location
));
1057 snprintf(printer_name
, sizeof(printer_name
), "PRINTER=%s",
1058 printer
? printer
: "Unknown");
1060 argv
[0] = (char *)printer
;
1064 argv
[4] = cupsGetOption("copies", num_options
, options
);
1072 envp
[0] = "<CFProcessPath>";
1073 envp
[1] = content_type
;
1074 envp
[2] = cups_datadir
;
1075 envp
[3] = cups_fontpath
;
1076 envp
[4] = cups_serverbin
;
1077 envp
[5] = cups_serverroot
;
1081 envp
[9] = printer_info
;
1082 envp
[10] = printer_location
;
1083 envp
[11] = printer_name
;
1084 envp
[12] = rip_max_cache
;
1086 envp
[14] = "CHARSET=utf-8";
1087 if (final_content_type
[0])
1089 envp
[15] = final_content_type
;
1095 for (i
= 0; argv
[i
]; i
++)
1096 fprintf(stderr
, "DEBUG: argv[%d]=\"%s\"\n", i
, argv
[i
]);
1098 for (i
= 0; envp
[i
]; i
++)
1099 fprintf(stderr
, "DEBUG: envp[%d]=\"%s\"\n", i
, envp
[i
]);
1102 * Execute all of the filters...
1105 pids
= cupsArrayNew((cups_array_func_t
)compare_pids
, NULL
);
1107 filterfds
[0][0] = -1;
1108 filterfds
[0][1] = -1;
1109 filterfds
[1][0] = -1;
1110 filterfds
[1][1] = -1;
1113 filterfds
[0][0] = 0;
1115 for (filter
= (mime_filter_t
*)cupsArrayFirst(filters
);
1117 filter
= next
, current
= 1 - current
)
1119 next
= (mime_filter_t
*)cupsArrayNext(filters
);
1121 if (filter
->filter
[0] == '/')
1122 strlcpy(program
, filter
->filter
, sizeof(program
));
1124 snprintf(program
, sizeof(program
), "%s/filter/%s", ServerBin
,
1127 if (filterfds
[!current
][1] > 1)
1129 close(filterfds
[1 - current
][0]);
1130 close(filterfds
[1 - current
][1]);
1132 filterfds
[1 - current
][0] = -1;
1133 filterfds
[1 - current
][0] = -1;
1137 open_pipe(filterfds
[1 - current
]);
1140 filterfds
[1 - current
][1] = open(outfile
, O_CREAT
| O_TRUNC
| O_WRONLY
,
1143 if (filterfds
[1 - current
][1] < 0)
1144 fprintf(stderr
, "ERROR: Unable to create \"%s\" - %s\n", outfile
,
1148 filterfds
[1 - current
][1] = 1;
1150 pid
= exec_filter(program
, (char **)argv
, (char **)envp
,
1151 filterfds
[current
][0], filterfds
[1 - current
][1]);
1155 fprintf(stderr
, "INFO: %s (PID %d) started.\n", filter
->filter
, pid
);
1158 cupsArrayAdd(pids
, filter
);
1167 * Close remaining pipes...
1170 if (filterfds
[0][1] > 1)
1172 close(filterfds
[0][0]);
1173 close(filterfds
[0][1]);
1176 if (filterfds
[1][1] > 1)
1178 close(filterfds
[1][0]);
1179 close(filterfds
[1][1]);
1183 * Wait for the children to exit...
1188 while (cupsArrayCount(pids
) > 0)
1190 if ((pid
= wait(&status
)) < 0)
1194 if ((filter
= (mime_filter_t
*)cupsArrayFind(pids
, &key
)) != NULL
)
1196 cupsArrayRemove(pids
, filter
);
1200 if (WIFEXITED(status
))
1201 fprintf(stderr
, "ERROR: %s (PID %d) stopped with status %d\n",
1202 filter
->filter
, pid
, WEXITSTATUS(status
));
1204 fprintf(stderr
, "ERROR: %s (PID %d) crashed on signal %d\n",
1205 filter
->filter
, pid
, WTERMSIG(status
));
1210 fprintf(stderr
, "INFO: %s (PID %d) exited with no errors.\n",
1211 filter
->filter
, pid
);
1215 cupsArrayDelete(pids
);
1222 * 'get_job_file()' - Get the specified job file.
1226 get_job_file(const char *job
) /* I - Job ID */
1228 long jobid
, /* Job ID */
1229 docnum
; /* Document number */
1230 const char *jobptr
; /* Pointer into job ID string */
1231 char uri
[1024]; /* job-uri */
1232 http_t
*http
; /* Connection to server */
1233 ipp_t
*request
; /* Request data */
1234 int tempfd
; /* Temporary file */
1238 * Get the job ID and document number, if any...
1241 if ((jobptr
= strrchr(job
, '-')) != NULL
)
1246 jobid
= strtol(jobptr
, (char **)&jobptr
, 10);
1249 docnum
= strtol(jobptr
+ 1, NULL
, 10);
1253 if (jobid
< 1 || jobid
> INT_MAX
)
1255 _cupsLangPrintf(stderr
, _("cupsfilter: Invalid job ID %d."), (int)jobid
);
1259 if (docnum
< 1 || docnum
> INT_MAX
)
1261 _cupsLangPrintf(stderr
, _("cupsfilter: Invalid document number %d."),
1267 * Ask the server for the document file...
1270 if ((http
= httpConnectEncrypt(cupsServer(), ippPort(),
1271 cupsEncryption())) == NULL
)
1273 _cupsLangPrintf(stderr
, _("%s: Unable to connect to server."),
1278 request
= ippNewRequest(CUPS_GET_DOCUMENT
);
1280 snprintf(uri
, sizeof(uri
), "ipp://localhost/jobs/%d", (int)jobid
);
1282 ippAddString(request
, IPP_TAG_OPERATION
, IPP_TAG_URI
, "job-uri", NULL
, uri
);
1283 ippAddInteger(request
, IPP_TAG_OPERATION
, IPP_TAG_INTEGER
, "document-number",
1286 if ((tempfd
= cupsTempFd(TempFile
, sizeof(TempFile
))) == -1)
1288 _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
1293 signal(SIGTERM
, sighandler
);
1295 ippDelete(cupsDoIORequest(http
, request
, "/", -1, tempfd
));
1301 if (cupsLastError() != IPP_OK
)
1303 _cupsLangPrintf(stderr
, _("cupsfilter: Unable to get job file - %s"),
1304 cupsLastErrorString());
1312 * 'open_pipe()' - Create a pipe which is closed on exec.
1315 static int /* O - 0 on success, -1 on error */
1316 open_pipe(int *fds
) /* O - Pipe file descriptors (2) */
1319 * Create the pipe...
1331 * Set the "close on exec" flag on each end of the pipe...
1334 if (fcntl(fds
[0], F_SETFD
, fcntl(fds
[0], F_GETFD
) | FD_CLOEXEC
))
1345 if (fcntl(fds
[1], F_SETFD
, fcntl(fds
[1], F_GETFD
) | FD_CLOEXEC
))
1357 * Return 0 indicating success...
1365 * 'read_cups_files_conf()' - Read the cups-files.conf file to get the filter settings.
1368 static int /* O - 0 on success, 1 on error */
1369 read_cups_files_conf(
1370 const char *filename
) /* I - File to read */
1372 cups_file_t
*fp
; /* cups-files.conf file */
1373 const char *temp
; /* Temporary string */
1374 char line
[1024], /* Line from file */
1375 *ptr
; /* Pointer into line */
1376 int linenum
; /* Current line number */
1379 if ((temp
= getenv("CUPS_DATADIR")) != NULL
)
1380 set_string(&DataDir
, temp
);
1382 set_string(&DataDir
, CUPS_DATADIR
);
1384 if ((temp
= getenv("CUPS_FONTPATH")) != NULL
)
1385 set_string(&FontPath
, temp
);
1387 set_string(&FontPath
, CUPS_FONTPATH
);
1389 set_string(&RIPCache
, "128m");
1391 if ((temp
= getenv("CUPS_SERVERBIN")) != NULL
)
1392 set_string(&ServerBin
, temp
);
1394 set_string(&ServerBin
, CUPS_SERVERBIN
);
1396 strlcpy(line
, filename
, sizeof(line
));
1397 if ((ptr
= strrchr(line
, '/')) != NULL
)
1400 getcwd(line
, sizeof(line
));
1402 set_string(&ServerRoot
, line
);
1404 if ((fp
= cupsFileOpen(filename
, "r")) != NULL
)
1408 while (cupsFileGetConf(fp
, line
, sizeof(line
), &ptr
, &linenum
))
1410 if (!_cups_strcasecmp(line
, "DataDir"))
1411 set_string(&DataDir
, ptr
);
1412 else if (!_cups_strcasecmp(line
, "FontPath"))
1413 set_string(&FontPath
, ptr
);
1414 else if (!_cups_strcasecmp(line
, "RIPCache"))
1415 set_string(&RIPCache
, ptr
);
1416 else if (!_cups_strcasecmp(line
, "ServerBin"))
1417 set_string(&ServerBin
, ptr
);
1418 else if (!_cups_strcasecmp(line
, "ServerRoot"))
1419 set_string(&ServerRoot
, ptr
);
1425 snprintf(line
, sizeof(line
), "%s/filter:" CUPS_BINDIR
":" CUPS_SBINDIR
":/bin:/usr/bin", ServerBin
);
1426 set_string(&Path
, line
);
1433 * 'set_string()' - Copy and set a string.
1437 set_string(char **s
, /* O - Copy of string */
1438 const char *val
) /* I - String to copy */
1448 * 'sighandler()' - Signal catcher for when we print from stdin...
1452 sighandler(int s
) /* I - Signal number */
1455 * Remove the temporary file we're using to print a job file...
1470 * 'usage()' - Show program usage...
1474 usage(const char *opt
) /* I - Incorrect option, if any */
1477 _cupsLangPrintf(stderr
, _("%s: Unknown option \"%c\"."), "cupsfilter", *opt
);
1479 _cupsLangPuts(stdout
, _("Usage: cupsfilter [ options ] [ -- ] filename"));
1480 _cupsLangPuts(stdout
, _("Options:"));
1481 _cupsLangPuts(stdout
, _(" --list-filters List filters that will be used."));
1482 _cupsLangPuts(stdout
, _(" -D Remove the input file when finished."));
1483 _cupsLangPuts(stdout
, _(" -P filename.ppd Set PPD file."));
1484 _cupsLangPuts(stdout
, _(" -U username Specify username."));
1485 _cupsLangPuts(stdout
, _(" -c cups-files.conf Set cups-files.conf file to use."));
1486 _cupsLangPuts(stdout
, _(" -d printer Use the named printer."));
1487 _cupsLangPuts(stdout
, _(" -e Use every filter from the PPD file."));
1488 _cupsLangPuts(stdout
, _(" -i mime/type Set input MIME type (otherwise auto-typed)."));
1489 _cupsLangPuts(stdout
, _(" -j job-id[,N] Filter file N from the specified job (default is file 1)."));
1490 _cupsLangPuts(stdout
, _(" -m mime/type Set output MIME type (otherwise application/pdf)."));
1491 _cupsLangPuts(stdout
, _(" -n copies Set number of copies."));
1492 _cupsLangPuts(stdout
, _(" -o name=value Set option(s)."));
1493 _cupsLangPuts(stdout
, _(" -p filename.ppd Set PPD file."));
1494 _cupsLangPuts(stdout
, _(" -t title Set title."));
1495 _cupsLangPuts(stdout
, _(" -u Remove the PPD file when finished."));