#include <cups/cups.h>
#include <cups/string.h>
#include <cups/i18n.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
static void cancel_job(int sig);
static int job_canceled = 0;
int
main(int argc,
char *argv[])
{
int fd;
char *filename,
tempfile[1024];
char buffer[8192];
int bytes;
int num_options;
cups_option_t *options;
const char *val;
int orientation,
fit;
ppd_file_t *ppd;
ppd_size_t *size;
int pdf_pid,
pdf_argc,
pstops_pid,
pstops_pipe[2],
wait_children,
wait_pid,
wait_status,
exit_status = 0;
char *pdf_argv[100],
pdf_width[255],
pdf_height[255],
pstops_path[1024],
*pstops_argv[7],
*pstops_options,
*pstops_start,
*pstops_end;
const char *cups_serverbin;
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
struct sigaction action;
#endif
setbuf(stderr, NULL);
if (argc < 6 || argc > 7)
{
_cupsLangPrintf(stderr,
_("Usage: %s job user title copies options [filename]\n"),
argv[0]);
return (1);
}
#ifdef HAVE_SIGSET
sigset(SIGTERM, cancel_job);
#elif defined(HAVE_SIGACTION)
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_handler = cancel_job;
sigaction(SIGTERM, &action, NULL);
#else
signal(SIGTERM, cancel_job);
#endif
if (argc == 6)
{
if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
{
_cupsLangPrintError(_("ERROR: Unable to copy PDF file"));
return (1);
}
fprintf(stderr, "DEBUG: pdftops - copying to temp print file \"%s\"\n",
tempfile);
while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
write(fd, buffer, bytes);
close(fd);
filename = tempfile;
}
else
{
filename = argv[6];
tempfile[0] = '\0';
}
ppd = ppdOpenFile(getenv("PPD"));
num_options = cupsParseOptions(argv[5], 0, &options);
ppdMarkDefaults(ppd);
cupsMarkOptions(ppd, num_options, options);
if ((cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL)
cups_serverbin = CUPS_SERVERBIN;
snprintf(pstops_path, sizeof(pstops_path), "%s/filter/pstops",
cups_serverbin);
pstops_options = strdup(argv[5]);
if ((pstops_start = strstr(pstops_options, "fitplot")) != NULL &&
(!pstops_start[7] || isspace(pstops_start[7] & 255)))
{
pstops_end = pstops_start + 7;
if ((pstops_start - pstops_options) >= 2 &&
!strncmp(pstops_start - 2, "no", 2))
pstops_start -= 2;
while (*pstops_end && isspace(*pstops_end & 255))
pstops_end ++;
_cups_strcpy(pstops_start, pstops_end);
}
if ((pstops_start = strstr(pstops_options, "fit-to-page")) != NULL &&
(!pstops_start[11] || isspace(pstops_start[11] & 255)))
{
pstops_end = pstops_start + 11;
if ((pstops_start - pstops_options) >= 2 &&
!strncmp(pstops_start - 2, "no", 2))
pstops_start -= 2;
while (*pstops_end && isspace(*pstops_end & 255))
pstops_end ++;
_cups_strcpy(pstops_start, pstops_end);
}
if ((pstops_start = strstr(pstops_options, "landscape")) != NULL &&
(!pstops_start[9] || isspace(pstops_start[9] & 255)))
{
pstops_end = pstops_start + 9;
if ((pstops_start - pstops_options) >= 2 &&
!strncmp(pstops_start - 2, "no", 2))
pstops_start -= 2;
while (*pstops_end && isspace(*pstops_end & 255))
pstops_end ++;
_cups_strcpy(pstops_start, pstops_end);
}
if ((pstops_start = strstr(pstops_options, "orientation-requested=")) != NULL)
{
pstops_end = pstops_start + 22;
while (*pstops_end && !isspace(*pstops_end & 255))
pstops_end ++;
_cups_strcpy(pstops_start, pstops_end);
}
pstops_argv[0] = argv[0];
pstops_argv[1] = argv[1];
pstops_argv[2] = argv[2];
pstops_argv[3] = argv[3];
pstops_argv[4] = argv[4];
pstops_argv[5] = pstops_options;
pstops_argv[6] = NULL;
#ifdef HAVE_PDFTOPS
pdf_argv[0] = (char *)"pdftops";
pdf_argc = 1;
#else
pdf_argv[0] = (char *)"gs";
pdf_argv[1] = (char *)"-q";
pdf_argv[2] = (char *)"-dNOPAUSE";
pdf_argv[3] = (char *)"-dBATCH";
pdf_argv[4] = (char *)"-dSAFER";
pdf_argv[5] = (char *)"-sDEVICE=pswrite";
pdf_argv[6] = (char *)"-sOUTPUTFILE=%stdout";
pdf_argc = 7;
#endif
if (ppd)
{
if (ppd->language_level == 1)
{
#ifdef HAVE_PDFTOPS
pdf_argv[pdf_argc++] = (char *)"-level1";
pdf_argv[pdf_argc++] = (char *)"-noembtt";
#else
pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=1";
#endif
}
else if (ppd->language_level == 2)
{
#ifdef HAVE_PDFTOPS
pdf_argv[pdf_argc++] = (char *)"-level2";
if (!ppd->ttrasterizer)
pdf_argv[pdf_argc++] = (char *)"-noembtt";
#else
pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=2";
#endif
}
else
#ifdef HAVE_PDFTOPS
pdf_argv[pdf_argc++] = (char *)"-level3";
#else
pdf_argv[pdf_argc++] = (char *)"-dLanguageLevel=3";
#endif
if ((val = cupsGetOption("fitplot", num_options, options)) == NULL)
val = cupsGetOption("fit-to-page", num_options, options);
if (val && strcasecmp(val, "no") && strcasecmp(val, "off") &&
strcasecmp(val, "false"))
fit = 1;
else
fit = 0;
size = ppdPageSize(ppd, NULL);
if (size && fit)
{
orientation = 0;
if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
{
if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
strcasecmp(val, "false") != 0)
orientation = 1;
}
else if ((val = cupsGetOption("orientation-requested", num_options, options)) != NULL)
{
orientation = atoi(val) - 3;
if (orientation >= 2)
orientation ^= 1;
}
#ifdef HAVE_PDFTOPS
if (orientation & 1)
{
snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->length);
snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->width);
}
else
{
snprintf(pdf_width, sizeof(pdf_width), "%.0f", size->width);
snprintf(pdf_height, sizeof(pdf_height), "%.0f", size->length);
}
pdf_argv[pdf_argc++] = (char *)"-paperw";
pdf_argv[pdf_argc++] = pdf_width;
pdf_argv[pdf_argc++] = (char *)"-paperh";
pdf_argv[pdf_argc++] = pdf_height;
pdf_argv[pdf_argc++] = (char *)"-expand";
#else
if (orientation & 1)
{
snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
size->length);
snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
size->width);
}
else
{
snprintf(pdf_width, sizeof(pdf_width), "-dDEVICEWIDTHPOINTS=%.0f",
size->width);
snprintf(pdf_height, sizeof(pdf_height), "-dDEVICEHEIGHTPOINTS=%.0f",
size->length);
}
pdf_argv[pdf_argc++] = pdf_width;
pdf_argv[pdf_argc++] = pdf_height;
#endif
}
}
#ifdef HAVE_PDFTOPS
pdf_argv[pdf_argc++] = filename;
pdf_argv[pdf_argc++] = (char *)"-";
#else
pdf_argv[pdf_argc++] = (char *)"-c";
pdf_argv[pdf_argc++] = (char *)"save pop";
pdf_argv[pdf_argc++] = (char *)"-f";
pdf_argv[pdf_argc++] = filename;
#endif
pdf_argv[pdf_argc] = NULL;
if (pipe(pstops_pipe))
{
_cupsLangPrintError(_("ERROR: Unable to create pipe"));
exit_status = 1;
goto error;
}
if ((pdf_pid = fork()) == 0)
{
dup2(pstops_pipe[1], 1);
close(pstops_pipe[0]);
close(pstops_pipe[1]);
#ifdef HAVE_PDFTOPS
execv(CUPS_PDFTOPS, pdf_argv);
_cupsLangPrintError(_("ERROR: Unable to execute pdftops program"));
#else
execv(CUPS_GHOSTSCRIPT, pdf_argv);
_cupsLangPrintError(_("ERROR: Unable to execute gs program"));
#endif
exit(1);
}
else if (pdf_pid < 0)
{
#ifdef HAVE_PDFTOPS
_cupsLangPrintError(_("ERROR: Unable to execute pdftops program"));
#else
_cupsLangPrintError(_("ERROR: Unable to execute gs program"));
#endif
exit_status = 1;
goto error;
}
fprintf(stderr, "DEBUG: Started filter %s (PID %d)\n", pdf_argv[0], pdf_pid);
if ((pstops_pid = fork()) == 0)
{
dup2(pstops_pipe[0], 0);
close(pstops_pipe[0]);
close(pstops_pipe[1]);
execv(pstops_path, pstops_argv);
_cupsLangPrintError(_("ERROR: Unable to execute pstops program"));
exit(1);
}
else if (pstops_pid < 0)
{
_cupsLangPrintError(_("ERROR: Unable to execute pstops program"));
exit_status = 1;
goto error;
}
fprintf(stderr, "DEBUG: Started filter pstops (PID %d)\n", pstops_pid);
close(pstops_pipe[0]);
close(pstops_pipe[1]);
wait_children = 2;
while (wait_children > 0)
{
while ((wait_pid = wait(&wait_status)) < 0 && errno == EINTR)
{
if (job_canceled)
{
kill(pdf_pid, SIGTERM);
kill(pstops_pid, SIGTERM);
job_canceled = 0;
}
}
if (wait_pid < 0)
break;
wait_children --;
if (wait_status)
{
if (WIFEXITED(wait_status))
{
exit_status = WEXITSTATUS(wait_status);
fprintf(stderr, "DEBUG: PID %d (%s) stopped with status %d!\n",
wait_pid,
#ifdef HAVE_PDFTOPS
wait_pid == pdf_pid ? "pdftops" : "pstops",
#else
wait_pid == pdf_pid ? "gs" : "pstops",
#endif
exit_status);
}
else if (WTERMSIG(wait_status) == SIGTERM)
{
fprintf(stderr,
"DEBUG: PID %d (%s) was terminated normally with signal %d!\n",
wait_pid,
#ifdef HAVE_PDFTOPS
wait_pid == pdf_pid ? "pdftops" : "pstops",
#else
wait_pid == pdf_pid ? "gs" : "pstops",
#endif
exit_status);
}
else
{
exit_status = WTERMSIG(wait_status);
fprintf(stderr, "DEBUG: PID %d (%s) crashed on signal %d!\n", wait_pid,
#ifdef HAVE_PDFTOPS
wait_pid == pdf_pid ? "pdftops" : "pstops",
#else
wait_pid == pdf_pid ? "gs" : "pstops",
#endif
exit_status);
}
}
else
{
fprintf(stderr, "DEBUG: PID %d (%s) exited with no errors.\n", wait_pid,
#ifdef HAVE_PDFTOPS
wait_pid == pdf_pid ? "pdftops" : "pstops");
#else
wait_pid == pdf_pid ? "gs" : "pstops");
#endif
}
}
error:
if (tempfile[0])
unlink(tempfile);
return (exit_status);
}
static void
cancel_job(int sig)
{
(void)sig;
job_canceled = 1;
}