mirror of https://gitee.com/openkylin/cups.git
1560 lines
39 KiB
C
1560 lines
39 KiB
C
/*
|
||
* Filtering program for CUPS.
|
||
*
|
||
* Copyright © 2021-2022 by OpenPrinting
|
||
* Copyright © 2007-2016 by Apple Inc.
|
||
* Copyright © 1997-2006 by Easy Software Products, all rights reserved.
|
||
*
|
||
* Licensed under Apache License v2.0. See the file "LICENSE" for more information.
|
||
*/
|
||
|
||
/*
|
||
* Include necessary headers...
|
||
*/
|
||
|
||
#include <cups/cups-private.h>
|
||
#include <cups/file-private.h>
|
||
#include <cups/ppd-private.h>
|
||
#include "mime.h"
|
||
#include <limits.h>
|
||
#include <unistd.h>
|
||
#include <fcntl.h>
|
||
#include <signal.h>
|
||
#include <sys/wait.h>
|
||
#if defined(__APPLE__)
|
||
# include <libgen.h>
|
||
#endif /* __APPLE__ */
|
||
|
||
|
||
/*
|
||
* Local globals...
|
||
*/
|
||
|
||
static char *DataDir = NULL;/* CUPS_DATADIR environment variable */
|
||
static mime_filter_t GZIPFilter = /* gziptoany filter */
|
||
{
|
||
NULL, /* Source type */
|
||
NULL, /* Destination type */
|
||
0, /* Cost */
|
||
"gziptoany" /* Filter program to run */
|
||
};
|
||
static char *Path = NULL; /* PATH environment variable */
|
||
static char *ServerBin = NULL;
|
||
/* CUPS_SERVERBIN environment variable */
|
||
static char *ServerRoot = NULL;
|
||
/* CUPS_SERVERROOT environment variable */
|
||
static char TempFile[1024] = "";
|
||
/* Temporary file */
|
||
|
||
|
||
/*
|
||
* Local functions...
|
||
*/
|
||
|
||
static void add_printer_filter(const char *command, mime_t *mime,
|
||
mime_type_t *printer_type,
|
||
const char *filter);
|
||
static mime_type_t *add_printer_filters(const char *command,
|
||
mime_t *mime, const char *printer,
|
||
const char *ppdfile,
|
||
mime_type_t **prefilter_type);
|
||
static void check_cb(void *context, _cups_fc_result_t result,
|
||
const char *message);
|
||
static int compare_pids(mime_filter_t *a, mime_filter_t *b);
|
||
static char *escape_options(int num_options, cups_option_t *options);
|
||
static int exec_filter(const char *filter, char **argv,
|
||
char **envp, int infd, int outfd);
|
||
static int exec_filters(mime_type_t *srctype,
|
||
cups_array_t *filters, const char *infile,
|
||
const char *outfile, const char *ppdfile,
|
||
const char *printer, const char *user,
|
||
const char *title, int num_options,
|
||
cups_option_t *options);
|
||
static void get_job_file(const char *job);
|
||
static int open_pipe(int *fds);
|
||
static int read_cups_files_conf(const char *filename);
|
||
static void set_string(char **s, const char *val);
|
||
static void sighandler(int sig);
|
||
static void usage(const char *opt) _CUPS_NORETURN;
|
||
|
||
|
||
/*
|
||
* 'main()' - Main entry for the test program.
|
||
*/
|
||
|
||
int /* O - Exit status */
|
||
main(int argc, /* I - Number of command-line args */
|
||
char *argv[]) /* I - Command-line arguments */
|
||
{
|
||
int i, /* Looping vars */
|
||
list_filters = 0; /* Just list the filters? */
|
||
const char *command, /* Command name */
|
||
*opt, /* Current option */
|
||
*printer; /* Printer name */
|
||
mime_type_t *printer_type, /* Printer MIME type */
|
||
*prefilter_type; /* Printer prefilter MIME type */
|
||
char *srctype, /* Source type */
|
||
*dsttype, /* Destination type */
|
||
super[MIME_MAX_SUPER], /* Super-type name */
|
||
type[MIME_MAX_TYPE]; /* Type name */
|
||
int compression; /* Compression of file */
|
||
int cost; /* Cost of filters */
|
||
mime_t *mime; /* MIME database */
|
||
char mimedir[1024]; /* MIME directory */
|
||
char *infile, /* File to filter */
|
||
*outfile; /* File to create */
|
||
char cupsfilesconf[1024]; /* cups-files.conf file */
|
||
const char *server_root; /* CUPS_SERVERROOT environment variable */
|
||
mime_type_t *src, /* Source type */
|
||
*dst; /* Destination type */
|
||
cups_array_t *filters; /* Filters for the file */
|
||
int num_options; /* Number of options */
|
||
cups_option_t *options; /* Options */
|
||
const char *ppdfile; /* PPD file */
|
||
const char *title, /* Title string */
|
||
*user; /* Username */
|
||
int all_filters, /* Use all filters */
|
||
removeppd, /* Remove PPD file */
|
||
removeinfile; /* Remove input file */
|
||
int status; /* Execution status */
|
||
|
||
|
||
/*
|
||
* Setup defaults...
|
||
*/
|
||
|
||
if ((command = strrchr(argv[0], '/')) != NULL)
|
||
command ++;
|
||
else
|
||
command = argv[0];
|
||
|
||
printer = !strcmp(command, "convert") ? "tofile" : "cupsfilter";
|
||
mime = NULL;
|
||
srctype = NULL;
|
||
compression = 0;
|
||
dsttype = "application/pdf";
|
||
infile = NULL;
|
||
outfile = NULL;
|
||
num_options = 0;
|
||
options = NULL;
|
||
ppdfile = NULL;
|
||
title = NULL;
|
||
user = cupsUser();
|
||
all_filters = 0;
|
||
removeppd = 0;
|
||
removeinfile = 0;
|
||
|
||
if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
|
||
server_root = CUPS_SERVERROOT;
|
||
|
||
snprintf(cupsfilesconf, sizeof(cupsfilesconf), "%s/cups-files.conf", server_root);
|
||
|
||
/*
|
||
* Process command-line arguments...
|
||
*/
|
||
|
||
_cupsSetLocale(argv);
|
||
|
||
for (i = 1; i < argc; i ++)
|
||
{
|
||
if (argv[i][0] == '-')
|
||
{
|
||
if (!strcmp(argv[i], "--list-filters"))
|
||
{
|
||
list_filters = 1;
|
||
}
|
||
else if (!strcmp(argv[i], "--"))
|
||
{
|
||
i ++;
|
||
if (i < argc && !infile)
|
||
infile = argv[i];
|
||
else
|
||
usage(NULL);
|
||
}
|
||
else
|
||
{
|
||
for (opt = argv[i] + 1; *opt; opt ++)
|
||
{
|
||
switch (*opt)
|
||
{
|
||
case 'a' : /* Specify option... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
num_options = cupsParseOptions(argv[i], num_options, &options);
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected name=value after \"-a\" option."), argv[0]);
|
||
usage(opt);
|
||
}
|
||
break;
|
||
|
||
case 'c' : /* Specify cups-files.conf file location... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
if (!strcmp(command, "convert"))
|
||
num_options = cupsAddOption("copies", argv[i], num_options, &options);
|
||
else
|
||
strlcpy(cupsfilesconf, argv[i], sizeof(cupsfilesconf));
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected filename after \"-c\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'd' : /* Specify the real printer name */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
printer = argv[i];
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected printer name after \"-d\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'D' : /* Delete input file after conversion */
|
||
removeinfile = 1;
|
||
break;
|
||
|
||
case 'e' : /* Use every filter from the PPD file */
|
||
all_filters = 1;
|
||
break;
|
||
|
||
case 'f' : /* Specify input file... */
|
||
i ++;
|
||
if (i < argc && !infile)
|
||
{
|
||
infile = argv[i];
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected input file after \"-f\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'i' : /* Specify source MIME type... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
|
||
usage(opt);
|
||
|
||
srctype = argv[i];
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected source MIME type after \"-i\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'j' : /* Get job file or specify destination MIME type... */
|
||
if (strcmp(command, "convert"))
|
||
{
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
get_job_file(argv[i]);
|
||
infile = TempFile;
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stdout, _("%s: Error - expected job-id after \"-j\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
}
|
||
|
||
case 'm' : /* Specify destination MIME type... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
|
||
usage(opt);
|
||
|
||
dsttype = argv[i];
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected destination MIME type after \"-m\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'n' : /* Specify number of copies... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
num_options = cupsAddOption("copies", argv[i], num_options, &options);
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected number of copies after \"-n\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'o' : /* Specify option(s) or output filename */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
if (!strcmp(command, "convert"))
|
||
{
|
||
if (outfile)
|
||
usage(NULL);
|
||
else
|
||
outfile = argv[i];
|
||
}
|
||
else
|
||
{
|
||
num_options = cupsParseOptions(argv[i], num_options, &options);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected name=value after \"-o\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'p' : /* Specify PPD file... */
|
||
case 'P' : /* Specify PPD file... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
ppdfile = argv[i];
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected PPD file after \"-%c\" option."), argv[0], *opt);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 't' : /* Specify title... */
|
||
case 'J' : /* Specify title... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
title = argv[i];
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected title after \"-%c\" option."), argv[0], *opt);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
case 'u' : /* Delete PPD file after conversion */
|
||
removeppd = 1;
|
||
break;
|
||
|
||
case 'U' : /* Specify username... */
|
||
i ++;
|
||
if (i < argc)
|
||
{
|
||
user = argv[i];
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Error - expected \"username\" after \"-U\" option."), argv[0]);
|
||
usage(NULL);
|
||
}
|
||
break;
|
||
|
||
default : /* Something we don't understand... */
|
||
_cupsLangPrintf(stderr, _("%s: Error - unknown option \"-%c\"."), argv[0], *opt);
|
||
usage(NULL);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (!infile)
|
||
{
|
||
if (strcmp(command, "convert"))
|
||
infile = argv[i];
|
||
else
|
||
usage(NULL);
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPuts(stderr, _("cupsfilter: Only one filename can be specified."));
|
||
usage(NULL);
|
||
}
|
||
}
|
||
|
||
if (!infile && !srctype)
|
||
usage(NULL);
|
||
|
||
if (!title)
|
||
{
|
||
if (!infile)
|
||
title = "(stdin)";
|
||
else if ((title = strrchr(infile, '/')) != NULL)
|
||
title ++;
|
||
else
|
||
title = infile;
|
||
}
|
||
|
||
/*
|
||
* Load the cups-files.conf file and create the MIME database...
|
||
*/
|
||
|
||
if (read_cups_files_conf(cupsfilesconf))
|
||
return (1);
|
||
|
||
snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);
|
||
|
||
mime = mimeLoadTypes(NULL, mimedir);
|
||
mime = mimeLoadTypes(mime, ServerRoot);
|
||
mime = mimeLoadFilters(mime, mimedir, Path);
|
||
mime = mimeLoadFilters(mime, ServerRoot, Path);
|
||
|
||
if (!mime)
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Unable to read MIME database from \"%s\" or \"%s\"."), command, mimedir, ServerRoot);
|
||
return (1);
|
||
}
|
||
|
||
prefilter_type = NULL;
|
||
|
||
if (all_filters)
|
||
printer_type = add_printer_filters(command, mime, printer, ppdfile,
|
||
&prefilter_type);
|
||
else
|
||
printer_type = mimeType(mime, "application", "vnd.cups-postscript");
|
||
|
||
/*
|
||
* Get the source and destination types...
|
||
*/
|
||
|
||
if (srctype)
|
||
{
|
||
/* sscanf return value already checked above */
|
||
sscanf(srctype, "%15[^/]/%255s", super, type);
|
||
if ((src = mimeType(mime, super, type)) == NULL)
|
||
{
|
||
_cupsLangPrintf(stderr,
|
||
_("%s: Unknown source MIME type %s/%s."),
|
||
command, super, type);
|
||
return (1);
|
||
}
|
||
}
|
||
else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
|
||
{
|
||
_cupsLangPrintf(stderr,
|
||
_("%s: Unable to determine MIME type of \"%s\"."),
|
||
command, infile);
|
||
return (1);
|
||
}
|
||
|
||
/* sscanf return value already checked above */
|
||
sscanf(dsttype, "%15[^/]/%255s", super, type);
|
||
if (!_cups_strcasecmp(super, "printer"))
|
||
dst = printer_type;
|
||
else if ((dst = mimeType(mime, super, type)) == NULL)
|
||
{
|
||
_cupsLangPrintf(stderr,
|
||
_("%s: Unknown destination MIME type %s/%s."),
|
||
command, super, type);
|
||
return (1);
|
||
}
|
||
|
||
/*
|
||
* Figure out how to filter the file...
|
||
*/
|
||
|
||
if (src == dst)
|
||
{
|
||
/*
|
||
* Special case - no filtering needed...
|
||
*/
|
||
|
||
filters = cupsArrayNew(NULL, NULL);
|
||
cupsArrayAdd(filters, &GZIPFilter);
|
||
GZIPFilter.src = src;
|
||
GZIPFilter.dst = dst;
|
||
}
|
||
else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
|
||
{
|
||
_cupsLangPrintf(stderr,
|
||
_("%s: No filter to convert from %s/%s to %s/%s."),
|
||
command, src->super, src->type, dst->super, dst->type);
|
||
return (1);
|
||
}
|
||
else if (compression)
|
||
cupsArrayInsert(filters, &GZIPFilter);
|
||
|
||
if (prefilter_type)
|
||
{
|
||
/*
|
||
* Add pre-filters...
|
||
*/
|
||
|
||
mime_filter_t *filter, /* Current filter */
|
||
*prefilter; /* Current pre-filter */
|
||
cups_array_t *prefilters = cupsArrayNew(NULL, NULL);
|
||
/* New filters array */
|
||
|
||
|
||
for (filter = (mime_filter_t *)cupsArrayFirst(filters);
|
||
filter;
|
||
filter = (mime_filter_t *)cupsArrayNext(filters))
|
||
{
|
||
if ((prefilter = mimeFilterLookup(mime, filter->src,
|
||
prefilter_type)) != NULL)
|
||
cupsArrayAdd(prefilters, prefilter);
|
||
|
||
cupsArrayAdd(prefilters, filter);
|
||
}
|
||
|
||
cupsArrayDelete(filters);
|
||
filters = prefilters;
|
||
}
|
||
|
||
if (list_filters)
|
||
{
|
||
/*
|
||
* List filters...
|
||
*/
|
||
|
||
mime_filter_t *filter; /* Current filter */
|
||
|
||
for (filter = (mime_filter_t *)cupsArrayFirst(filters);
|
||
filter;
|
||
filter = (mime_filter_t *)cupsArrayNext(filters))
|
||
if (strcmp(filter->filter, "-"))
|
||
_cupsLangPuts(stdout, filter->filter);
|
||
|
||
status = 0;
|
||
}
|
||
else
|
||
{
|
||
/*
|
||
* Run filters...
|
||
*/
|
||
|
||
status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user,
|
||
title, num_options, options);
|
||
}
|
||
|
||
/*
|
||
* Remove files as needed, then exit...
|
||
*/
|
||
|
||
if (TempFile[0])
|
||
unlink(TempFile);
|
||
|
||
if (removeppd && ppdfile)
|
||
unlink(ppdfile);
|
||
|
||
if (removeinfile && infile)
|
||
unlink(infile);
|
||
|
||
return (status);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'add_printer_filter()' - Add a single filters from a PPD file.
|
||
*/
|
||
|
||
static void
|
||
add_printer_filter(
|
||
const char *command, /* I - Command name */
|
||
mime_t *mime, /* I - MIME database */
|
||
mime_type_t *filtertype, /* I - Printer or prefilter MIME type */
|
||
const char *filter) /* I - Filter to add */
|
||
{
|
||
char super[MIME_MAX_SUPER], /* Super-type for filter */
|
||
type[MIME_MAX_TYPE], /* Type for filter */
|
||
dsuper[MIME_MAX_SUPER], /* Destination super-type for filter */
|
||
dtype[MIME_MAX_TYPE], /* Destination type for filter */
|
||
dest[MIME_MAX_SUPER + MIME_MAX_TYPE + 2],
|
||
/* Destination super/type */
|
||
program[1024]; /* Program/filter name */
|
||
int cost; /* Cost of filter */
|
||
size_t maxsize = 0; /* Maximum supported file size */
|
||
mime_type_t *temptype, /* MIME type looping var */
|
||
*desttype; /* Destination MIME type */
|
||
mime_filter_t *filterptr; /* MIME filter */
|
||
|
||
|
||
/*
|
||
* Parse the filter string; it should be in one of the following formats:
|
||
*
|
||
* source/type cost program
|
||
* source/type cost maxsize(nnnn) program
|
||
* source/type dest/type cost program
|
||
* source/type dest/type cost maxsize(nnnn) program
|
||
*/
|
||
|
||
if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
|
||
super, type, dsuper, dtype, &cost, program) == 6)
|
||
{
|
||
snprintf(dest, sizeof(dest), "%s/%s/%s", filtertype->type, dsuper, dtype);
|
||
|
||
if ((desttype = mimeType(mime, "printer", dest)) == NULL)
|
||
desttype = mimeAddType(mime, "printer", dest);
|
||
}
|
||
else
|
||
{
|
||
if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
|
||
program) == 4)
|
||
{
|
||
desttype = filtertype;
|
||
}
|
||
else
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Invalid filter string \"%s\"."), command,
|
||
filter);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (!strncmp(program, "maxsize(", 8))
|
||
{
|
||
char *ptr; /* Pointer into maxsize(nnnn) program */
|
||
|
||
maxsize = (size_t)strtoll(program + 8, &ptr, 10);
|
||
|
||
if (*ptr != ')')
|
||
{
|
||
printf("testmime: Invalid filter string \"%s\".\n", filter);
|
||
return;
|
||
}
|
||
|
||
ptr ++;
|
||
while (_cups_isspace(*ptr))
|
||
ptr ++;
|
||
|
||
_cups_strcpy(program, ptr);
|
||
}
|
||
|
||
/*
|
||
* See if the filter program exists; if not, stop the printer and flag
|
||
* the error!
|
||
*/
|
||
|
||
if (strcmp(program, "-"))
|
||
{
|
||
char filename[1024]; /* Full path to program */
|
||
|
||
if (program[0] == '/')
|
||
strlcpy(filename, program, sizeof(filename));
|
||
else
|
||
snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
|
||
|
||
if (_cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !geteuid(), check_cb,
|
||
(void *)command))
|
||
return;
|
||
}
|
||
|
||
/*
|
||
* Add the filter to the MIME database, supporting wildcards as needed...
|
||
*/
|
||
|
||
for (temptype = mimeFirstType(mime);
|
||
temptype;
|
||
temptype = mimeNextType(mime))
|
||
if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
|
||
!_cups_strcasecmp(temptype->super, super)) &&
|
||
(type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
|
||
{
|
||
if (desttype != filtertype)
|
||
{
|
||
filterptr = mimeAddFilter(mime, temptype, desttype, cost, program);
|
||
|
||
if (!mimeFilterLookup(mime, desttype, filtertype))
|
||
mimeAddFilter(mime, desttype, filtertype, 0, "-");
|
||
}
|
||
else
|
||
filterptr = mimeAddFilter(mime, temptype, filtertype, cost, program);
|
||
|
||
if (filterptr)
|
||
filterptr->maxsize = maxsize;
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* 'add_printer_filters()' - Add filters from a PPD file.
|
||
*/
|
||
|
||
static mime_type_t * /* O - Printer type or NULL on error */
|
||
add_printer_filters(
|
||
const char *command, /* I - Command name */
|
||
mime_t *mime, /* I - MIME database */
|
||
const char *printer, /* I - Printer name */
|
||
const char *ppdfile, /* I - PPD file */
|
||
mime_type_t **prefilter_type) /* O - Prefilter type */
|
||
{
|
||
ppd_file_t *ppd; /* PPD file data */
|
||
_ppd_cache_t *pc; /* Cache data for PPD */
|
||
const char *value; /* Filter definition value */
|
||
mime_type_t *printer_type; /* Printer filter type */
|
||
|
||
|
||
if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_NONE)) == NULL)
|
||
{
|
||
ppd_status_t status; /* PPD load status */
|
||
int linenum; /* Line number */
|
||
|
||
status = ppdLastError(&linenum);
|
||
_cupsLangPrintf(stderr, _("%s: Unable to open PPD file: %s on line %d."),
|
||
command, ppdErrorString(status), linenum);
|
||
return (NULL);
|
||
}
|
||
|
||
pc = _ppdCacheCreateWithPPD(ppd);
|
||
if (!pc)
|
||
return (NULL);
|
||
|
||
printer_type = mimeAddType(mime, "printer", printer);
|
||
*prefilter_type = NULL;
|
||
|
||
if (pc->filters)
|
||
{
|
||
for (value = (const char *)cupsArrayFirst(pc->filters);
|
||
value;
|
||
value = (const char *)cupsArrayNext(pc->filters))
|
||
add_printer_filter(command, mime, printer_type, value);
|
||
}
|
||
else
|
||
{
|
||
add_printer_filter(command, mime, printer_type,
|
||
"application/vnd.cups-raw 0 -");
|
||
add_printer_filter(command, mime, printer_type,
|
||
"application/vnd.cups-postscript 0 -");
|
||
}
|
||
|
||
if (pc->prefilters)
|
||
{
|
||
*prefilter_type = mimeAddType(mime, "prefilter", printer);
|
||
|
||
for (value = (const char *)cupsArrayFirst(pc->prefilters);
|
||
value;
|
||
value = (const char *)cupsArrayNext(pc->prefilters))
|
||
add_printer_filter(command, mime, *prefilter_type, value);
|
||
}
|
||
|
||
return (printer_type);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'check_cb()' - Callback function for _cupsFileCheck.
|
||
*/
|
||
|
||
static void
|
||
check_cb(void *context, /* I - Context (command name) */
|
||
_cups_fc_result_t result, /* I - Result of check */
|
||
const char *message) /* I - Localized message */
|
||
{
|
||
(void)result;
|
||
|
||
_cupsLangPrintf(stderr, _("%s: %s"), (char *)context, message);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'compare_pids()' - Compare two filter PIDs...
|
||
*/
|
||
|
||
static int /* O - Result of comparison */
|
||
compare_pids(mime_filter_t *a, /* I - First filter */
|
||
mime_filter_t *b) /* I - Second filter */
|
||
{
|
||
/*
|
||
* Because we're particularly lazy, we store the process ID in the "cost"
|
||
* variable...
|
||
*/
|
||
|
||
return (a->cost - b->cost);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'escape_options()' - Convert an options array to a string.
|
||
*/
|
||
|
||
static char * /* O - Option string */
|
||
escape_options(
|
||
int num_options, /* I - Number of options */
|
||
cups_option_t *options) /* I - Options */
|
||
{
|
||
int i; /* Looping var */
|
||
cups_option_t *option; /* Current option */
|
||
size_t bytes; /* Number of bytes needed */
|
||
char *s, /* Option string */
|
||
*sptr, /* Pointer into string */
|
||
*vptr; /* Pointer into value */
|
||
|
||
|
||
/*
|
||
* Figure out the worst-case number of bytes we need for the option string.
|
||
*/
|
||
|
||
for (i = num_options, option = options, bytes = 1; i > 0; i --, option ++)
|
||
bytes += 2 * (strlen(option->name) + strlen(option->value)) + 2;
|
||
|
||
if ((s = malloc(bytes)) == NULL)
|
||
return (NULL);
|
||
|
||
/*
|
||
* Copy the options to the string...
|
||
*/
|
||
|
||
for (i = num_options, option = options, sptr = s; i > 0; i --, option ++)
|
||
{
|
||
if (!strcmp(option->name, "copies"))
|
||
continue;
|
||
|
||
if (sptr > s)
|
||
*sptr++ = ' ';
|
||
|
||
strlcpy(sptr, option->name, bytes - (size_t)(sptr - s));
|
||
sptr += strlen(sptr);
|
||
*sptr++ = '=';
|
||
|
||
for (vptr = option->value; *vptr;)
|
||
{
|
||
if (strchr("\\ \t\n", *vptr))
|
||
*sptr++ = '\\';
|
||
|
||
*sptr++ = *vptr++;
|
||
}
|
||
}
|
||
|
||
*sptr = '\0';
|
||
|
||
return (s);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'exec_filter()' - Execute a single filter.
|
||
*/
|
||
|
||
static int /* O - Process ID or -1 on error */
|
||
exec_filter(const char *filter, /* I - Filter to execute */
|
||
char **argv, /* I - Argument list */
|
||
char **envp, /* I - Environment list */
|
||
int infd, /* I - Stdin file descriptor */
|
||
int outfd) /* I - Stdout file descriptor */
|
||
{
|
||
int pid, /* Process ID */
|
||
fd; /* Temporary file descriptor */
|
||
#if defined(__APPLE__)
|
||
char processPath[1024], /* CFProcessPath environment variable */
|
||
linkpath[1024]; /* Link path for symlinks... */
|
||
int linkbytes; /* Bytes for link path */
|
||
|
||
|
||
/*
|
||
* Add special voodoo magic for macOS - this allows macOS
|
||
* programs to access their bundle resources properly...
|
||
*/
|
||
|
||
if ((linkbytes = readlink(filter, linkpath, sizeof(linkpath) - 1)) > 0)
|
||
{
|
||
/*
|
||
* Yes, this is a symlink to the actual program, nul-terminate and
|
||
* use it...
|
||
*/
|
||
|
||
linkpath[linkbytes] = '\0';
|
||
|
||
if (linkpath[0] == '/')
|
||
snprintf(processPath, sizeof(processPath), "CFProcessPath=%s",
|
||
linkpath);
|
||
else
|
||
snprintf(processPath, sizeof(processPath), "CFProcessPath=%s/%s",
|
||
dirname((char *)filter), linkpath);
|
||
}
|
||
else
|
||
snprintf(processPath, sizeof(processPath), "CFProcessPath=%s", filter);
|
||
|
||
envp[0] = processPath; /* Replace <CFProcessPath> string */
|
||
#endif /* __APPLE__ */
|
||
|
||
if ((pid = fork()) == 0)
|
||
{
|
||
/*
|
||
* Child process goes here...
|
||
*
|
||
* Update stdin/stdout/stderr as needed...
|
||
*/
|
||
|
||
if (infd != 0)
|
||
{
|
||
if (infd < 0)
|
||
infd = open("/dev/null", O_RDONLY);
|
||
|
||
if (infd > 0)
|
||
{
|
||
dup2(infd, 0);
|
||
close(infd);
|
||
}
|
||
}
|
||
|
||
if (outfd != 1)
|
||
{
|
||
if (outfd < 0)
|
||
outfd = open("/dev/null", O_WRONLY);
|
||
|
||
if (outfd > 1)
|
||
{
|
||
dup2(outfd, 1);
|
||
close(outfd);
|
||
}
|
||
}
|
||
|
||
if ((fd = open("/dev/null", O_RDWR)) > 3)
|
||
{
|
||
dup2(fd, 3);
|
||
close(fd);
|
||
}
|
||
fcntl(3, F_SETFL, O_NDELAY);
|
||
|
||
if ((fd = open("/dev/null", O_RDWR)) > 4)
|
||
{
|
||
dup2(fd, 4);
|
||
close(fd);
|
||
}
|
||
fcntl(4, F_SETFL, O_NDELAY);
|
||
|
||
/*
|
||
* Execute command...
|
||
*/
|
||
|
||
execve(filter, argv, envp);
|
||
|
||
perror(filter);
|
||
|
||
exit(errno);
|
||
}
|
||
|
||
return (pid);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'exec_filters()' - Execute filters for the given file and options.
|
||
*/
|
||
|
||
static int /* O - 0 on success, 1 on error */
|
||
exec_filters(mime_type_t *srctype, /* I - Source type */
|
||
cups_array_t *filters, /* I - Array of filters to run */
|
||
const char *infile, /* I - File to filter */
|
||
const char *outfile, /* I - File to create */
|
||
const char *ppdfile, /* I - PPD file, if any */
|
||
const char *printer, /* I - Printer name */
|
||
const char *user, /* I - Username */
|
||
const char *title, /* I - Job title */
|
||
int num_options, /* I - Number of filter options */
|
||
cups_option_t *options) /* I - Filter options */
|
||
{
|
||
int i; /* Looping var */
|
||
const char *argv[8], /* Command-line arguments */
|
||
*envp[21], /* Environment variables */
|
||
*temp; /* Temporary string */
|
||
char *optstr, /* Filter options */
|
||
content_type[1024], /* CONTENT_TYPE */
|
||
cups_datadir[1024], /* CUPS_DATADIR */
|
||
cups_fontpath[1024], /* CUPS_FONTPATH */
|
||
cups_serverbin[1024], /* CUPS_SERVERBIN */
|
||
cups_serverroot[1024], /* CUPS_SERVERROOT */
|
||
final_content_type[1024] = "",
|
||
/* FINAL_CONTENT_TYPE */
|
||
lang[1024], /* LANG */
|
||
path[1024], /* PATH */
|
||
ppd[1024], /* PPD */
|
||
printer_info[255], /* PRINTER_INFO env variable */
|
||
printer_location[255], /* PRINTER_LOCATION env variable */
|
||
printer_name[255], /* PRINTER env variable */
|
||
userenv[1024], /* USER */
|
||
#if CUPS_SNAP
|
||
fontconfig_file[1024], /* FONTCONFIG_FILE */
|
||
fontconfig_path[1024], /* FONTCONFIG_PATH */
|
||
fontconfig_sysroot[1024],
|
||
/* FONTCONFIG_SYSROOT */
|
||
ld_library_path[2048], /* LD_LIBRARY_PATH */
|
||
#endif /* CUPS_SNAP */
|
||
program[1024]; /* Program to run */
|
||
mime_filter_t *filter, /* Current filter */
|
||
*next; /* Next filter */
|
||
int current, /* Current filter */
|
||
filterfds[2][2], /* Pipes for filters */
|
||
pid, /* Process ID of filter */
|
||
status, /* Exit status */
|
||
retval; /* Return value */
|
||
cups_array_t *pids; /* Executed filters array */
|
||
mime_filter_t key; /* Search key for filters */
|
||
cups_lang_t *language; /* Current language */
|
||
cups_dest_t *dest; /* Destination information */
|
||
|
||
|
||
/*
|
||
* Figure out the final content type...
|
||
*/
|
||
|
||
for (filter = (mime_filter_t *)cupsArrayLast(filters);
|
||
filter && filter->dst;
|
||
filter = (mime_filter_t *)cupsArrayPrev(filters))
|
||
if (strcmp(filter->dst->super, "printer"))
|
||
break;
|
||
|
||
if (filter && filter->dst)
|
||
{
|
||
const char *ptr; /* Pointer in type name */
|
||
|
||
if ((ptr = strchr(filter->dst->type, '/')) != NULL)
|
||
snprintf(final_content_type, sizeof(final_content_type),
|
||
"FINAL_CONTENT_TYPE=%s", ptr + 1);
|
||
else
|
||
snprintf(final_content_type, sizeof(final_content_type),
|
||
"FINAL_CONTENT_TYPE=%s/%s", filter->dst->super,
|
||
filter->dst->type);
|
||
}
|
||
|
||
/*
|
||
* Remove NULL ("-") filters...
|
||
*/
|
||
|
||
for (filter = (mime_filter_t *)cupsArrayFirst(filters);
|
||
filter;
|
||
filter = (mime_filter_t *)cupsArrayNext(filters))
|
||
if (!strcmp(filter->filter, "-"))
|
||
cupsArrayRemove(filters, filter);
|
||
|
||
/*
|
||
* Setup the filter environment and command-line...
|
||
*/
|
||
|
||
optstr = escape_options(num_options, options);
|
||
|
||
snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s",
|
||
srctype->super, srctype->type);
|
||
snprintf(cups_datadir, sizeof(cups_datadir), "CUPS_DATADIR=%s", DataDir);
|
||
snprintf(cups_serverbin, sizeof(cups_serverbin), "CUPS_SERVERBIN=%s",
|
||
ServerBin);
|
||
snprintf(cups_serverroot, sizeof(cups_serverroot), "CUPS_SERVERROOT=%s",
|
||
ServerRoot);
|
||
language = cupsLangDefault();
|
||
snprintf(lang, sizeof(lang), "LANG=%s.UTF8", language->language);
|
||
snprintf(path, sizeof(path), "PATH=%s", Path);
|
||
if (ppdfile)
|
||
snprintf(ppd, sizeof(ppd), "PPD=%s", ppdfile);
|
||
else if ((temp = getenv("PPD")) != NULL)
|
||
snprintf(ppd, sizeof(ppd), "PPD=%s", temp);
|
||
else
|
||
#ifdef __APPLE__
|
||
if (!access("/System/Library/Frameworks/ApplicationServices.framework/"
|
||
"Versions/A/Frameworks/PrintCore.framework/Versions/A/"
|
||
"Resources/English.lproj/Generic.ppd", 0))
|
||
strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
|
||
"Versions/A/Frameworks/PrintCore.framework/Versions/A/"
|
||
"Resources/English.lproj/Generic.ppd", sizeof(ppd));
|
||
else
|
||
strlcpy(ppd, "PPD=/System/Library/Frameworks/ApplicationServices.framework/"
|
||
"Versions/A/Frameworks/PrintCore.framework/Versions/A/"
|
||
"Resources/Generic.ppd", sizeof(ppd));
|
||
#else
|
||
snprintf(ppd, sizeof(ppd), "PPD=%s/model/laserjet.ppd", DataDir);
|
||
#endif /* __APPLE__ */
|
||
|
||
snprintf(userenv, sizeof(userenv), "USER=%s", user);
|
||
|
||
if (printer &&
|
||
(dest = cupsGetNamedDest(CUPS_HTTP_DEFAULT, printer, NULL)) != NULL)
|
||
{
|
||
if ((temp = cupsGetOption("printer-info", dest->num_options,
|
||
dest->options)) != NULL)
|
||
snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", temp);
|
||
else
|
||
snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s", printer);
|
||
|
||
if ((temp = cupsGetOption("printer-location", dest->num_options,
|
||
dest->options)) != NULL)
|
||
snprintf(printer_location, sizeof(printer_location),
|
||
"PRINTER_LOCATION=%s", temp);
|
||
else
|
||
strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
|
||
sizeof(printer_location));
|
||
}
|
||
else
|
||
{
|
||
snprintf(printer_info, sizeof(printer_info), "PRINTER_INFO=%s",
|
||
printer ? printer : "Unknown");
|
||
strlcpy(printer_location, "PRINTER_LOCATION=Unknown",
|
||
sizeof(printer_location));
|
||
}
|
||
|
||
snprintf(printer_name, sizeof(printer_name), "PRINTER=%s",
|
||
printer ? printer : "Unknown");
|
||
|
||
argv[0] = (char *)printer;
|
||
argv[1] = "1";
|
||
argv[2] = user;
|
||
argv[3] = title;
|
||
argv[4] = cupsGetOption("copies", num_options, options);
|
||
argv[5] = optstr;
|
||
argv[6] = infile;
|
||
argv[7] = NULL;
|
||
|
||
if (!argv[4])
|
||
argv[4] = "1";
|
||
|
||
for (i = 0; argv[i]; i ++)
|
||
fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]);
|
||
|
||
i = 0;
|
||
#ifdef __APPLE__
|
||
envp[i ++] = "<CFProcessPath>";
|
||
#endif /* __APPLE__ */
|
||
envp[i ++] = content_type;
|
||
envp[i ++] = cups_datadir;
|
||
envp[i ++] = cups_fontpath;
|
||
envp[i ++] = cups_serverbin;
|
||
envp[i ++] = cups_serverroot;
|
||
envp[i ++] = lang;
|
||
envp[i ++] = path;
|
||
envp[i ++] = ppd;
|
||
envp[i ++] = printer_info;
|
||
envp[i ++] = printer_location;
|
||
envp[i ++] = printer_name;
|
||
envp[i ++] = userenv;
|
||
envp[i ++] = "CHARSET=utf-8";
|
||
if (final_content_type[0])
|
||
envp[i ++] = final_content_type;
|
||
|
||
#if CUPS_SNAP
|
||
if ((temp = getenv("FONTCONFIG_FILE")) != NULL)
|
||
{
|
||
snprintf(fontconfig_file, sizeof(fontconfig_file), "FONTCONFIG_FILE=%s", temp);
|
||
envp[i ++] = fontconfig_file;
|
||
}
|
||
if ((temp = getenv("FONTCONFIG_PATH")) != NULL)
|
||
{
|
||
snprintf(fontconfig_path, sizeof(fontconfig_path), "FONTCONFIG_PATH=%s", temp);
|
||
envp[i ++] = fontconfig_path;
|
||
}
|
||
if ((temp = getenv("FONTCONFIG_SYSROOT")) != NULL)
|
||
{
|
||
snprintf(fontconfig_sysroot, sizeof(fontconfig_sysroot), "FONTCONFIG_SYSROOT=%s", temp);
|
||
envp[i ++] = fontconfig_sysroot;
|
||
}
|
||
if ((temp = getenv("LD_LIBRARY_PATH")) != NULL)
|
||
{
|
||
snprintf(ld_library_path, sizeof(ld_library_path), "LD_LIBRARY_PATH=%s", temp);
|
||
envp[i ++] = ld_library_path;
|
||
}
|
||
#endif /* CUPS_SNAP */
|
||
|
||
envp[i] = NULL;
|
||
|
||
for (i = 0; envp[i]; i ++)
|
||
fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]);
|
||
|
||
/*
|
||
* Execute all of the filters...
|
||
*/
|
||
|
||
pids = cupsArrayNew((cups_array_func_t)compare_pids, NULL);
|
||
current = 0;
|
||
filterfds[0][0] = -1;
|
||
filterfds[0][1] = -1;
|
||
filterfds[1][0] = -1;
|
||
filterfds[1][1] = -1;
|
||
|
||
if (!infile)
|
||
filterfds[0][0] = 0;
|
||
|
||
for (filter = (mime_filter_t *)cupsArrayFirst(filters);
|
||
filter;
|
||
filter = next, current = 1 - current)
|
||
{
|
||
next = (mime_filter_t *)cupsArrayNext(filters);
|
||
|
||
if (filter->filter[0] == '/')
|
||
strlcpy(program, filter->filter, sizeof(program));
|
||
else
|
||
snprintf(program, sizeof(program), "%s/filter/%s", ServerBin,
|
||
filter->filter);
|
||
|
||
if (filterfds[!current][1] > 1)
|
||
{
|
||
close(filterfds[1 - current][0]);
|
||
close(filterfds[1 - current][1]);
|
||
|
||
filterfds[1 - current][0] = -1;
|
||
filterfds[1 - current][0] = -1;
|
||
}
|
||
|
||
if (next)
|
||
open_pipe(filterfds[1 - current]);
|
||
else if (outfile)
|
||
{
|
||
filterfds[1 - current][1] = open(outfile, O_CREAT | O_TRUNC | O_WRONLY,
|
||
0666);
|
||
|
||
if (filterfds[1 - current][1] < 0)
|
||
fprintf(stderr, "ERROR: Unable to create \"%s\" - %s\n", outfile,
|
||
strerror(errno));
|
||
}
|
||
else
|
||
filterfds[1 - current][1] = 1;
|
||
|
||
pid = exec_filter(program, (char **)argv, (char **)envp,
|
||
filterfds[current][0], filterfds[1 - current][1]);
|
||
|
||
if (pid > 0)
|
||
{
|
||
fprintf(stderr, "INFO: %s (PID %d) started.\n", filter->filter, pid);
|
||
|
||
filter->cost = pid;
|
||
cupsArrayAdd(pids, filter);
|
||
}
|
||
else
|
||
break;
|
||
|
||
argv[6] = NULL;
|
||
}
|
||
|
||
/*
|
||
* Close remaining pipes...
|
||
*/
|
||
|
||
if (filterfds[0][1] > 1)
|
||
{
|
||
close(filterfds[0][0]);
|
||
close(filterfds[0][1]);
|
||
}
|
||
|
||
if (filterfds[1][1] > 1)
|
||
{
|
||
close(filterfds[1][0]);
|
||
close(filterfds[1][1]);
|
||
}
|
||
|
||
/*
|
||
* Wait for the children to exit...
|
||
*/
|
||
|
||
retval = 0;
|
||
|
||
while (cupsArrayCount(pids) > 0)
|
||
{
|
||
if ((pid = wait(&status)) < 0)
|
||
continue;
|
||
|
||
key.cost = pid;
|
||
if ((filter = (mime_filter_t *)cupsArrayFind(pids, &key)) != NULL)
|
||
{
|
||
cupsArrayRemove(pids, filter);
|
||
|
||
if (status)
|
||
{
|
||
if (WIFEXITED(status))
|
||
fprintf(stderr, "ERROR: %s (PID %d) stopped with status %d\n",
|
||
filter->filter, pid, WEXITSTATUS(status));
|
||
else
|
||
fprintf(stderr, "ERROR: %s (PID %d) crashed on signal %d\n",
|
||
filter->filter, pid, WTERMSIG(status));
|
||
|
||
retval = 1;
|
||
}
|
||
else
|
||
fprintf(stderr, "INFO: %s (PID %d) exited with no errors.\n",
|
||
filter->filter, pid);
|
||
}
|
||
}
|
||
|
||
cupsArrayDelete(pids);
|
||
|
||
return (retval);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'get_job_file()' - Get the specified job file.
|
||
*/
|
||
|
||
static void
|
||
get_job_file(const char *job) /* I - Job ID */
|
||
{
|
||
long jobid, /* Job ID */
|
||
docnum; /* Document number */
|
||
const char *jobptr; /* Pointer into job ID string */
|
||
char uri[1024]; /* job-uri */
|
||
http_t *http; /* Connection to server */
|
||
ipp_t *request; /* Request data */
|
||
int tempfd; /* Temporary file */
|
||
|
||
|
||
/*
|
||
* Get the job ID and document number, if any...
|
||
*/
|
||
|
||
if ((jobptr = strrchr(job, '-')) != NULL)
|
||
jobptr ++;
|
||
else
|
||
jobptr = job;
|
||
|
||
jobid = strtol(jobptr, (char **)&jobptr, 10);
|
||
|
||
if (*jobptr == ',')
|
||
docnum = strtol(jobptr + 1, NULL, 10);
|
||
else
|
||
docnum = 1;
|
||
|
||
if (jobid < 1 || jobid > INT_MAX)
|
||
{
|
||
_cupsLangPrintf(stderr, _("cupsfilter: Invalid job ID %d."), (int)jobid);
|
||
exit(1);
|
||
}
|
||
|
||
if (docnum < 1 || docnum > INT_MAX)
|
||
{
|
||
_cupsLangPrintf(stderr, _("cupsfilter: Invalid document number %d."),
|
||
(int)docnum);
|
||
exit(1);
|
||
}
|
||
|
||
/*
|
||
* Ask the server for the document file...
|
||
*/
|
||
|
||
if ((http = httpConnectEncrypt(cupsServer(), ippPort(),
|
||
cupsEncryption())) == NULL)
|
||
{
|
||
_cupsLangPrintf(stderr, _("%s: Unable to connect to server."),
|
||
"cupsfilter");
|
||
exit(1);
|
||
}
|
||
|
||
request = ippNewRequest(CUPS_GET_DOCUMENT);
|
||
|
||
snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%d", (int)jobid);
|
||
|
||
ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", NULL, uri);
|
||
ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_INTEGER, "document-number",
|
||
(int)docnum);
|
||
|
||
if ((tempfd = cupsTempFd(TempFile, sizeof(TempFile))) == -1)
|
||
{
|
||
_cupsLangPrintError("ERROR", _("Unable to create temporary file"));
|
||
httpClose(http);
|
||
exit(1);
|
||
}
|
||
|
||
signal(SIGTERM, sighandler);
|
||
|
||
ippDelete(cupsDoIORequest(http, request, "/", -1, tempfd));
|
||
|
||
close(tempfd);
|
||
|
||
httpClose(http);
|
||
|
||
if (cupsLastError() != IPP_OK)
|
||
{
|
||
_cupsLangPrintf(stderr, _("cupsfilter: Unable to get job file - %s"),
|
||
cupsLastErrorString());
|
||
unlink(TempFile);
|
||
exit(1);
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
* 'open_pipe()' - Create a pipe which is closed on exec.
|
||
*/
|
||
|
||
static int /* O - 0 on success, -1 on error */
|
||
open_pipe(int *fds) /* O - Pipe file descriptors (2) */
|
||
{
|
||
/*
|
||
* Create the pipe...
|
||
*/
|
||
|
||
if (pipe(fds))
|
||
{
|
||
fds[0] = -1;
|
||
fds[1] = -1;
|
||
|
||
return (-1);
|
||
}
|
||
|
||
/*
|
||
* Set the "close on exec" flag on each end of the pipe...
|
||
*/
|
||
|
||
if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
|
||
{
|
||
close(fds[0]);
|
||
close(fds[1]);
|
||
|
||
fds[0] = -1;
|
||
fds[1] = -1;
|
||
|
||
return (-1);
|
||
}
|
||
|
||
if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
|
||
{
|
||
close(fds[0]);
|
||
close(fds[1]);
|
||
|
||
fds[0] = -1;
|
||
fds[1] = -1;
|
||
|
||
return (-1);
|
||
}
|
||
|
||
/*
|
||
* Return 0 indicating success...
|
||
*/
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'read_cups_files_conf()' - Read the cups-files.conf file to get the filter settings.
|
||
*/
|
||
|
||
static int /* O - 0 on success, 1 on error */
|
||
read_cups_files_conf(
|
||
const char *filename) /* I - File to read */
|
||
{
|
||
cups_file_t *fp; /* cups-files.conf file */
|
||
const char *temp; /* Temporary string */
|
||
char line[1024], /* Line from file */
|
||
*ptr; /* Pointer into line */
|
||
int linenum; /* Current line number */
|
||
|
||
|
||
if ((temp = getenv("CUPS_DATADIR")) != NULL)
|
||
set_string(&DataDir, temp);
|
||
else
|
||
set_string(&DataDir, CUPS_DATADIR);
|
||
|
||
if ((temp = getenv("CUPS_SERVERBIN")) != NULL)
|
||
set_string(&ServerBin, temp);
|
||
else
|
||
set_string(&ServerBin, CUPS_SERVERBIN);
|
||
|
||
strlcpy(line, filename, sizeof(line));
|
||
if ((ptr = strrchr(line, '/')) != NULL)
|
||
*ptr = '\0';
|
||
else
|
||
getcwd(line, sizeof(line));
|
||
|
||
set_string(&ServerRoot, line);
|
||
|
||
if ((fp = cupsFileOpen(filename, "r")) != NULL)
|
||
{
|
||
linenum = 0;
|
||
|
||
while (cupsFileGetConf(fp, line, sizeof(line), &ptr, &linenum))
|
||
{
|
||
if (!_cups_strcasecmp(line, "DataDir"))
|
||
set_string(&DataDir, ptr);
|
||
else if (!_cups_strcasecmp(line, "ServerBin"))
|
||
set_string(&ServerBin, ptr);
|
||
else if (!_cups_strcasecmp(line, "ServerRoot"))
|
||
set_string(&ServerRoot, ptr);
|
||
}
|
||
|
||
cupsFileClose(fp);
|
||
}
|
||
|
||
#if CUPS_SNAP
|
||
if ((temp = getenv("PATH")) != NULL)
|
||
snprintf(line, sizeof(line), "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":%s", ServerBin, temp);
|
||
else
|
||
#endif /* CUPS_SNAP */
|
||
snprintf(line, sizeof(line), "%s/filter:" CUPS_BINDIR ":" CUPS_SBINDIR ":/bin:/usr/bin", ServerBin);
|
||
set_string(&Path, line);
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'set_string()' - Copy and set a string.
|
||
*/
|
||
|
||
static void
|
||
set_string(char **s, /* O - Copy of string */
|
||
const char *val) /* I - String to copy */
|
||
{
|
||
if (*s)
|
||
free(*s);
|
||
|
||
*s = strdup(val);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'sighandler()' - Signal catcher for when we print from stdin...
|
||
*/
|
||
|
||
static void
|
||
sighandler(int s) /* I - Signal number */
|
||
{
|
||
/*
|
||
* Remove the temporary file we're using to print a job file...
|
||
*/
|
||
|
||
if (TempFile[0])
|
||
unlink(TempFile);
|
||
|
||
/*
|
||
* Exit...
|
||
*/
|
||
|
||
exit(s);
|
||
}
|
||
|
||
|
||
/*
|
||
* 'usage()' - Show program usage...
|
||
*/
|
||
|
||
static void
|
||
usage(const char *opt) /* I - Incorrect option, if any */
|
||
{
|
||
if (opt)
|
||
_cupsLangPrintf(stderr, _("%s: Unknown option \"%c\"."), "cupsfilter", *opt);
|
||
|
||
_cupsLangPuts(stdout, _("Usage: cupsfilter [ options ] [ -- ] filename"));
|
||
_cupsLangPuts(stdout, _("Options:"));
|
||
_cupsLangPuts(stdout, _(" --list-filters List filters that will be used."));
|
||
_cupsLangPuts(stdout, _(" -D Remove the input file when finished."));
|
||
_cupsLangPuts(stdout, _(" -P filename.ppd Set PPD file."));
|
||
_cupsLangPuts(stdout, _(" -U username Specify username."));
|
||
_cupsLangPuts(stdout, _(" -c cups-files.conf Set cups-files.conf file to use."));
|
||
_cupsLangPuts(stdout, _(" -d printer Use the named printer."));
|
||
_cupsLangPuts(stdout, _(" -e Use every filter from the PPD file."));
|
||
_cupsLangPuts(stdout, _(" -i mime/type Set input MIME type (otherwise auto-typed)."));
|
||
_cupsLangPuts(stdout, _(" -j job-id[,N] Filter file N from the specified job (default is file 1)."));
|
||
_cupsLangPuts(stdout, _(" -m mime/type Set output MIME type (otherwise application/pdf)."));
|
||
_cupsLangPuts(stdout, _(" -n copies Set number of copies."));
|
||
_cupsLangPuts(stdout, _(" -o name=value Set option(s)."));
|
||
_cupsLangPuts(stdout, _(" -p filename.ppd Set PPD file."));
|
||
_cupsLangPuts(stdout, _(" -t title Set title."));
|
||
_cupsLangPuts(stdout, _(" -u Remove the PPD file when finished."));
|
||
|
||
exit(1);
|
||
}
|