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