]>
Commit | Line | Data |
---|---|---|
91c84a35 MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
4 | * PDF to PostScript filter front-end for the Common UNIX Printing | |
5 | * System (CUPS). | |
6 | * | |
7 | * Copyright 2007-2008 by Apple Inc. | |
8 | * Copyright 1997-2006 by Easy Software Products. | |
9 | * | |
10 | * These coded instructions, statements, and computer programs are the | |
11 | * property of Apple Inc. and are protected by Federal copyright | |
12 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
13 | * which should have been included with this file. If this file is | |
14 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
15 | * | |
16 | * Contents: | |
17 | * | |
18 | * main() - Main entry for filter... | |
19 | * cancel_job() - Flag the job as canceled. | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Include necessary headers... | |
24 | */ | |
25 | ||
26 | #include <cups/cups.h> | |
27 | #include <cups/string.h> | |
28 | #include <cups/i18n.h> | |
29 | #include <signal.h> | |
30 | #include <sys/wait.h> | |
839a51c8 | 31 | #include <errno.h> |
91c84a35 MS |
32 | |
33 | ||
34 | /* | |
35 | * Local functions... | |
36 | */ | |
37 | ||
38 | static void cancel_job(int sig); | |
39 | ||
40 | ||
839a51c8 MS |
41 | /* |
42 | * Local globals... | |
43 | */ | |
44 | ||
45 | static int job_canceled = 0; | |
46 | ||
47 | ||
91c84a35 MS |
48 | /* |
49 | * 'main()' - Main entry for filter... | |
50 | */ | |
51 | ||
52 | int /* O - Exit status */ | |
53 | main(int argc, /* I - Number of command-line args */ | |
54 | char *argv[]) /* I - Command-line arguments */ | |
55 | { | |
56 | int fd; /* Copy file descriptor */ | |
57 | char *filename, /* PDF file to convert */ | |
58 | tempfile[1024]; /* Temporary file */ | |
59 | char buffer[8192]; /* Copy buffer */ | |
60 | int bytes; /* Bytes copied */ | |
61 | int num_options; /* Number of options */ | |
62 | cups_option_t *options; /* Options */ | |
63 | const char *val; /* Option value */ | |
64 | int orientation; /* Output orientation */ | |
65 | ppd_file_t *ppd; /* PPD file */ | |
66 | ppd_size_t *size; /* Current page size */ | |
67 | int pdfpid, /* Process ID for pdftops */ | |
839a51c8 | 68 | pdfwaitpid, /* Process ID from wait() */ |
91c84a35 MS |
69 | pdfstatus, /* Status from pdftops */ |
70 | pdfargc; /* Number of args for pdftops */ | |
ae71f5de MS |
71 | char *pdfargv[100], /* Arguments for pdftops/gs */ |
72 | #ifdef HAVE_PDFTOPS | |
91c84a35 MS |
73 | pdfwidth[255], /* Paper width */ |
74 | pdfheight[255]; /* Paper height */ | |
ae71f5de MS |
75 | #else |
76 | pdfgeometry[255]; /* Paper width and height */ | |
77 | #endif /* HAVE_PDFTOPS */ | |
91c84a35 MS |
78 | #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) |
79 | struct sigaction action; /* Actions for POSIX signals */ | |
80 | #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ | |
81 | ||
82 | ||
83 | /* | |
84 | * Make sure status messages are not buffered... | |
85 | */ | |
86 | ||
87 | setbuf(stderr, NULL); | |
88 | ||
89 | /* | |
90 | * Make sure we have the right number of arguments for CUPS! | |
91 | */ | |
92 | ||
93 | if (argc < 6 || argc > 7) | |
94 | { | |
95 | _cupsLangPrintf(stderr, | |
96 | _("Usage: %s job user title copies options [filename]\n"), | |
97 | argv[0]); | |
98 | return (1); | |
99 | } | |
100 | ||
101 | /* | |
102 | * Register a signal handler to cleanly cancel a job. | |
103 | */ | |
104 | ||
105 | #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ | |
106 | sigset(SIGTERM, cancel_job); | |
107 | #elif defined(HAVE_SIGACTION) | |
108 | memset(&action, 0, sizeof(action)); | |
109 | ||
110 | sigemptyset(&action.sa_mask); | |
111 | action.sa_handler = cancel_job; | |
112 | sigaction(SIGTERM, &action, NULL); | |
113 | #else | |
114 | signal(SIGTERM, cancel_job); | |
115 | #endif /* HAVE_SIGSET */ | |
116 | ||
117 | /* | |
118 | * Copy stdin if needed... | |
119 | */ | |
120 | ||
121 | if (argc == 6) | |
122 | { | |
123 | /* | |
124 | * Copy stdin to a temp file... | |
125 | */ | |
126 | ||
127 | if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) | |
128 | { | |
129 | _cupsLangPrintError(_("ERROR: Unable to copy PDF file")); | |
130 | return (1); | |
131 | } | |
132 | ||
133 | fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n", | |
134 | tempfile); | |
135 | ||
136 | while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) | |
137 | write(fd, buffer, bytes); | |
138 | ||
139 | close(fd); | |
140 | ||
141 | filename = tempfile; | |
142 | } | |
143 | else | |
144 | { | |
145 | /* | |
146 | * Use the filename on the command-line... | |
147 | */ | |
148 | ||
149 | filename = argv[6]; | |
150 | tempfile[0] = '\0'; | |
151 | } | |
152 | ||
153 | /* | |
154 | * Load the PPD file and mark options... | |
155 | */ | |
156 | ||
157 | ppd = ppdOpenFile(getenv("PPD")); | |
158 | num_options = cupsParseOptions(argv[5], 0, &options); | |
159 | ||
160 | ppdMarkDefaults(ppd); | |
161 | cupsMarkOptions(ppd, num_options, options); | |
162 | ||
163 | /* | |
ae71f5de | 164 | * Build the command-line for the pdftops or gs filter... |
91c84a35 MS |
165 | */ |
166 | ||
ae71f5de | 167 | #ifdef HAVE_PDFTOPS |
91c84a35 MS |
168 | pdfargv[0] = (char *)"pdftops"; |
169 | pdfargc = 1; | |
ae71f5de MS |
170 | #else |
171 | pdfargv[0] = (char *)"gs"; | |
172 | pdfargv[1] = (char *)"-q"; | |
173 | pdfargv[2] = (char *)"-dNOPAUSE"; | |
174 | pdfargv[3] = (char *)"-dBATCH"; | |
175 | pdfargv[4] = (char *)"-dSAFER"; | |
176 | pdfargv[5] = (char *)"-sDEVICE=pswrite"; | |
177 | pdfargv[6] = (char *)"-sOUTPUTFILE=%stdout"; | |
178 | pdfargc = 7; | |
179 | #endif /* HAVE_PDFTOPS */ | |
91c84a35 MS |
180 | |
181 | if (ppd) | |
182 | { | |
183 | /* | |
184 | * Set language level and TrueType font handling... | |
185 | */ | |
186 | ||
187 | if (ppd->language_level == 1) | |
188 | { | |
ae71f5de | 189 | #ifdef HAVE_PDFTOPS |
91c84a35 MS |
190 | pdfargv[pdfargc++] = (char *)"-level1"; |
191 | pdfargv[pdfargc++] = (char *)"-noembtt"; | |
ae71f5de MS |
192 | #else |
193 | pdfargv[pdfargc++] = (char *)"-dLanguageLevel=1"; | |
194 | #endif /* HAVE_PDFTOPS */ | |
91c84a35 MS |
195 | } |
196 | else if (ppd->language_level == 2) | |
197 | { | |
ae71f5de | 198 | #ifdef HAVE_PDFTOPS |
91c84a35 MS |
199 | pdfargv[pdfargc++] = (char *)"-level2"; |
200 | if (!ppd->ttrasterizer) | |
201 | pdfargv[pdfargc++] = (char *)"-noembtt"; | |
ae71f5de MS |
202 | #else |
203 | pdfargv[pdfargc++] = (char *)"-dLanguageLevel=2"; | |
204 | #endif /* HAVE_PDFTOPS */ | |
91c84a35 MS |
205 | } |
206 | else | |
ae71f5de | 207 | #ifdef HAVE_PDFTOPS |
91c84a35 | 208 | pdfargv[pdfargc++] = (char *)"-level3"; |
ae71f5de MS |
209 | #else |
210 | pdfargv[pdfargc++] = (char *)"-dLanguageLevel=3"; | |
211 | #endif /* HAVE_PDFTOPS */ | |
91c84a35 MS |
212 | |
213 | /* | |
214 | * Set output page size... | |
215 | */ | |
216 | ||
217 | size = ppdPageSize(ppd, NULL); | |
218 | if (size) | |
219 | { | |
220 | /* | |
221 | * Got the size, now get the orientation... | |
222 | */ | |
223 | ||
224 | orientation = 0; | |
225 | ||
226 | if ((val = cupsGetOption("landscape", num_options, options)) != NULL) | |
227 | { | |
228 | if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 && | |
229 | strcasecmp(val, "false") != 0) | |
230 | orientation = 1; | |
231 | } | |
232 | else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL) | |
233 | { | |
234 | /* | |
235 | * Map IPP orientation values to 0 to 3: | |
236 | * | |
237 | * 3 = 0 degrees = 0 | |
238 | * 4 = 90 degrees = 1 | |
239 | * 5 = -90 degrees = 3 | |
240 | * 6 = 180 degrees = 2 | |
241 | */ | |
242 | ||
243 | orientation = atoi(val) - 3; | |
244 | if (orientation >= 2) | |
245 | orientation ^= 1; | |
246 | } | |
247 | ||
ae71f5de | 248 | #ifdef HAVE_PDFTOPS |
91c84a35 MS |
249 | if (orientation & 1) |
250 | { | |
50fe7201 MS |
251 | snprintf(pdfwidth, sizeof(pdfwidth), "%.0f", size->length); |
252 | snprintf(pdfheight, sizeof(pdfheight), "%.0f", size->width); | |
91c84a35 MS |
253 | } |
254 | else | |
255 | { | |
50fe7201 MS |
256 | snprintf(pdfwidth, sizeof(pdfwidth), "%.0f", size->width); |
257 | snprintf(pdfheight, sizeof(pdfheight), "%.0f", size->length); | |
91c84a35 MS |
258 | } |
259 | ||
260 | pdfargv[pdfargc++] = (char *)"-paperw"; | |
261 | pdfargv[pdfargc++] = pdfwidth; | |
262 | pdfargv[pdfargc++] = (char *)"-paperh"; | |
263 | pdfargv[pdfargc++] = pdfheight; | |
ae71f5de MS |
264 | #else |
265 | if (orientation & 1) | |
266 | snprintf(pdfgeometry, sizeof(pdfgeometry), "-g%.0fx%.0f", size->length, | |
267 | size->width); | |
268 | else | |
269 | snprintf(pdfgeometry, sizeof(pdfgeometry), "-g%.0fx%.0f", size->width, | |
270 | size->length); | |
271 | ||
272 | pdfargv[pdfargc++] = pdfgeometry; | |
273 | #endif /* HAVE_PDFTOPS */ | |
91c84a35 MS |
274 | } |
275 | } | |
276 | ||
ae71f5de | 277 | #ifdef HAVE_PDFTOPS |
91c84a35 MS |
278 | if ((val = cupsGetOption("fitplot", num_options, options)) != NULL && |
279 | strcasecmp(val, "no") && strcasecmp(val, "off") && | |
280 | strcasecmp(val, "false")) | |
281 | pdfargv[pdfargc++] = (char *)"-expand"; | |
282 | ||
283 | pdfargv[pdfargc++] = filename; | |
284 | pdfargv[pdfargc++] = (char *)"-"; | |
ae71f5de MS |
285 | #else |
286 | pdfargv[pdfargc++] = (char *)"-c"; | |
287 | pdfargv[pdfargc++] = (char *)"save pop"; | |
288 | pdfargv[pdfargc++] = (char *)"-f"; | |
289 | pdfargv[pdfargc++] = filename; | |
290 | #endif /* HAVE_PDFTOPS */ | |
291 | ||
292 | pdfargv[pdfargc] = NULL; | |
91c84a35 MS |
293 | |
294 | if ((pdfpid = fork()) == 0) | |
295 | { | |
296 | /* | |
297 | * Child comes here... | |
298 | */ | |
299 | ||
ae71f5de | 300 | #ifdef HAVE_PDFTOPS |
50fe7201 | 301 | execv(CUPS_PDFTOPS, pdfargv); |
ae71f5de MS |
302 | _cupsLangPrintError(_("ERROR: Unable to execute pdftops program")); |
303 | #else | |
304 | execv(CUPS_GHOSTSCRIPT, pdfargv); | |
305 | _cupsLangPrintError(_("ERROR: Unable to execute gs program")); | |
306 | #endif /* HAVE_PDFTOPS */ | |
307 | ||
91c84a35 MS |
308 | exit(1); |
309 | } | |
310 | else if (pdfpid < 0) | |
311 | { | |
312 | /* | |
313 | * Unable to fork! | |
314 | */ | |
315 | ||
ae71f5de MS |
316 | #ifdef HAVE_PDFTOPS |
317 | _cupsLangPrintError(_("ERROR: Unable to execute pdftops program")); | |
318 | #else | |
319 | _cupsLangPrintError(_("ERROR: Unable to execute gs program")); | |
320 | #endif /* HAVE_PDFTOPS */ | |
321 | ||
91c84a35 MS |
322 | pdfstatus = 1; |
323 | } | |
324 | else | |
325 | { | |
326 | /* | |
327 | * Parent comes here... | |
328 | */ | |
329 | ||
3dfe78b3 | 330 | while ((pdfwaitpid = wait(&pdfstatus)) != pdfpid && errno == EINTR) |
839a51c8 MS |
331 | { |
332 | /* | |
333 | * Wait until we get a valid process ID or the job is canceled... | |
334 | */ | |
335 | ||
336 | if (job_canceled) | |
3dfe78b3 MS |
337 | { |
338 | kill(pdfpid, SIGTERM); | |
339 | job_canceled = 0; | |
340 | } | |
839a51c8 MS |
341 | } |
342 | ||
3dfe78b3 | 343 | if (pdfstatus) |
91c84a35 MS |
344 | { |
345 | if (WIFEXITED(pdfstatus)) | |
346 | { | |
839a51c8 | 347 | pdfstatus = WEXITSTATUS(pdfstatus); |
91c84a35 | 348 | |
839a51c8 MS |
349 | _cupsLangPrintf(stderr, |
350 | _("ERROR: pdftops filter exited with status %d!\n"), | |
91c84a35 MS |
351 | pdfstatus); |
352 | } | |
353 | else | |
354 | { | |
839a51c8 | 355 | pdfstatus = WTERMSIG(pdfstatus); |
91c84a35 | 356 | |
839a51c8 MS |
357 | _cupsLangPrintf(stderr, |
358 | _("ERROR: pdftops filter crashed on signal %d!\n"), | |
91c84a35 MS |
359 | pdfstatus); |
360 | } | |
361 | } | |
362 | } | |
363 | ||
364 | /* | |
365 | * Cleanup and exit... | |
366 | */ | |
367 | ||
368 | if (tempfile[0]) | |
369 | unlink(tempfile); | |
370 | ||
371 | return (pdfstatus); | |
372 | } | |
373 | ||
374 | ||
375 | /* | |
376 | * 'cancel_job()' - Flag the job as canceled. | |
377 | */ | |
378 | ||
379 | static void | |
380 | cancel_job(int sig) /* I - Signal number (unused) */ | |
381 | { | |
382 | (void)sig; | |
839a51c8 MS |
383 | |
384 | job_canceled = 1; | |
91c84a35 MS |
385 | } |
386 | ||
387 | ||
388 | /* | |
389 | * End of "$Id$". | |
390 | */ |