]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/cupsfilter.c
Merge changes from CUPS 1.5rc1-r9834.
[thirdparty/cups.git] / scheduler / cupsfilter.c
CommitLineData
bc44d920 1/*
b19ccc9e 2 * "$Id: cupsfilter.c 7952 2008-09-17 00:56:20Z mike $"
bc44d920 3 *
10d09e33 4 * Filtering program for CUPS.
bc44d920 5 *
84315f46 6 * Copyright 2007-2011 by Apple Inc.
bc44d920 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 *
eac3a0a0
MS
17 * main() - Main entry for the test program.
18 * add_printer_filter() - Add a single filters from a PPD file.
19 * add_printer_filters() - Add filters from a PPD file.
20 * check_cb() - Callback function for _cupsFileCheck.
21 * compare_pids() - Compare two filter PIDs...
22 * escape_options() - Convert an options array to a string.
23 * exec_filter() - Execute a single filter.
24 * exec_filters() - Execute filters for the given file and options.
25 * get_job_file() - Get the specified job file.
26 * open_pipe() - Create a pipe which is closed on exec.
27 * read_cupsd_conf() - Read the cupsd.conf file to get the filter
28 * settings.
29 * set_string() - Copy and set a string.
30 * sighandler() - Signal catcher for when we print from stdin...
31 * usage() - Show program usage...
bc44d920 32 */
33
34/*
35 * Include necessary headers...
36 */
37
71e16022 38#include <cups/cups-private.h>
eac3a0a0
MS
39#include <cups/file-private.h>
40#include <cups/ppd-private.h>
bc44d920 41#include "mime.h"
2e4ff8af 42#include <limits.h>
bc44d920 43#include <unistd.h>
44#include <fcntl.h>
2e4ff8af 45#include <signal.h>
bc44d920 46#include <sys/wait.h>
47#if defined(__APPLE__)
48# include <libgen.h>
88f9aafc 49#endif /* __APPLE__ */
bc44d920 50
51
52/*
53 * Local globals...
54 */
55
56static char *DataDir = NULL;/* CUPS_DATADIR environment variable */
57static char *FontPath = NULL;
58 /* CUPS_FONTPATH environment variable */
59static mime_filter_t GZIPFilter = /* gziptoany filter */
60{
61 NULL, /* Source type */
62 NULL, /* Destination type */
63 0, /* Cost */
64 "gziptoany" /* Filter program to run */
65};
66static char *Path = NULL; /* PATH environment variable */
67static char *ServerBin = NULL;
68 /* CUPS_SERVERBIN environment variable */
69static char *ServerRoot = NULL;
70 /* CUPS_SERVERROOT environment variable */
71static char *RIPCache = NULL;
71e16022 72 /* RIP_MAX_CACHE environment variable */
2e4ff8af
MS
73static char TempFile[1024] = "";
74 /* Temporary file */
bc44d920 75
76
77/*
78 * Local functions...
79 */
80
b19ccc9e
MS
81static void add_printer_filter(const char *command, mime_t *mime,
82 mime_type_t *printer_type,
83 const char *filter);
84static mime_type_t *add_printer_filters(const char *command,
85 mime_t *mime, const char *printer,
86 const char *ppdfile,
87 mime_type_t **prefilter_type);
eac3a0a0
MS
88static void check_cb(void *context, _cups_fc_result_t result,
89 const char *message);
b19ccc9e
MS
90static int compare_pids(mime_filter_t *a, mime_filter_t *b);
91static char *escape_options(int num_options, cups_option_t *options);
92static int exec_filter(const char *filter, char **argv,
93 char **envp, int infd, int outfd);
1340db2d
MS
94static int exec_filters(mime_type_t *srctype,
95 cups_array_t *filters, const char *infile,
b19ccc9e
MS
96 const char *outfile, const char *ppdfile,
97 const char *printer, const char *user,
98 const char *title, int num_options,
99 cups_option_t *options);
100static void get_job_file(const char *job);
101static int open_pipe(int *fds);
102static int read_cupsd_conf(const char *filename);
103static void set_string(char **s, const char *val);
104static void sighandler(int sig);
105static void usage(const char *command, const char *opt);
bc44d920 106
107
108/*
109 * 'main()' - Main entry for the test program.
110 */
111
112int /* O - Exit status */
113main(int argc, /* I - Number of command-line args */
114 char *argv[]) /* I - Command-line arguments */
115{
116 int i; /* Looping vars */
cc0d019f 117 const char *command, /* Command name */
b19ccc9e
MS
118 *opt, /* Current option */
119 *printer; /* Printer name */
120 mime_type_t *printer_type, /* Printer MIME type */
121 *prefilter_type; /* Printer prefilter MIME type */
cc0d019f
MS
122 char *srctype, /* Source type */
123 *dsttype, /* Destination type */
124 super[MIME_MAX_SUPER], /* Super-type name */
bc44d920 125 type[MIME_MAX_TYPE]; /* Type name */
126 int compression; /* Compression of file */
127 int cost; /* Cost of filters */
128 mime_t *mime; /* MIME database */
dd1abb6b 129 char mimedir[1024]; /* MIME directory */
cc0d019f
MS
130 char *infile, /* File to filter */
131 *outfile; /* File to create */
bc44d920 132 char cupsdconf[1024]; /* cupsd.conf file */
133 const char *server_root; /* CUPS_SERVERROOT environment variable */
134 mime_type_t *src, /* Source type */
135 *dst; /* Destination type */
136 cups_array_t *filters; /* Filters for the file */
137 int num_options; /* Number of options */
138 cups_option_t *options; /* Options */
139 const char *ppdfile; /* PPD file */
cc0d019f
MS
140 const char *title, /* Title string */
141 *user; /* Username */
1340db2d
MS
142 int all_filters, /* Use all filters */
143 removeppd, /* Remove PPD file */
cc0d019f
MS
144 removeinfile; /* Remove input file */
145 int status; /* Execution status */
bc44d920 146
147
148 /*
149 * Setup defaults...
150 */
151
cc0d019f
MS
152 if ((command = strrchr(argv[0], '/')) != NULL)
153 command ++;
154 else
155 command = argv[0];
156
b19ccc9e 157 printer = !strcmp(command, "convert") ? "tofile" : "cupsfilter";
cc0d019f
MS
158 mime = NULL;
159 srctype = NULL;
91c84a35 160 compression = 0;
cc0d019f
MS
161 dsttype = "application/pdf";
162 infile = NULL;
163 outfile = NULL;
164 num_options = 0;
165 options = NULL;
166 ppdfile = NULL;
167 title = NULL;
168 user = cupsUser();
1340db2d 169 all_filters = 0;
cc0d019f
MS
170 removeppd = 0;
171 removeinfile = 0;
bc44d920 172
173 if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
174 server_root = CUPS_SERVERROOT;
175
176 snprintf(cupsdconf, sizeof(cupsdconf), "%s/cupsd.conf", server_root);
177
178 /*
179 * Process command-line arguments...
180 */
181
182 _cupsSetLocale(argv);
183
184 for (i = 1; i < argc; i ++)
185 if (argv[i][0] == '-')
186 {
187 for (opt = argv[i] + 1; *opt; opt ++)
188 switch (*opt)
189 {
190 case '-' : /* Next argument is a filename... */
191 i ++;
cc0d019f
MS
192 if (i < argc && !infile)
193 infile = argv[i];
bc44d920 194 else
cc0d019f
MS
195 usage(command, opt);
196 break;
197
198 case 'a' : /* Specify option... */
199 i ++;
200 if (i < argc)
201 num_options = cupsParseOptions(argv[i], num_options, &options);
202 else
203 usage(command, opt);
bc44d920 204 break;
205
206 case 'c' : /* Specify cupsd.conf file location... */
207 i ++;
208 if (i < argc)
cc0d019f
MS
209 {
210 if (!strcmp(command, "convert"))
211 num_options = cupsAddOption("copies", argv[i], num_options,
212 &options);
213 else
214 strlcpy(cupsdconf, argv[i], sizeof(cupsdconf));
215 }
216 else
217 usage(command, opt);
218 break;
219
ba55dc12
MS
220 case 'd' : /* Specify the real printer name */
221 i ++;
222 if (i < argc)
223 printer = argv[i];
224 else
225 usage(command, opt);
226 break;
227
cc0d019f
MS
228 case 'D' : /* Delete input file after conversion */
229 removeinfile = 1;
230 break;
231
1340db2d
MS
232 case 'e' : /* Use every filter from the PPD file */
233 all_filters = 1;
234 break;
235
cc0d019f
MS
236 case 'f' : /* Specify input file... */
237 i ++;
238 if (i < argc && !infile)
239 infile = argv[i];
240 else
241 usage(command, opt);
242 break;
243
244 case 'i' : /* Specify source MIME type... */
245 i ++;
246 if (i < argc)
247 {
248 if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
249 usage(command, opt);
250
251 srctype = argv[i];
252 }
bc44d920 253 else
cc0d019f 254 usage(command, opt);
bc44d920 255 break;
256
2e4ff8af
MS
257 case 'j' : /* Get job file or specify destination MIME type... */
258 if (strcmp(command, "convert"))
259 {
260 i ++;
261 if (i < argc)
262 {
263 get_job_file(argv[i]);
264 infile = TempFile;
265 }
266 else
267 usage(command, opt);
268
269 break;
270 }
271
bc44d920 272 case 'm' : /* Specify destination MIME type... */
273 i ++;
274 if (i < argc)
275 {
276 if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
cc0d019f
MS
277 usage(command, opt);
278
279 dsttype = argv[i];
bc44d920 280 }
281 else
cc0d019f 282 usage(command, opt);
bc44d920 283 break;
284
285 case 'n' : /* Specify number of copies... */
286 i ++;
287 if (i < argc)
288 num_options = cupsAddOption("copies", argv[i], num_options,
289 &options);
290 else
cc0d019f 291 usage(command, opt);
bc44d920 292 break;
293
cc0d019f 294 case 'o' : /* Specify option(s) or output filename */
bc44d920 295 i ++;
296 if (i < argc)
cc0d019f
MS
297 {
298 if (!strcmp(command, "convert"))
299 {
300 if (outfile)
301 usage(command, NULL);
302 else
303 outfile = argv[i];
304 }
305 else
306 num_options = cupsParseOptions(argv[i], num_options,
307 &options);
308 }
bc44d920 309 else
cc0d019f 310 usage(command, opt);
bc44d920 311 break;
312
313 case 'p' : /* Specify PPD file... */
cc0d019f 314 case 'P' : /* Specify PPD file... */
bc44d920 315 i ++;
316 if (i < argc)
317 ppdfile = argv[i];
318 else
cc0d019f 319 usage(command, opt);
bc44d920 320 break;
321
cc0d019f
MS
322 case 't' : /* Specify title... */
323 case 'J' : /* Specify title... */
bc44d920 324 i ++;
325 if (i < argc)
326 title = argv[i];
327 else
cc0d019f
MS
328 usage(command, opt);
329 break;
330
331 case 'u' : /* Delete PPD file after conversion */
332 removeinfile = 1;
333 break;
334
335 case 'U' : /* Specify username... */
336 i ++;
337 if (i < argc)
338 user = argv[i];
339 else
340 usage(command, opt);
bc44d920 341 break;
342
343 default : /* Something we don't understand... */
cc0d019f 344 usage(command, opt);
bc44d920 345 break;
346 }
347 }
cc0d019f
MS
348 else if (!infile)
349 {
350 if (strcmp(command, "convert"))
351 infile = argv[i];
352 else
353 {
354 _cupsLangPuts(stderr,
355 _("convert: Use the -f option to specify a file to "
0837b7e8 356 "convert."));
cc0d019f
MS
357 usage(command, NULL);
358 }
359 }
bc44d920 360 else
361 {
362 _cupsLangPuts(stderr,
0837b7e8 363 _("cupsfilter: Only one filename can be specified."));
cc0d019f 364 usage(command, NULL);
bc44d920 365 }
366
cc0d019f
MS
367 if (!infile && !srctype)
368 usage(command, NULL);
bc44d920 369
370 if (!title)
371 {
cc0d019f
MS
372 if (!infile)
373 title = "(stdin)";
374 else if ((title = strrchr(infile, '/')) != NULL)
bc44d920 375 title ++;
376 else
cc0d019f 377 title = infile;
bc44d920 378 }
379
380 /*
381 * Load the cupsd.conf file and create the MIME database...
382 */
383
384 if (read_cupsd_conf(cupsdconf))
385 return (1);
386
75bd9771
MS
387 snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);
388
389 mime = mimeLoadTypes(NULL, mimedir);
390 mime = mimeLoadTypes(mime, ServerRoot);
391 mime = mimeLoadFilters(mime, mimedir, Path);
392 mime = mimeLoadFilters(mime, ServerRoot, Path);
393
394 if (!mime)
bc44d920 395 {
396 _cupsLangPrintf(stderr,
75bd9771 397 _("%s: Unable to read MIME database from \"%s\" or "
0837b7e8 398 "\"%s\"."),
75bd9771 399 command, mimedir, ServerRoot);
bc44d920 400 return (1);
401 }
402
f228370c
MS
403 prefilter_type = NULL;
404
1340db2d 405 if (all_filters)
1340db2d
MS
406 printer_type = add_printer_filters(command, mime, printer, ppdfile,
407 &prefilter_type);
1340db2d 408 else
1340db2d 409 printer_type = mimeType(mime, "application", "vnd.cups-postscript");
b19ccc9e 410
bc44d920 411 /*
412 * Get the source and destination types...
413 */
414
cc0d019f
MS
415 if (srctype)
416 {
417 sscanf(srctype, "%15[^/]/%255s", super, type);
418 if ((src = mimeType(mime, super, type)) == NULL)
419 {
420 _cupsLangPrintf(stderr,
0837b7e8 421 _("%s: Unknown source MIME type %s/%s."),
cc0d019f
MS
422 command, super, type);
423 return (1);
424 }
425 }
426 else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
bc44d920 427 {
428 _cupsLangPrintf(stderr,
0837b7e8 429 _("%s: Unable to determine MIME type of \"%s\"."),
cc0d019f 430 command, infile);
bc44d920 431 return (1);
432 }
433
cc0d019f 434 sscanf(dsttype, "%15[^/]/%255s", super, type);
88f9aafc 435 if (!_cups_strcasecmp(super, "printer"))
b19ccc9e
MS
436 dst = printer_type;
437 else if ((dst = mimeType(mime, super, type)) == NULL)
bc44d920 438 {
439 _cupsLangPrintf(stderr,
0837b7e8 440 _("%s: Unknown destination MIME type %s/%s."),
cc0d019f 441 command, super, type);
bc44d920 442 return (1);
443 }
444
445 /*
446 * Figure out how to filter the file...
447 */
448
449 if (src == dst)
450 {
451 /*
452 * Special case - no filtering needed...
453 */
454
455 filters = cupsArrayNew(NULL, NULL);
456 cupsArrayAdd(filters, &GZIPFilter);
1340db2d
MS
457 GZIPFilter.src = src;
458 GZIPFilter.dst = dst;
bc44d920 459 }
460 else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
461 {
462 _cupsLangPrintf(stderr,
0837b7e8 463 _("%s: No filter to convert from %s/%s to %s/%s."),
cc0d019f 464 command, src->super, src->type, dst->super, dst->type);
bc44d920 465 return (1);
466 }
467 else if (compression)
468 cupsArrayInsert(filters, &GZIPFilter);
469
b19ccc9e
MS
470 if (prefilter_type)
471 {
472 /*
473 * Add pre-filters...
474 */
475
476 mime_filter_t *filter, /* Current filter */
477 *prefilter; /* Current pre-filter */
478 cups_array_t *prefilters = cupsArrayNew(NULL, NULL);
479 /* New filters array */
480
481
482 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
483 filter;
484 filter = (mime_filter_t *)cupsArrayNext(filters))
485 {
1340db2d
MS
486 if ((prefilter = mimeFilterLookup(mime, filter->src,
487 prefilter_type)) != NULL)
b19ccc9e
MS
488 cupsArrayAdd(prefilters, prefilter);
489
490 cupsArrayAdd(prefilters, filter);
491 }
492
493 cupsArrayDelete(filters);
494 filters = prefilters;
495 }
496
bc44d920 497 /*
498 * Do it!
499 */
500
1340db2d 501 status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user,
b19ccc9e 502 title, num_options, options);
cc0d019f
MS
503
504 /*
505 * Remove files as needed, then exit...
506 */
507
2e4ff8af
MS
508 if (TempFile[0])
509 unlink(TempFile);
510
cc0d019f
MS
511 if (removeppd && ppdfile)
512 unlink(ppdfile);
513
514 if (removeinfile && infile)
515 unlink(infile);
516
517 return (status);
bc44d920 518}
519
520
b19ccc9e
MS
521/*
522 * 'add_printer_filter()' - Add a single filters from a PPD file.
523 */
524
525static void
526add_printer_filter(
527 const char *command, /* I - Command name */
528 mime_t *mime, /* I - MIME database */
529 mime_type_t *filtertype, /* I - Printer or prefilter MIME type */
530 const char *filter) /* I - Filter to add */
531{
532 char super[MIME_MAX_SUPER], /* Super-type for filter */
533 type[MIME_MAX_TYPE], /* Type for filter */
eac3a0a0
MS
534 dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
535 dtype[MIME_MAX_TYPE], /* Destination type for filter */
536 dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
537 /* Destination super/type */
b19ccc9e
MS
538 program[1024]; /* Program/filter name */
539 int cost; /* Cost of filter */
eac3a0a0
MS
540 size_t maxsize = 0; /* Maximum supported file size */
541 mime_type_t *temptype, /* MIME type looping var */
542 *desttype; /* Destination MIME type */
543 mime_filter_t *filterptr; /* MIME filter */
b19ccc9e
MS
544
545
546 /*
eac3a0a0 547 * Parse the filter string; it should be in one of the following formats:
b19ccc9e 548 *
eac3a0a0
MS
549 * source/type cost program
550 * source/type cost maxsize(nnnn) program
551 * source/type dest/type cost program
552 * source/type dest/type cost maxsize(nnnn) program
b19ccc9e
MS
553 */
554
eac3a0a0
MS
555 if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
556 super, type, dsuper, dtype, &cost, program) == 6)
b19ccc9e 557 {
eac3a0a0
MS
558 snprintf(dest, sizeof(dest), "%s/%s/%s", filtertype->type, dsuper, dtype);
559
560 if ((desttype = mimeType(mime, "printer", dest)) == NULL)
561 desttype = mimeAddType(mime, "printer", dest);
562 }
563 else
564 {
565 if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
566 program) == 4)
567 {
568 desttype = filtertype;
569 }
570 else
571 {
572 _cupsLangPrintf(stderr, _("%s: Invalid filter string \"%s\"."), command,
573 filter);
574 return;
575 }
576 }
577
578 if (!strncmp(program, "maxsize(", 8))
579 {
580 char *ptr; /* Pointer into maxsize(nnnn) program */
581
582 maxsize = strtoll(program + 8, &ptr, 10);
583
584 if (*ptr != ')')
585 {
586 printf("testmime: Invalid filter string \"%s\".\n", filter);
587 return;
588 }
589
590 ptr ++;
591 while (_cups_isspace(*ptr))
592 ptr ++;
593
594 _cups_strcpy(program, ptr);
b19ccc9e
MS
595 }
596
597 /*
598 * See if the filter program exists; if not, stop the printer and flag
599 * the error!
600 */
601
602 if (strcmp(program, "-"))
603 {
eac3a0a0
MS
604 char filename[1024]; /* Full path to program */
605
b19ccc9e
MS
606 if (program[0] == '/')
607 strlcpy(filename, program, sizeof(filename));
608 else
609 snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
610
eac3a0a0
MS
611 if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !geteuid(), check_cb,
612 (void *)command))
b19ccc9e 613 return;
b19ccc9e
MS
614 }
615
616 /*
617 * Add the filter to the MIME database, supporting wildcards as needed...
618 */
619
620 for (temptype = mimeFirstType(mime);
621 temptype;
622 temptype = mimeNextType(mime))
88f9aafc
MS
623 if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
624 !_cups_strcasecmp(temptype->super, super)) &&
625 (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
eac3a0a0
MS
626 {
627 if (desttype != filtertype)
628 {
629 filterptr = mimeAddFilter(mime, temptype, desttype, cost, program);
630
631 if (!mimeFilterLookup(mime, desttype, filtertype))
632 mimeAddFilter(mime, desttype, filtertype, cost, "-");
633 }
634 else
635 filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program);
636
637 if (filterptr)
638 filterptr->maxsize = maxsize;
639 }
b19ccc9e
MS
640}
641
642
643/*
644 * 'add_printer_filters()' - Add filters from a PPD file.
645 */
646
647static mime_type_t * /* O - Printer type or NULL on error */
648add_printer_filters(
649 const char *command, /* I - Command name */
650 mime_t *mime, /* I - MIME database */
651 const char *printer, /* I - Printer name */
652 const char *ppdfile, /* I - PPD file */
653 mime_type_t **prefilter_type) /* O - Prefilter type */
654{
eac3a0a0
MS
655 ppd_file_t *ppd; /* PPD file data */
656 _ppd_cache_t *pc; /* Cache data for PPD */
657 const char *value; /* Filter definition value */
658 mime_type_t *printer_type; /* Printer filter type */
b19ccc9e
MS
659
660
661 if ((ppd = ppdOpenFile(ppdfile)) == NULL)
662 {
eac3a0a0
MS
663 ppd_status_t status; /* PPD load status */
664 int linenum; /* Line number */
b19ccc9e 665
eac3a0a0 666 status = ppdLastError(&linenum);
0837b7e8 667 _cupsLangPrintf(stderr, _("%s: Unable to open PPD file: %s on line %d."),
eac3a0a0 668 command, ppdErrorString(status), linenum);
b19ccc9e
MS
669 return (NULL);
670 }
671
eac3a0a0
MS
672 pc = _ppdCacheCreateWithPPD(ppd);
673 if (!pc)
674 return (NULL);
675
676 printer_type = mimeAddType(mime, "printer", printer);
677 *prefilter_type = NULL;
b19ccc9e 678
eac3a0a0 679 if (pc->filters)
b19ccc9e 680 {
eac3a0a0
MS
681 for (value = (const char *)cupsArrayFirst(pc->filters);
682 value;
683 value = (const char *)cupsArrayNext(pc->filters))
684 add_printer_filter(command, mime, printer_type, value);
b19ccc9e
MS
685 }
686 else
687 {
688 add_printer_filter(command, mime, printer_type,
eac3a0a0 689 "application/vnd.cups-raw 0 -");
b19ccc9e
MS
690 add_printer_filter(command, mime, printer_type,
691 "application/vnd.cups-postscript 0 -");
692 }
693
eac3a0a0 694 if (pc->prefilters)
b19ccc9e
MS
695 {
696 *prefilter_type = mimeAddType(mime, "prefilter", printer);
697
eac3a0a0
MS
698 for (value = (const char *)cupsArrayFirst(pc->prefilters);
699 value;
700 value = (const char *)cupsArrayNext(pc->prefilters))
701 add_printer_filter(command, mime, *prefilter_type, value);
b19ccc9e 702 }
b19ccc9e
MS
703
704 return (printer_type);
705}
706
707
eac3a0a0
MS
708/*
709 * 'check_cb()' - Callback function for _cupsFileCheck.
710 */
711
712static void
713check_cb(void *context, /* I - Context (command name) */
714 _cups_fc_result_t result, /* I - Result of check */
715 const char *message) /* I - Localized message */
716{
321d8d57
MS
717 (void)result;
718
eac3a0a0
MS
719 _cupsLangPrintf(stderr, _("%s: %s"), (char *)context, message);
720}
721
722
bc44d920 723/*
724 * 'compare_pids()' - Compare two filter PIDs...
725 */
726
727static int /* O - Result of comparison */
728compare_pids(mime_filter_t *a, /* I - First filter */
729 mime_filter_t *b) /* I - Second filter */
730{
731 /*
732 * Because we're particularly lazy, we store the process ID in the "cost"
733 * variable...
734 */
735
736 return (a->cost - b->cost);
737}
738
739
740/*
741 * 'escape_options()' - Convert an options array to a string.
742 */
743
744static char * /* O - Option string */
745escape_options(
746 int num_options, /* I - Number of options */
747 cups_option_t *options) /* I - Options */
748{
749 int i; /* Looping var */
750 cups_option_t *option; /* Current option */
751 int bytes; /* Number of bytes needed */
752 char *s, /* Option string */
753 *sptr, /* Pointer into string */
754 *vptr; /* Pointer into value */
755
756
757 /*
758 * Figure out the worst-case number of bytes we need for the option string.
759 */
760
761 for (i = num_options, option = options, bytes = 1; i > 0; i --, option ++)
762 bytes += 2 * (strlen(option->name) + strlen(option->value)) + 2;
763
91c84a35
MS
764 if ((s = malloc(bytes)) == NULL)
765 return (NULL);
bc44d920 766
767 /*
768 * Copy the options to the string...
769 */
770
771 for (i = num_options, option = options, sptr = s; i > 0; i --, option ++)
772 {
773 if (!strcmp(option->name, "copies"))
774 continue;
775
776 if (sptr > s)
777 *sptr++ = ' ';
778
779 strcpy(sptr, option->name);
780 sptr += strlen(sptr);
781 *sptr++ = '=';
782
783 for (vptr = option->value; *vptr;)
784 {
785 if (strchr("\\ \t\n", *vptr))
786 *sptr++ = '\\';
787
788 *sptr++ = *vptr++;
789 }
790 }
791
792 *sptr = '\0';
793
bc44d920 794 return (s);
795}
796
797
798/*
799 * 'exec_filter()' - Execute a single filter.
800 */
801
802static int /* O - Process ID or -1 on error */
803exec_filter(const char *filter, /* I - Filter to execute */
804 char **argv, /* I - Argument list */
805 char **envp, /* I - Environment list */
806 int infd, /* I - Stdin file descriptor */
807 int outfd) /* I - Stdout file descriptor */
808{
97c9a8d7
MS
809 int pid, /* Process ID */
810 fd; /* Temporary file descriptor */
bc44d920 811#if defined(__APPLE__)
812 char processPath[1024], /* CFProcessPath environment variable */
813 linkpath[1024]; /* Link path for symlinks... */
814 int linkbytes; /* Bytes for link path */
815
816
817 /*
88f9aafc 818 * Add special voodoo magic for MacOS X - this allows MacOS X
bc44d920 819 * programs to access their bundle resources properly...
820 */
821
822 if ((linkbytes = readlink(filter, linkpath, sizeof(linkpath) - 1)) > 0)
823 {
824 /*
825 * Yes, this is a symlink to the actual program, nul-terminate and
826 * use it...
827 */
828
829 linkpath[linkbytes] = '\0';
830
831 if (linkpath[0] == '/')
832 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
833 linkpath);
834 else
835 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
836 dirname((char *)filter), linkpath);
837 }
838 else
839 snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", filter);
840
841 envp[0] = processPath; /* Replace <CFProcessPath> string */
842#endif /* __APPLE__ */
843
844 if ((pid = fork()) == 0)
845 {
846 /*
847 * Child process goes here...
848 *
849 * Update stdin/stdout/stderr as needed...
850 */
851
852 if (infd != 0)
853 {
97c9a8d7
MS
854 if (infd < 0)
855 infd = open("/dev/null", O_RDONLY);
856
bc44d920 857 if (infd > 0)
97c9a8d7
MS
858 {
859 dup2(infd, 0);
860 close(infd);
861 }
bc44d920 862 }
863
864 if (outfd != 1)
865 {
97c9a8d7
MS
866 if (outfd < 0)
867 outfd = open("/dev/null", O_WRONLY);
868
869 if (outfd > 1)
870 {
871 dup2(outfd, 1);
872 close(outfd);
873 }
bc44d920 874 }
875
97c9a8d7
MS
876 if ((fd = open("/dev/null", O_RDWR)) > 3)
877 {
878 dup2(fd, 3);
879 close(fd);
880 }
bc44d920 881 fcntl(3, F_SETFL, O_NDELAY);
882
97c9a8d7
MS
883 if ((fd = open("/dev/null", O_RDWR)) > 4)
884 {
885 dup2(fd, 4);
886 close(fd);
887 }
bc44d920 888 fcntl(4, F_SETFL, O_NDELAY);
889
890 /*
891 * Execute command...
892 */
893
894 execve(filter, argv, envp);
895
896 perror(filter);
897
898 exit(errno);
899 }
900
901 return (pid);
902}
903
904
905/*
906 * 'exec_filters()' - Execute filters for the given file and options.
907 */
908
909static int /* O - 0 on success, 1 on error */
1340db2d
MS
910exec_filters(mime_type_t *srctype, /* I - Source type */
911 cups_array_t *filters, /* I - Array of filters to run */
cc0d019f
MS
912 const char *infile, /* I - File to filter */
913 const char *outfile, /* I - File to create */
bc44d920 914 const char *ppdfile, /* I - PPD file, if any */
db1f069b 915 const char *printer, /* I - Printer name */
cc0d019f 916 const char *user, /* I - Username */
bc44d920 917 const char *title, /* I - Job title */
918 int num_options, /* I - Number of filter options */
919 cups_option_t *options) /* I - Filter options */
920{
cc0d019f 921 int i; /* Looping var */
bc44d920 922 const char *argv[8], /* Command-line arguments */
5a6b583a 923 *envp[15], /* Environment variables */
bc44d920 924 *temp; /* Temporary string */
925 char *optstr, /* Filter options */
e6013cfa 926 content_type[1024], /* CONTENT_TYPE */
bc44d920 927 cups_datadir[1024], /* CUPS_DATADIR */
928 cups_fontpath[1024], /* CUPS_FONTPATH */
929 cups_serverbin[1024], /* CUPS_SERVERBIN */
930 cups_serverroot[1024], /* CUPS_SERVERROOT */
931 lang[1024], /* LANG */
932 path[1024], /* PATH */
933 ppd[1024], /* PPD */
5a6b583a
MS
934 printer_info[255], /* PRINTER_INFO env variable */
935 printer_location[255], /* PRINTER_LOCATION env variable */
936 printer_name[255], /* PRINTER env variable */
71e16022 937 rip_max_cache[1024], /* RIP_MAX_CACHE */
cc0d019f 938 userenv[1024], /* USER */
bc44d920 939 program[1024]; /* Program to run */
940 mime_filter_t *filter, /* Current filter */
941 *next; /* Next filter */
942 int current, /* Current filter */
943 filterfds[2][2], /* Pipes for filters */
944 pid, /* Process ID of filter */
945 status, /* Exit status */
946 retval; /* Return value */
947 cups_array_t *pids; /* Executed filters array */
948 mime_filter_t key; /* Search key for filters */
cc0d019f 949 cups_lang_t *language; /* Current language */
5a6b583a 950 cups_dest_t *dest; /* Destination information */
bc44d920 951
952
953 /*
954 * Setup the filter environment and command-line...
955 */
956
957 optstr = escape_options(num_options, options);
958
e6013cfa 959 snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
1340db2d 960 srctype->super, srctype->type);
bc44d920 961 snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
962 snprintf(cups_fontpath, sizeof(cups_fontpath), "CUPS_FONTPATH=%s", FontPath);
963 snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s",
964 ServerBin);
965 snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s",
966 ServerRoot);
cc0d019f
MS
967 language = cupsLangDefault();
968 snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
bc44d920 969 snprintf(path, sizeof(path), "PATH=%s", Path);
970 if (ppdfile)
971 snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile);
972 else if ((temp = getenv("PPD")) != NULL)
973 snprintf(ppd, sizeof(ppd), "PPD=%s", temp);
974 else
cc0d019f 975#ifdef __APPLE__
db1f069b
MS
976 if (!access("/System/Library/Frameworks/ApplicationServices.framework/"
977 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
978 "Resources/English.lproj/Generic.ppd", 0))
cc0d019f
MS
979 strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
980 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
981 "Resources/English.lproj/Generic.ppd", sizeof(ppd));
db1f069b
MS
982 else
983 strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
984 "Versions/A/Frameworks/PrintCore.framework/Versions/A/"
985 "Resources/Generic.ppd", sizeof(ppd));
cc0d019f 986#else
bc44d920 987 snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir);
cc0d019f 988#endif /* __APPLE__ */
71e16022 989 snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache);
cc0d019f 990 snprintf(userenv, sizeof(userenv), "USER=%s", user);
bc44d920 991
5a6b583a
MS
992 if (printer &&
993 (dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, NULL)) != NULL)
994 {
995 if ((temp = cupsGetOption("printer-info", dest->num_options,
996 dest->options)) != NULL)
997 snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", temp);
998 else
999 snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", printer);
1000
1001 if ((temp = cupsGetOption("printer-location", dest->num_options,
1002 dest->options)) != NULL)
1003 snprintf(printer_location, sizeof(printer_location),
1004 "PRINTER_LOCATION=%s", temp);
1005 else
1006 strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
1007 sizeof(printer_location));
1008 }
1009 else
1010 {
1011 snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s",
1012 printer ? printer : "Unknown");
1013 strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
1014 sizeof(printer_location));
1015 }
1016
1017 snprintf(printer_name, sizeof(printer_name), "PRINTER=%s",
1018 printer ? printer : "Unknown");
1019
db1f069b
MS
1020 argv[0] = (char *)printer;
1021 argv[1] = "1";
cc0d019f 1022 argv[2] = user;
bc44d920 1023 argv[3] = title;
1024 argv[4] = cupsGetOption("copies", num_options, options);
1025 argv[5] = optstr;
cc0d019f 1026 argv[6] = infile;
bc44d920 1027 argv[7] = NULL;
1028
1029 if (!argv[4])
1030 argv[4] = "1";
1031
1032 envp[0] = "<CFProcessPath>";
e6013cfa
MS
1033 envp[1] = content_type;
1034 envp[2] = cups_datadir;
1035 envp[3] = cups_fontpath;
1036 envp[4] = cups_serverbin;
1037 envp[5] = cups_serverroot;
1038 envp[6] = lang;
1039 envp[7] = path;
1040 envp[8] = ppd;
5a6b583a
MS
1041 envp[9] = printer_info;
1042 envp[10] = printer_location;
1043 envp[11] = printer_name;
71e16022 1044 envp[12] = rip_max_cache;
5a6b583a
MS
1045 envp[13] = userenv;
1046 envp[14] = NULL;
bc44d920 1047
cc0d019f
MS
1048 for (i = 0; argv[i]; i ++)
1049 fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
1050
1051 for (i = 0; envp[i]; i ++)
1052 fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]);
1053
bc44d920 1054 /*
1055 * Execute all of the filters...
1056 */
1057
1058 pids = cupsArrayNew((cups_array_func_t)compare_pids, NULL);
1059 current = 0;
1060 filterfds[0][0] = -1;
1061 filterfds[0][1] = -1;
1062 filterfds[1][0] = -1;
1063 filterfds[1][1] = -1;
1064
cc0d019f
MS
1065 if (!infile)
1066 filterfds[0][0] = 0;
1067
bc44d920 1068 for (filter = (mime_filter_t *)cupsArrayFirst(filters);
1069 filter;
1070 filter = next, current = 1 - current)
1071 {
1072 next = (mime_filter_t *)cupsArrayNext(filters);
1073
1074 if (filter->filter[0] == '/')
1075 strlcpy(program, filter->filter, sizeof(program));
1076 else
1077 snprintf(program, sizeof(program), "%s/filter/%s", ServerBin,
1078 filter->filter);
1079
1080 if (filterfds[!current][1] > 1)
1081 {
1082 close(filterfds[1 - current][0]);
1083 close(filterfds[1 - current][1]);
1084
1085 filterfds[1 - current][0] = -1;
1086 filterfds[1 - current][0] = -1;
1087 }
1088
1089 if (next)
1090 open_pipe(filterfds[1 - current]);
cc0d019f
MS
1091 else if (outfile)
1092 {
1093 filterfds[1 - current][1] = open(outfile, O_CREAT | O_TRUNC | O_WRONLY,
1094 0666);
1095
1096 if (filterfds[1 - current][1] < 0)
1097 fprintf(stderr, "ERROR: Unable to create \"%s\" - %s\n", outfile,
1098 strerror(errno));
1099 }
bc44d920 1100 else
1101 filterfds[1 - current][1] = 1;
1102
1103 pid = exec_filter(program, (char **)argv, (char **)envp,
1104 filterfds[current][0], filterfds[1 - current][1]);
1105
1106 if (pid > 0)
1107 {
1108 fprintf(stderr, "INFO: %s (PID %d) started.\n", filter->filter, pid);
1109
1110 filter->cost = pid;
1111 cupsArrayAdd(pids, filter);
1112 }
1113 else
1114 break;
1115
1116 argv[6] = NULL;
1117 }
1118
1119 /*
1120 * Close remaining pipes...
1121 */
1122
1123 if (filterfds[0][1] > 1)
1124 {
1125 close(filterfds[0][0]);
1126 close(filterfds[0][1]);
1127 }
1128
1129 if (filterfds[1][1] > 1)
1130 {
1131 close(filterfds[1][0]);
1132 close(filterfds[1][1]);
1133 }
1134
1135 /*
1136 * Wait for the children to exit...
1137 */
1138
1139 retval = 0;
1140
1141 while (cupsArrayCount(pids) > 0)
1142 {
1143 if ((pid = wait(&status)) < 0)
1144 continue;
1145
1146 key.cost = pid;
1147 if ((filter = (mime_filter_t *)cupsArrayFind(pids, &key)) != NULL)
1148 {
1149 cupsArrayRemove(pids, filter);
1150
1151 if (status)
1152 {
1153 if (WIFEXITED(status))
4d301e69 1154 fprintf(stderr, "ERROR: %s (PID %d) stopped with status %d\n",
bc44d920 1155 filter->filter, pid, WEXITSTATUS(status));
1156 else
4d301e69 1157 fprintf(stderr, "ERROR: %s (PID %d) crashed on signal %d\n",
bc44d920 1158 filter->filter, pid, WTERMSIG(status));
1159
1160 retval = 1;
1161 }
1162 else
1163 fprintf(stderr, "INFO: %s (PID %d) exited with no errors.\n",
1164 filter->filter, pid);
1165 }
1166 }
1167
91c84a35
MS
1168 cupsArrayDelete(pids);
1169
bc44d920 1170 return (retval);
1171}
1172
1173
2e4ff8af
MS
1174/*
1175 * 'get_job_file()' - Get the specified job file.
1176 */
1177
1178static void
1179get_job_file(const char *job) /* I - Job ID */
1180{
1181 long jobid, /* Job ID */
1182 docnum; /* Document number */
1183 const char *jobptr; /* Pointer into job ID string */
1184 char uri[1024]; /* job-uri */
1185 http_t *http; /* Connection to server */
1186 ipp_t *request; /* Request data */
1187 int tempfd; /* Temporary file */
1188
1189
1190 /*
1191 * Get the job ID and document number, if any...
1192 */
1193
1194 if ((jobptr = strrchr(job, '-')) != NULL)
1195 jobptr ++;
1196 else
1197 jobptr = job;
1198
1199 jobid = strtol(jobptr, (char **)&jobptr, 10);
1200
1201 if (*jobptr == ',')
1202 docnum = strtol(jobptr + 1, NULL, 10);
1203 else
1204 docnum = 1;
1205
1206 if (jobid < 1 || jobid > INT_MAX)
1207 {
0837b7e8 1208 _cupsLangPrintf(stderr, _("cupsfilter: Invalid job ID %d."), (int)jobid);
2e4ff8af
MS
1209 exit(1);
1210 }
1211
1212 if (docnum < 1 || docnum > INT_MAX)
1213 {
0837b7e8 1214 _cupsLangPrintf(stderr, _("cupsfilter: Invalid document number %d."),
2e4ff8af
MS
1215 (int)docnum);
1216 exit(1);
1217 }
1218
1219 /*
1220 * Ask the server for the document file...
1221 */
1222
1223 if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
1224 cupsEncryption())) == NULL)
1225 {
0837b7e8 1226 _cupsLangPrintf(stderr, _("%s: Unable to connect to server."),
2e4ff8af
MS
1227 "cupsfilter");
1228 exit(1);
1229 }
1230
1231 request = ippNewRequest(CUPS_GET_DOCUMENT);
1232
1233 snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", (int)jobid);
1234
1235 ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
1236 ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "document-number",
1237 (int)docnum);
1238
1239 if ((tempfd = cupsTempFd(TempFile, sizeof(TempFile))) == -1)
1240 {
0837b7e8 1241 _cupsLangPrintError("ERROR", _("Unable to create temporary file"));
2e4ff8af
MS
1242 httpClose(http);
1243 exit(1);
1244 }
1245
1246 signal(SIGTERM, sighandler);
1247
1248 ippDelete(cupsDoIORequest(http, request, "/", -1, tempfd));
1249
1250 close(tempfd);
1251
1252 httpClose(http);
1253
1254 if (cupsLastError() != IPP_OK)
1255 {
0837b7e8 1256 _cupsLangPrintf(stderr, _("cupsfilter: Unable to get job file - %s"),
2e4ff8af
MS
1257 cupsLastErrorString());
1258 unlink(TempFile);
1259 exit(1);
1260 }
1261}
1262
1263
bc44d920 1264/*
1265 * 'open_pipe()' - Create a pipe which is closed on exec.
1266 */
1267
2e4ff8af 1268static int /* O - 0 on success, -1 on error */
bc44d920 1269open_pipe(int *fds) /* O - Pipe file descriptors (2) */
1270{
1271 /*
1272 * Create the pipe...
1273 */
1274
1275 if (pipe(fds))
1276 {
1277 fds[0] = -1;
1278 fds[1] = -1;
1279
1280 return (-1);
1281 }
1282
1283 /*
1284 * Set the "close on exec" flag on each end of the pipe...
1285 */
1286
1287 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
1288 {
1289 close(fds[0]);
1290 close(fds[1]);
1291
1292 fds[0] = -1;
1293 fds[1] = -1;
1294
1295 return (-1);
1296 }
1297
1298 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
1299 {
1300 close(fds[0]);
1301 close(fds[1]);
1302
1303 fds[0] = -1;
1304 fds[1] = -1;
1305
1306 return (-1);
1307 }
1308
1309 /*
1310 * Return 0 indicating success...
1311 */
1312
1313 return (0);
1314}
1315
1316
1317/*
1318 * 'read_cupsd_conf()' - Read the cupsd.conf file to get the filter settings.
1319 */
1320
1321static int /* O - 0 on success, 1 on error */
1322read_cupsd_conf(const char *filename) /* I - File to read */
1323{
cc0d019f 1324 cups_file_t *fp; /* cupsd.conf file */
bc44d920 1325 const char *temp; /* Temporary string */
1326 char line[1024], /* Line from file */
1327 *ptr; /* Pointer into line */
cc0d019f 1328 int linenum; /* Current line number */
bc44d920 1329
1330
1331 if ((temp = getenv("CUPS_DATADIR")) != NULL)
1332 set_string(&DataDir, temp);
1333 else
1334 set_string(&DataDir, CUPS_DATADIR);
1335
1336 if ((temp = getenv("CUPS_FONTPATH")) != NULL)
1337 set_string(&FontPath, temp);
1338 else
1339 set_string(&FontPath, CUPS_FONTPATH);
1340
eac3a0a0 1341 set_string(&RIPCache, "128m");
cc0d019f 1342
bc44d920 1343 if ((temp = getenv("CUPS_SERVERBIN")) != NULL)
1344 set_string(&ServerBin, temp);
1345 else
1346 set_string(&ServerBin, CUPS_SERVERBIN);
1347
1348 strlcpy(line, filename, sizeof(line));
1349 if ((ptr = strrchr(line, '/')) != NULL)
1350 *ptr = '\0';
1351 else
1352 getcwd(line, sizeof(line));
1353
1354 set_string(&ServerRoot, line);
1355
cc0d019f
MS
1356 if ((fp = cupsFileOpen(filename, "r")) != NULL)
1357 {
1358 linenum = 0;
1359
1360 while (cupsFileGetConf(fp, line, sizeof(line), &ptr, &linenum))
1361 {
88f9aafc 1362 if (!_cups_strcasecmp(line, "DataDir"))
cc0d019f 1363 set_string(&DataDir, ptr);
88f9aafc 1364 else if (!_cups_strcasecmp(line, "FontPath"))
cc0d019f 1365 set_string(&FontPath, ptr);
88f9aafc 1366 else if (!_cups_strcasecmp(line, "RIPCache"))
cc0d019f 1367 set_string(&RIPCache, ptr);
88f9aafc 1368 else if (!_cups_strcasecmp(line, "ServerBin"))
cc0d019f 1369 set_string(&ServerBin, ptr);
88f9aafc 1370 else if (!_cups_strcasecmp(line, "ServerRoot"))
cc0d019f
MS
1371 set_string(&ServerRoot, ptr);
1372 }
1373
1374 cupsFileClose(fp);
1375 }
1376
bc44d920 1377 snprintf(line, sizeof(line),
06d4e77b 1378 "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin:/usr/bin",
bc44d920 1379 ServerBin);
1380 set_string(&Path, line);
1381
1382 return (0);
1383}
1384
1385
1386/*
1387 * 'set_string()' - Copy and set a string.
1388 */
1389
1390static void
1391set_string(char **s, /* O - Copy of string */
1392 const char *val) /* I - String to copy */
1393{
1394 if (*s)
1395 free(*s);
1396
1397 *s = strdup(val);
1398}
1399
1400
2e4ff8af
MS
1401/*
1402 * 'sighandler()' - Signal catcher for when we print from stdin...
1403 */
1404
1405static void
1406sighandler(int s) /* I - Signal number */
1407{
1408 /*
1409 * Remove the temporary file we're using to print a job file...
1410 */
1411
1412 if (TempFile[0])
1413 unlink(TempFile);
1414
1415 /*
1416 * Exit...
1417 */
1418
1419 exit(s);
1420}
1421
1422
bc44d920 1423/*
1424 * 'usage()' - Show program usage...
1425 */
1426
1427static void
cc0d019f
MS
1428usage(const char *command, /* I - Command name */
1429 const char *opt) /* I - Incorrect option, if any */
bc44d920 1430{
1431 if (opt)
0837b7e8 1432 _cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), command, *opt);
cc0d019f
MS
1433
1434 if (!strcmp(command, "cupsfilter"))
0837b7e8 1435 {
84315f46 1436 _cupsLangPuts(stdout, _("Usage: cupsfilter [ options ] filename"));
0837b7e8 1437 _cupsLangPuts(stdout, _("Options:"));
84315f46
MS
1438 _cupsLangPuts(stdout, _(" -D Remove the input file "
1439 "when finished."));
1440 _cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file."));
1441 _cupsLangPuts(stdout, _(" -U username Set username for job."));
1442 _cupsLangPuts(stdout, _(" -c cupsd.conf Set cupsd.conf file to "
1443 "use."));
1444 _cupsLangPuts(stdout, _(" -d printer Use the named "
1445 "printer."));
1446 _cupsLangPuts(stdout, _(" -e Use every filter from "
1447 "the PPD file."));
1448 _cupsLangPuts(stdout, _(" -i mime/type Set input MIME type "
1449 "(otherwise auto-typed)."));
1450 _cupsLangPuts(stdout, _(" -j job-id[,N] Filter file N from the "
0837b7e8 1451 "specified job (default is file 1)."));
84315f46
MS
1452 _cupsLangPuts(stdout, _(" -m mime/type Set output MIME type "
1453 "(otherwise application/pdf)."));
1454 _cupsLangPuts(stdout, _(" -n copies Set number of copies."));
1455 _cupsLangPuts(stdout, _(" -o name=value Set option(s)."));
1456 _cupsLangPuts(stdout, _(" -p filename.ppd Set PPD file."));
1457 _cupsLangPuts(stdout, _(" -t title Set title."));
1458 _cupsLangPuts(stdout, _(" -u Remove the PPD file "
1459 "when finished."));
0837b7e8 1460 }
cc0d019f 1461 else
0837b7e8
MS
1462 {
1463 _cupsLangPuts(stdout, _("Usage: convert [ options ]"));
1464 _cupsLangPuts(stdout, _("Options:"));
84315f46
MS
1465 _cupsLangPuts(stdout, _(" -D Remove the input file "
1466 "when finished."));
1467 _cupsLangPuts(stdout, _(" -J title Set title."));
1468 _cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file."));
1469 _cupsLangPuts(stdout, _(" -U username Set username for job."));
1470 _cupsLangPuts(stdout, _(" -a 'name=value ...' Set option(s)."));
1471 _cupsLangPuts(stdout, _(" -c copies Set number of copies."));
1472 _cupsLangPuts(stdout, _(" -d printer Use the named "
1473 "printer."));
1474 _cupsLangPuts(stdout, _(" -e Use every filter from "
1475 "the PPD file."));
1476 _cupsLangPuts(stdout, _(" -f filename Set file to be "
1477 "converted (otherwise stdin)."));
1478 _cupsLangPuts(stdout, _(" -i mime/type Set input MIME type "
0837b7e8 1479 "(otherwise auto-typed)."));
84315f46 1480 _cupsLangPuts(stdout, _(" -j mime/type Set output MIME type "
0837b7e8 1481 "(otherwise application/pdf)."));
84315f46
MS
1482 _cupsLangPuts(stdout, _(" -o filename Set file to be "
1483 "generated (otherwise stdout)."));
1484 _cupsLangPuts(stdout, _(" -u Remove the PPD file "
1485 "when finished."));
0837b7e8 1486 }
bc44d920 1487
1488 exit(1);
1489}
1490
1491
1492/*
b19ccc9e 1493 * End of "$Id: cupsfilter.c 7952 2008-09-17 00:56:20Z mike $".
bc44d920 1494 */