1 /* foomaticrip.c
2 *
3 * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
4 * Copyright (C) 2008 Lars Uebernickel <larsuebernickel@gmx.de>
5 *
6 * This file is part of foomatic-rip.
7 *
8 * Foomatic-rip is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Foomatic-rip is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24 #include "foomaticrip.h"
25 #include "util.h"
26 #include "options.h"
27 #include "pdf.h"
28 #include "postscript.h"
29 #include "process.h"
30 #include "spooler.h"
31 #include "renderer.h"
32 #include "fileconverter.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <strings.h>
37 #include <errno.h>
38 #include <memory.h>
39 #include <ctype.h>
40 #include <stdarg.h>
41 #include <assert.h>
42 #include <unistd.h>
43 #include <sys/wait.h>
44 #include <math.h>
45 #include <signal.h>
46 #include <pwd.h>
47
48 #ifdef HAVE_DBUS
49 #include "colord.h"
50 #endif
51
52 /* Logging */
53 FILE* logh = NULL;
54
_logv(const char * msg,va_list ap)55 void _logv(const char *msg, va_list ap)
56 {
57 if (!logh)
58 return;
59 vfprintf(logh, msg, ap);
60 fflush(logh);
61 }
62
_log(const char * msg,...)63 void _log(const char* msg, ...)
64 {
65 va_list ap;
66 va_start(ap, msg);
67 _logv(msg, ap);
68 va_end(ap);
69 }
70
close_log()71 void close_log()
72 {
73 if (logh && logh != stderr)
74 fclose(logh);
75 }
76
redirect_log_to_stderr()77 int redirect_log_to_stderr()
78 {
79 if (dup2(fileno(logh), fileno(stderr)) < 0) {
80 _log("Could not dup logh to stderr\n");
81 return 0;
82 }
83 return 1;
84 }
85
rip_die(int status,const char * msg,...)86 void rip_die(int status, const char *msg, ...)
87 {
88 va_list ap;
89
90 _log("Process is dying with \"");
91 va_start(ap, msg);
92 _logv(msg, ap);
93 va_end(ap);
94 _log("\", exit stat %d\n", status);
95
96 _log("Cleaning up...\n");
97 kill_all_processes();
98
99 exit(status);
100 }
101
102
103 jobparams_t *job = NULL;
104
get_current_job()105 jobparams_t * get_current_job()
106 {
107 assert(job);
108 return job;
109 }
110
111
112 dstr_t *postpipe = NULL; /* command into which the output of this filter should be piped */
113 FILE *postpipe_fh = NULL;
114
open_postpipe()115 FILE * open_postpipe()
116 {
117 const char *p;
118
119 if (postpipe_fh)
120 return postpipe_fh;
121
122 if (isempty(postpipe->data))
123 return stdout;
124
125 /* Delete possible '|' symbol in the beginning */
126 p = skip_whitespace(postpipe->data);
127 if (*p && *p == '|')
128 p += 1;
129
130 if (start_system_process("postpipe", p, &postpipe_fh, NULL) < 0)
131 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
132 "Cannot execute postpipe %s\n", postpipe->data);
133
134 return postpipe_fh;
135 }
136
137
138 char printer_model[256] = "";
139 const char *accounting_prolog = NULL;
140 char attrpath[256] = "";
141
142
143 int spooler = SPOOLER_DIRECT;
144 int do_docs = 0;
145 int dontparse = 0;
146 int jobhasjcl;
147 int pdfconvertedtops;
148
149 /* Variable for PPR's backend interface name (parallel, tcpip, atalk, ...) */
150 char backend [64];
151
152 /* Array to collect unknown options so that they can get passed to the
153 backend interface of PPR. For other spoolers we ignore them. */
154 dstr_t *backendoptions = NULL;
155
156 /* These variables were in 'dat' before */
157 char colorprofile [128];
158 char cupsfilter[256];
159 char **jclprepend = NULL;
160 dstr_t *jclappend;
161
162 /* Set debug to 1 to enable the debug logfile for this filter; it will appear
163 * as defined by LOG_FILE. It will contain status from this filter, plus the
164 * renderer's stderr output. You can also add a line "debug: 1" to your
165 * /etc/foomatic/filter.conf to get all your Foomatic filters into debug mode.
166 * WARNING: This logfile is a security hole; do not use in production. */
167 int debug = 0;
168
169 /* Path to the GhostScript which foomatic-rip shall use */
170 char gspath[PATH_MAX] = "gs";
171
172 /* What 'echo' program to use. It needs -e and -n. Linux's builtin
173 and regular echo work fine; non-GNU platforms may need to install
174 gnu echo and put gecho here or something. */
175 char echopath[PATH_MAX] = "echo";
176
177 /* CUPS raster drivers are searched here */
178 char cupsfilterpath[PATH_MAX] = "/usr/local/lib/cups/filter:"
179 "/usr/local/libexec/cups/filter:"
180 "/opt/cups/filter:"
181 "/usr/lib/cups/filter";
182
183 char modern_shell[64] = "/bin/sh";
184
config_set_option(const char * key,const char * value)185 void config_set_option(const char *key, const char *value)
186 {
187 if (strcmp(key, "debug") == 0)
188 debug = atoi(value);
189
190 /* What path to use for filter programs and such. Your printer driver must be
191 * in the path, as must be the renderer, $enscriptcommand, and possibly other
192 * stuff. The default path is often fine on Linux, but may not be on other
193 * systems. */
194 else if (strcmp(key, "execpath") == 0 && !isempty(value))
195 setenv("PATH", value, 1);
196
197 else if (strcmp(key, "cupsfilterpath") == 0)
198 strlcpy(cupsfilterpath, value, PATH_MAX);
199 else if (strcmp(key, "preferred_shell") == 0)
200 strlcpy(modern_shell, value, 32);
201 else if (strcmp(key, "textfilter") == 0)
202 set_fileconverter(value);
203 else if (strcmp(key, "gspath") == 0)
204 strlcpy(gspath, value, PATH_MAX);
205 else if (strcmp(key, "echo") == 0)
206 strlcpy(echopath, value, PATH_MAX);
207 }
208
config_from_file(const char * filename)209 void config_from_file(const char *filename)
210 {
211 FILE *fh;
212 char line[256];
213 char *key, *value;
214
215 fh = fopen(filename, "r");
216 if (fh == NULL)
217 return; /* no error here, only read config file if it is present */
218
219 while (fgets(line, 256, fh) != NULL)
220 {
221 key = strtok(line, " :\t\r\n");
222 if (key == NULL || key[0] == '#')
223 continue;
224 value = strtok(NULL, " \t\r\n#");
225 config_set_option(key, value);
226 }
227 fclose(fh);
228 }
229
get_modern_shell()230 const char * get_modern_shell()
231 {
232 return modern_shell;
233 }
234
235 /* returns position in 'str' after the option */
extract_next_option(char * str,char ** pagerange,char ** key,char ** value)236 char * extract_next_option(char *str, char **pagerange, char **key, char **value)
237 {
238 char *p = str;
239 char quotechar;
240
241 *pagerange = NULL;
242 *key = NULL;
243 *value = NULL;
244
245 if (!str)
246 return NULL;
247
248 /* skip whitespace and commas */
249 while (*p && (isspace(*p) || *p == ',')) p++;
250
251 if (!*p)
252 return NULL;
253
254 /* read the pagerange if we have one */
255 if (prefixcmp(p, "even:") == 0 || prefixcmp(p, "odd:") == 0 || isdigit(*p)) {
256 *pagerange = p;
257 p = strchr(p, ':');
258 if (!p)
259 return NULL;
260 *p = '\0';
261 p++;
262 }
263
264 /* read the key */
265 if (*p == '\'' || *p == '\"') {
266 quotechar = *p;
267 *key = p +1;
268 p = strchr(*key, quotechar);
269 if (!p)
270 return NULL;
271 }
272 else {
273 *key = p;
274 while (*p && *p != ':' && *p != '=' && *p != ' ') p++;
275 }
276
277 if (*p != ':' && *p != '=') { /* no value for this option */
278 if (!*p)
279 return NULL;
280 else if (isspace(*p)) {
281 *p = '\0';
282 return p +1;
283 }
284 return p;
285 }
286
287 *p++ = '\0'; /* remove the separator sign */
288
289 if (*p == '\"' || *p == '\'') {
290 quotechar = *p;
291 *value = p +1;
292 p = strchr(*value, quotechar);
293 if (!p)
294 return NULL;
295 *p = '\0';
296 p++;
297 }
298 else {
299 *value = p;
300 while (*p && *p != ' ' && *p != ',') p++;
301 if (*p == '\0')
302 return NULL;
303 *p = '\0';
304 p++;
305 }
306
307 return *p ? p : NULL;
308 }
309
310 /* processes job->optstr */
process_cmdline_options()311 void process_cmdline_options()
312 {
313 char *p, *cmdlineopts, *nextopt, *pagerange, *key, *value;
314 option_t *opt, *opt2;
315 int optset;
316 char tmp [256];
317
318 _log("Printing system options:\n");
319 cmdlineopts = strdup(job->optstr->data);
320 for (nextopt = extract_next_option(cmdlineopts, &pagerange, &key, &value);
321 key;
322 nextopt = extract_next_option(nextopt, &pagerange, &key, &value))
323 {
324 /* Consider only options which are not in the PPD file here */
325 if ((opt = find_option(key)) != NULL) continue;
326 if (value)
327 _log("Pondering option '%s=%s'\n", key, value);
328 else
329 _log("Pondering option '%s'\n", key);
330
331 /* "docs" option to print help page */
332 if (!strcasecmp(key, "docs")) {
333 do_docs = 1;
334 continue;
335 }
336 /* "profile" option to supply a color correction profile to a CUPS raster driver */
337 if (!strcmp(key, "profile")) {
338 strlcpy(colorprofile, value, 128);
339 continue;
340 }
341 /* Solaris options that have no reason to be */
342 if (!strcmp(key, "nobanner") || !strcmp(key, "dest") || !strcmp(key, "protocol"))
343 continue;
344
345 if (pagerange) {
346 snprintf(tmp, 256, "pages:%s", pagerange);
347 optset = optionset(tmp);
348 }
349 else
350 optset = optionset("userval");
351
352 if (value) {
353 /* At first look for the "backend" option to determine the PPR backend to use */
354 if (spooler == SPOOLER_PPR_INT && !strcasecmp(key, "backend")) {
355 /* backend interface name */
356 strlcpy(backend, value, 64);
357 }
358 else if (strcasecmp(key, "media") == 0) {
359 /* Standard arguments?
360 media=x,y,z
361 sides=one|two-sided-long|short-edge
362
363 Rummage around in the media= option for known media, source,
364 etc types.
365 We ought to do something sensible to make the common manual
366 boolean option work when specified as a media= tray thing.
367
368 Note that this fails miserably when the option value is in
369 fact a number; they all look alike. It's unclear how many
370 drivers do that. We may have to standardize the verbose
371 names to make them work as selections, too. */
372
373 p = strtok(value, ",");
374 do {
375 if ((opt = find_option("PageSize")) && option_accepts_value(opt, p))
376 option_set_value(opt, optset, p);
377 else if ((opt = find_option("MediaType")) && option_has_choice(opt, p))
378 option_set_value(opt, optset, p);
379 else if ((opt = find_option("InputSlot")) && option_has_choice(opt, p))
380 option_set_value(opt, optset, p);
381 else if (!strcasecmp(p, "manualfeed")) {
382 /* Special case for our typical boolean manual
383 feeder option if we didn't match an InputSlot above */
384 if ((opt = find_option("ManualFeed")))
385 option_set_value(opt, optset, "1");
386 }
387 else
388 _log("Unknown \"media\" component: \"%s\".\n", p);
389
390 } while ((p = strtok(NULL, ",")));
391 }
392 else if (!strcasecmp(key, "sides")) {
393 /* Handle the standard duplex option, mostly */
394 if (!prefixcasecmp(value, "two-sided")) {
395 if ((opt = find_option("Duplex"))) {
396 /* Default to long-edge binding here, for the case that
397 there is no binding setting */
398 option_set_value(opt, optset, "DuplexNoTumble");
399
400 /* Check the binding: "long edge" or "short edge" */
401 if (strcasestr(value, "long-edge")) {
402 if ((opt2 = find_option("Binding")))
403 option_set_value(opt2, optset, "LongEdge");
404 else
405 option_set_value(opt, optset, "DuplexNoTumble");
406 }
407 else if (strcasestr(value, "short-edge")) {
408 if ((opt2 = find_option("Binding")))
409 option_set_value(opt2, optset, "ShortEdge");
410 else
411 option_set_value(opt, optset, "DuplexNoTumble");
412 }
413 }
414 }
415 else if (!prefixcasecmp(value, "one-sided")) {
416 if ((opt = find_option("Duplex")))
417 option_set_value(opt, optset, "0");
418 }
419
420 /* TODO
421 We should handle the other half of this option - the
422 BindEdge bit. Also, are there well-known ipp/cups options
423 for Collate and StapleLocation? These may be here...
424 */
425 }
426 else if (spooler == SPOOLER_PPR_INT) {
427 /* Unknown option, pass it to PPR's backend interface */
428 if (!backendoptions)
429 backendoptions = create_dstr();
430 dstrcatf(backendoptions, "%s=%s ", key, value);
431 }
432 else
433 _log("Unknown option %s=%s.\n", key, value);
434 }
435 /* Custom paper size */
436 else if ((opt = find_option("PageSize")) && option_set_value(opt, optset, key)) {
437 /* do nothing, if the value could be set, it has been set */
438 }
439 else
440 _log("Unknown boolean option \"%s\".\n", key);
441 }
442 free(cmdlineopts);
443
444 _log("Options from the PPD file:\n");
445 cmdlineopts = strdup(job->optstr->data);
446 for (nextopt = extract_next_option(cmdlineopts, &pagerange, &key, &value);
447 key;
448 nextopt = extract_next_option(nextopt, &pagerange, &key, &value))
449 {
450 /* Consider only PPD file options here */
451 if ((opt = find_option(key)) == NULL) continue;
452 if (value)
453 _log("Pondering option '%s=%s'\n", key, value);
454 else
455 _log("Pondering option '%s'\n", key);
456
457 if (pagerange) {
458 snprintf(tmp, 256, "pages:%s", pagerange);
459 optset = optionset(tmp);
460
461 if (opt && (option_get_section(opt) != SECTION_ANYSETUP &&
462 option_get_section(opt) != SECTION_PAGESETUP)) {
463 _log("This option (%s) is not a \"PageSetup\" or \"AnySetup\" option, so it cannot be restricted to a page range.\n", key);
464 continue;
465 }
466 }
467 else
468 optset = optionset("userval");
469
470 if (value) {
471 /* Various non-standard printer-specific options */
472 if (!option_set_value(opt, optset, value)) {
473 _log(" invalid choice \"%s\", using \"%s\" instead\n",
474 value, option_get_value(opt, optset));
475 }
476 }
477 /* Standard bool args:
478 landscape; what to do here?
479 duplex; we should just handle this one OK now? */
480 else if (!prefixcasecmp(key, "no"))
481 option_set_value(opt, optset, "0");
482 else
483 option_set_value(opt, optset, "1");
484 }
485 free(cmdlineopts);
486 }
487
488 /* checks whether a pdq driver declaration file should be build
489 and returns an opened file handle if so */
check_pdq_file(list_t * arglist)490 FILE * check_pdq_file(list_t *arglist)
491 {
492 /* "--appendpdq=<file>" appends the data to the <file>,
493 "--genpdq=<file>" creates/overwrites <file> for the data, and
494 "--genpdq" writes to standard output */
495
496 listitem_t *i;
497 char filename[256];
498 FILE *handle;
499 char *p;
500 int raw, append;
501
502 if ((i = arglist_find_prefix(arglist, "--genpdq"))) {
503 raw = 0;
504 append = 0;
505 }
506 else if ((i = arglist_find_prefix(arglist, "--genrawpdq"))) {
507 raw = 1;
508 append = 0;
509 }
510 else if ((i = arglist_find_prefix(arglist, "--appendpdq"))) {
511 raw = 0;
512 append = 1;
513 }
514 else if ((i = arglist_find_prefix(arglist, "--appendrawpdq"))) {
515 raw = 1;
516 append = 1;
517 }
518
519 if (!i)
520 return NULL;
521
522 p = strchr((char*)i->data, '=');
523 if (p) {
524 strncpy_omit(filename, p +1, 256, omit_shellescapes);
525 handle = fopen(filename, append ? "a" : "w");
526 if (!handle)
527 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Cannot write PDQ driver declaration file.\n");
528 }
529 else if (!append)
530 handle = stdout;
531 else
532 return NULL;
533
534 /* remove option from args */
535 list_remove(arglist, i);
536
537 /* Do we have a pdq driver declaration for a raw printer */
538 if (raw) {
539 fprintf(handle,
540 "driver \"Raw-Printer-%u\" {\n"
541 " # This PDQ driver declaration file was generated automatically by\n"
542 " # foomatic-rip to allow raw (filter-less) printing.\n"
543 " language_driver all {\n"
544 " # We accept all file types and pass them through without any changes\n"
545 " filetype_regx \"\"\n"
546 " convert_exec {\n"
547 " ln -s $INPUT $OUTPUT\n"
548 " }\n"
549 " }\n"
550 " filter_exec {\n"
551 " ln -s $INPUT $OUTPUT\n"
552 " }\n"
553 "}", (unsigned int)job->time);
554 if (handle != stdout) {
555 fclose(handle);
556 handle = NULL;
557 }
558 exit(EXIT_PRINTED);
559 }
560
561 return handle;
562 }
563
564
565 /* Build a PDQ driver description file to use the given PPD file
566 together with foomatic-rip with the PDQ printing system
567 and output it into 'pdqfile' */
print_pdq_driver(FILE * pdqfile,int optset)568 void print_pdq_driver(FILE *pdqfile, int optset)
569 {
570 }
571 #if 0
572 option_t *opt;
573 value_t *val;
574 setting_t *setting, *setting_true, *setting_false;
575
576 /* Construct option list */
577 dstr_t *driveropts = create_dstr();
578
579 /* Do we have a "Custom" setting for the page size?
580 Then we have to insert the following into the filter_exec script. */
581 dstr_t *setcustompagesize = create_dstr();
582
583 dstr_t *tmp = create_dstr();
584 dstr_t *cmdline = create_dstr();
585 dstr_t *psfilter = create_dstr();
586
587
588 /* 1, if setting "PageSize=Custom" was found
589 Then we must add options for page width and height */
590 int custompagesize = 0;
591
592 /* Data for a custom page size, to allow a custom size as default */
593 int pagewidth = 612;
594 int pageheight = 792;
595 char pageunit[2] = "pt";
596
597 char def [128];
598
599 def[0] = '\0';
600
601 for (opt = optionlist; opt; opt = opt->next) {
602 if (opt->type == TYPE_ENUM) {
603 /* Option with only one choice, omit it, foomatic-rip will set
604 this choice anyway */
605 if (option_setting_count(opt) <= 1)
606 continue;
607
608 /* Omit "PageRegion" option, it does the same as "PageSize" */
609 if (!strcmp(opt->name, "PageRegion"))
610 continue;
611
612 /* 1, if setting "PageSize=Custom" was found
613 Then we must add options for page width and height */
614 custompagesize = 0;
615
616 if ((val = option_get_value(opt, optset)))
617 strlcpy(def, val->value, 128);
618
619 #if 0 TODO not used ?!
620 /* If the default is a custom size we have to set also
621 defaults for the width, height, and units of the page */
622 if (!strcmp(opt->name, "PageSize") && val && value_has_custom_setting(val))
623 strcpy(def, "Custom");
624 #endif
625
626 dstrcatf(driveropts,
627 " option {\n"
628 " var = \"%s\"\n"
629 " desc = \"%s\"\n", opt->varname, option_text(opt));
630
631 /* get enumeration values for each enum arg */
632 dstrclear(tmp);
633 for (setting = opt->settinglist; setting; setting = setting->next) {
634 dstrcatf(tmp,
635 " choice \"%s_%s\" {\n"
636 " desc = \"%s\"\n"
637 " value = \" -o %s=%s\"\n"
638 " }\n",
639 opt->name, setting->value,
640 isempty(setting->comment) ? setting->value : setting->comment,
641 opt->name, setting->value);
642
643 if (!strcmp(opt->name, "PageSize") && !strcmp(setting->value, "Custom")) {
644 custompagesize = 1;
645 if (isempty(setcustompagesize->data)) {
646 dstrcatf(setcustompagesize,
647 " # Custom page size settings\n"
648 " # We aren't really checking for legal vals.\n"
649 " if [ \"x${%s}\" = 'x -o %s=%s' ]; then\n"
650 " %s=\"${%s}.${PageWidth}x${PageHeight}${PageSizeUnit}\"\n"
651 " fi\n\n",
652 opt->varname, opt->varname, setting->value, opt->varname, opt->varname);
653 }
654 }
655 }
656
657 dstrcatf(driveropts, " default_choice \"%s_%s\"\n", opt->name, def);
658 dstrcatf(driveropts, tmp->data);
659 dstrcatf(driveropts, " }\n\n");
660
661 if (custompagesize) {
662 /* Add options to set the custom page size */
663 dstrcatf(driveropts,
664 " argument {\n"
665 " var = \"PageWidth\"\n"
666 " desc = \"Page Width (for \\\"Custom\\\" page size)\"\n"
667 " def_value \"%d\"\n" /* pagewidth */
668 " help = \"Minimum value: 0, Maximum value: 100000\"\n"
669 " }\n\n"
670 " argument {\n"
671 " var = \"PageHeight\"\n"
672 " desc = \"Page Height (for \\\"Custom\\\" page size)\"\n"
673 " def_value \"%d\"\n" /* pageheight */
674 " help = \"Minimum value: 0, Maximum value: 100000\"\n"
675 " }\n\n"
676 " option {\n"
677 " var = \"PageSizeUnit\"\n"
678 " desc = \"Unit (for \\\"Custom\\\" page size)\"\n"
679 " default_choice \"PageSizeUnit_%.2s\"\n" /* pageunit */
680 " choice \"PageSizeUnit_pt\" {\n"
681 " desc = \"Points (1/72 inch)\"\n"
682 " value = \"pt\"\n"
683 " }\n"
684 " choice \"PageSizeUnit_in\" {\n"
685 " desc = \"Inches\"\n"
686 " value = \"in\"\n"
687 " }\n"
688 " choice \"PageSizeUnit_cm\" {\n"
689 " desc = \"cm\"\n"
690 " value = \"cm\"\n"
691 " }\n"
692 " choice \"PageSizeUnit_mm\" {\n"
693 " desc = \"mm\"\n"
694 " value = \"mm\"\n"
695 " }\n"
696 " }\n\n",
697 pagewidth, pageheight, pageunit);
698 }
699 }
700 else if (opt->type == TYPE_INT || opt->type == TYPE_FLOAT) {
701 /* Assure that the comment is not emtpy */
702 if (isempty(opt->comment))
703 strcpy(opt->comment, opt->name);
704
705 if ((val = option_get_value(opt, optset)))
706 strlcpy(def, val->value, 128);
707
708 strcpy(opt->varname, opt->name);
709 strrepl(opt->varname, "-/.", '_');
710
711
712 dstrcatf(driveropts,
713 " argument {\n"
714 " var = \"%s\"\n"
715 " desc = \"%s\"\n"
716 " def_value \"%s\"\n"
717 " help = \"Minimum value: %s, Maximum value: %s\"\n"
718 " }\n\n",
719 opt->varname, opt->comment, def, opt->min, opt->max);
720 }
721 else if (opt->type == TYPE_BOOL) {
722 /* Assure that the comment is not emtpy */
723 if (isempty(opt->comment))
724 strcpy(opt->comment, opt->name);
725
726 if ((val = option_get_value(opt, optset)))
727 strlcpy(def, val->value, 128);
728 strcpy(opt->varname, opt->name);
729 strrepl(opt->varname, "-/.", '_');
730 setting_true = option_find_setting(opt, "true");
731 setting_false = option_find_setting(opt, "false");
732
733 dstrcatf(driveropts,
734 " option {\n"
735 " var = \"%s\"\n"
736 " desc = \"%s\"\n", opt->varname, opt->comment);
737
738 if (!isempty(def) && !strcasecmp(def, "true"))
739 dstrcatf(driveropts, " default_choice \"%s\"\n", def);
740 else
741 dstrcatf(driveropts, " default_choice \"no%s\"\n", def);
742
743 dstrcatf(driveropts,
744 " choice \"%s\" {\n"
745 " desc = \"%s\"\n"
746 " value = \" -o %s=True\"\n"
747 " }\n"
748 " choice \"no%s\" {\n"
749 " desc = \"%s\"\n"
750 " value = \" -o %s=False\"\n"
751 " }\n"
752 " }\n\n",
753 opt->name, setting_true->comment, opt->name,
754 opt->name, setting_false->comment, opt->name);
755 }
756 else if (opt->type == TYPE_STRING) {
757 /* Assure that the comment is not emtpy */
758 if (isempty(opt->comment))
759 strcpy(opt->comment, opt->name);
760
761 if ((val = option_get_value(opt, optset)))
762 strlcpy(def, val->value, 128);
763 strcpy(opt->varname, opt->name);
764 strrepl_nodups(opt->varname, "-/.", '_');
765
766 dstrclear(tmp);
767 if (opt->maxlength)
768 dstrcatf(tmp, "Maximum Length: %s characters, ", opt->maxlength);
769
770 dstrcatf(tmp, "Examples/special settings: ");
771 for (setting = opt->settinglist; setting; setting = setting->next) {
772 /* Retrieve the original string from the prototype and the driverval */
773 /* TODO perl code for this part doesn't make sense to me */
774 }
775 }
776 }
777
778 /* Define the "docs" option to print the driver documentation page */
779 dstrcatf(driveropts,
780 " option {\n"
781 " var = \"DRIVERDOCS\"\n"
782 " desc = \"Print driver usage information\"\n"
783 " default_choice \"nodocs\"\n"
784 " choice \"docs\" {\n"
785 " desc = \"Yes\"\n"
786 " value = \" -o docs\"\n"
787 " }\n"
788 " choice \"nodocs\" {\n"
789 " desc = \"No\"\n"
790 " value = \"\"\n"
791 " }\n"
792 " }\n\n");
793
794 /* Build the foomatic-rip command line */
795 dstrcatf(cmdline, "foomatic-rip --pdq");
796 if (!isempty(printer)) {
797 dstrcatf(cmdline, " -P %s", printer);
798 }
799 else {
800 /* Make sure that the PPD file is entered with an absolute path */
801 make_absolute_path(job->ppdfile, 256);
802 dstrcatf(cmdline, " --ppd=%s", job->ppdfile);
803 }
804
805 for (opt = optionlist; opt; opt = opt->next) {
806 if (!isempty(opt->varname))
807 dstrcatf(cmdline, "${%s}", opt->varname);
808 }
809 dstrcatf(cmdline, "${DRIVERDOCS} $INPUT > $OUTPUT");
810
811
812 /* Now we generate code to build the command line snippets for the numerical options */
813 for (opt = optionlist; opt; opt = opt->next) {
814 /* Only numerical and string options need to be treated here */
815 if (opt->type != TYPE_INT &&
816 opt->type != TYPE_FLOAT &&
817 opt->type != TYPE_STRING)
818 continue;
819
820 /* If the option's variable is non-null, put in the
821 argument. Otherwise this option is the empty
822 string. Error checking? */
823 dstrcatf(psfilter, " # %s\n", opt->comment);
824 if (opt->type == TYPE_INT || opt->type == TYPE_FLOAT) {
825 dstrcatf(psfilter,
826 " # We aren't really checking for max/min,\n"
827 " # this is done by foomatic-rip\n"
828 " if [ \"x${%s}\" != 'x' ]; then\n ", opt->varname);
829 }
830
831 dstrcatf(psfilter, " %s=\" -o %s='${%s}'\"\n", opt->varname, opt->name, opt->varname);
832
833 if (opt->type == TYPE_INT || opt->type == TYPE_FLOAT)
834 dstrcatf(psfilter, " fi\n");
835 dstrcatf(psfilter, "\n");
836 }
837
838 /* Command execution */
839 dstrcatf(psfilter,
840 " if ! test -e $INPUT.ok; then\n"
841 " sh -c \"%s\"\n"
842 " if ! test -e $OUTPUT; then \n"
843 " echo 'Error running foomatic-rip; no output!'\n"
844 " exit 1\n"
845 " fi\n"
846 " else\n"
847 " ln -s $INPUT $OUTPUT\n"
848 " fi\n\n", cmdline->data);
849
850
851 dstrclear(tmp);
852 dstrcatf(tmp, "%s", printer_model);
853 strrepl_nodups(tmp->data, " \t\n.,;/()[]{}+*", '-');
854 tmp->len = strlen(tmp->data); /* length could have changed */
855 if (tmp->data[tmp->len -1] == '-') {
856 tmp->data[--tmp->len] = '\0';
857 }
858
859
860 fprintf(pdqfile,
861 "driver \"%s-%u\" {\n\n"
862 " # This PDQ driver declaration file was generated automatically by\n"
863 " # foomatic-rip from information in the file %s.\n" /* ppdfile */
864 " # It allows printing with PDQ on the %s.\n" /* model */
865 "\n"
866 " requires \"foomatic-rip\"\n\n"
867 "%s" /* driveropts */
868 " language_driver all {\n"
869 " # We accept all file types and pass them to foomatic-rip\n"
870 " # (invoked in \"filter_exec {}\" section) without\n"
871 " # pre-filtering\n"
872 " filetype_regx \"\"\n"
873 " convert_exec {\n"
874 " ln -s $INPUT $OUTPUT\n"
875 " }\n"
876 " }\n\n"
877 " filter_exec {\n"
878 "%s" /* setcustompagesize */
879 "%s" /* psfilter */
880 " }\n"
881 "}\n",
882 tmp->data, /* cleaned printer_model */ (unsigned int)job->time, job->ppdfile, printer_model,
883 driveropts->data, setcustompagesize->data, psfilter->data);
884
885
886 free_dstr(setcustompagesize);
887 free_dstr(driveropts);
888 free_dstr(tmp);
889 free_dstr(cmdline);
890 free_dstr(psfilter);
891 }
892 #endif
893
894 /* Functions to let foomatic-rip fork to do several tasks in parallel.
895
896 To do the filtering without loading the whole file into memory we work
897 on a data stream, we read the data line by line analyse it to decide what
898 filters to use and start the filters if we have found out which we need.
899 We buffer the data only as long as we didn't determing which filters to
900 use for this piece of data and with which options. There are no temporary
901 files used.
902
903 foomatic-rip splits into up to 6 parallel processes to do the whole
904 filtering (listed in the order of the data flow):
905
906 KID0: Generate documentation pages (only jobs with "docs" option)
907 KID2: Put together already read data and current input stream for
908 feeding into the file conversion filter (only non-PostScript
909 and "docs" jobs)
910 KID1: Run the file conversion filter to convert non-PostScript
911 input into PostScript (only non-PostScript and "docs" jobs)
912 MAIN: Prepare the job auto-detecting the spooler, reading the PPD,
913 extracting the options from the command line, and parsing
914 the job data itself. It analyses the job data to check
915 whether it is PostScript and starts KID1/KID2 if not, it
916 also stuffs PostScript code from option settings into the
917 PostScript data stream. It starts the renderer (KID3/KID4)
918 as soon as it knows its command line and restarts it when
919 page-specific option settings need another command line
920 or different JCL commands.
921 KID3: The rendering process. In most cases Ghostscript, "cat"
922 for native PostScript printers with their manufacturer's
923 PPD files.
924 KID4: Put together the JCL commands and the renderer's output
925 and send all that either to STDOUT or pipe it into the
926 command line defined with $postpipe. */
927
928
929
write_output(void * data,size_t len)930 void write_output(void *data, size_t len)
931 {
932 const char *p = (const char *)data;
933 size_t left = len;
934 FILE *postpipe = open_postpipe();
935
936 /* Remove leading whitespace */
937 while (isspace(*p++) && left-- > 0)
938 ;
939
940 fwrite((void *)p, left, 1, postpipe);
941 fflush(postpipe);
942 }
943
944 enum FileType {
945 UNKNOWN_FILE,
946 PDF_FILE,
947 PS_FILE
948 };
949
guess_file_type(const char * begin,size_t len,int * startpos)950 int guess_file_type(const char *begin, size_t len, int *startpos)
951 {
952 const char * p, * end;
953 p = begin;
954 end = begin + len;
955
956 while (p < end)
957 {
958 p = memchr(p, '%', end - p);
959 if (!p)
960 return UNKNOWN_FILE;
961 *startpos = p - begin;
962 if ((end - p) > 2 && !memcmp(p, "%!", 2))
963 return PS_FILE;
964 else if ((end - p) > 7 && !memcmp(p, "%PDF-1.", 7))
965 return PDF_FILE;
966 ++ p;
967 }
968 *startpos = 0;
969 return UNKNOWN_FILE;
970 }
971
972 /*
973 * Prints 'filename'. If 'convert' is true, the file will be converted if it is
974 * not postscript or pdf
975 */
print_file(const char * filename,int convert)976 int print_file(const char *filename, int convert)
977 {
978 FILE *file;
979 char buf[8192];
980 int type;
981 int startpos;
982 size_t n;
983 FILE *fchandle = NULL;
984 int fcpid = 0, ret;
985
986 if (!strcasecmp(filename, "<STDIN>"))
987 file = stdin;
988 else {
989 file = fopen(filename, "r");
990 if (!file) {
991 _log("Could not open \"%s\" for reading\n", filename);
992 return 0;
993 }
994 }
995
996 n = fread(buf, 1, sizeof(buf) - 1, file);
997 buf[n] = '\0';
998 type = guess_file_type(buf, n, &startpos);
999 /* We do not use any JCL preceeded to the inputr data, as it is simply
1000 the PJL commands from the PPD file, and these commands we can also
1001 generate, end we even merge them with PJl from the driver */
1002 /*if (startpos > 0) {
1003 jobhasjcl = 1;
1004 write_output(buf, startpos);
1005 }*/
1006 if (file != stdin)
1007 rewind(file);
1008
1009 if (convert) pdfconvertedtops = 0;
1010
1011 switch (type) {
1012 case PDF_FILE:
1013 _log("Filetype: PDF\n");
1014
1015 if (!ppd_supports_pdf())
1016 {
1017 char pdf2ps_cmd[PATH_MAX];
1018 FILE *out, *in;
1019 int renderer_pid;
1020 char tmpfilename[PATH_MAX] = "";
1021
1022 _log("Driver does not understand PDF input, "
1023 "converting to PostScript\n");
1024
1025 pdfconvertedtops = 1;
1026
1027 /* If reading from stdin, write everything into a temporary file */
1028 if (file == stdin)
1029 {
1030 int fd;
1031 FILE *tmpfile;
1032
1033 snprintf(tmpfilename, PATH_MAX, "%s/foomatic-XXXXXX", temp_dir());
1034 fd = mkstemp(tmpfilename);
1035 if (fd < 0) {
1036 _log("Could not create temporary file: %s\n", strerror(errno));
1037 return EXIT_PRNERR_NORETRY_BAD_SETTINGS;
1038 }
1039 tmpfile = fdopen(fd, "r+");
1040 copy_file(tmpfile, stdin, buf, n);
1041 fclose(tmpfile);
1042
1043 filename = tmpfilename;
1044 }
1045
1046 /* If the spooler is CUPS we use the pdftops filter of CUPS,
1047 to have always the same PDF->PostScript conversion method
1048 in the whole printing environment, including incompatibility
1049 workarounds in the CUPS filter (so this way we also have to
1050 maintain all these quirks only once).
1051
1052 The "-dNOINTERPOLATE" makes Ghostscript rendering
1053 significantly faster.
1054
1055 Note that Ghostscript's "pswrite" output device turns text
1056 into bitmaps and therefore produces huge PostScript files.
1057 In addition, this output device is deprecated. Therefore
1058 we use "ps2write".
1059
1060 We give priority to Ghostscript here and use Poppler if
1061 Ghostscript is not available. */
1062 if (spooler == SPOOLER_CUPS)
1063 snprintf(pdf2ps_cmd, PATH_MAX,
1064 "/usr/local/libexec/cups/filter/pdftops '%s' '%s' '%s' '%s' '%s' '%s'",
1065 job->id, job->user, job->title, "1", job->optstr->data,
1066 filename);
1067 else
1068 snprintf(pdf2ps_cmd, PATH_MAX,
1069 "gs -q -sstdout=%%stderr -sDEVICE=ps2write -sOutputFile=- "
1070 "-dBATCH -dNOPAUSE -dPARANOIDSAFER -dNOINTERPOLATE %s 2>/dev/null || "
1071 "pdftops -level2 -origpagesizes %s - 2>/dev/null",
1072 filename, filename);
1073
1074 renderer_pid = start_system_process("pdf-to-ps", pdf2ps_cmd, &in, &out);
1075
1076 if (dup2(fileno(out), fileno(stdin)) < 0)
1077 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS,
1078 "Couldn't dup stdout of pdf-to-ps\n");
1079
1080 ret = print_file("<STDIN>", 0);
1081
1082 wait_for_process(renderer_pid);
1083 return ret;
1084 }
1085
1086 if (file == stdin)
1087 return print_pdf(stdin, buf, n, filename, startpos);
1088 else
1089 return print_pdf(file, NULL, 0, filename, startpos);
1090
1091 case PS_FILE:
1092 _log("Filetype: PostScript\n");
1093 if (file == stdin)
1094 return print_ps(stdin, buf, n, filename);
1095 else
1096 return print_ps(file, NULL, 0, filename);
1097
1098 case UNKNOWN_FILE:
1099 if (spooler == SPOOLER_CUPS) {
1100 _log("Cannot process \"%s\": Unknown filetype.\n", filename);
1101 return 0;
1102 }
1103
1104 _log("Filetype unknown, trying to convert ...\n");
1105 get_fileconverter_handle(buf, &fchandle, &fcpid);
1106
1107 /* Read further data from the file converter and not from STDIN */
1108 if (dup2(fileno(fchandle), fileno(stdin)) < 0)
1109 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Couldn't dup fileconverterhandle\n");
1110
1111 ret = print_file("<STDIN>", 0);
1112
1113 if (close_fileconverter_handle(fchandle, fcpid) != EXIT_PRINTED)
1114 rip_die(ret, "Error closing file converter\n");
1115 return ret;
1116 }
1117
1118 fclose(file);
1119 return 1;
1120 }
1121
signal_terminate(int signal)1122 void signal_terminate(int signal)
1123 {
1124 rip_die(EXIT_PRINTED, "Caught termination signal: Job canceled\n");
1125 }
1126
create_job()1127 jobparams_t * create_job()
1128 {
1129 jobparams_t *job = calloc(1, sizeof(jobparams_t));
1130 struct passwd *passwd;
1131
1132 job->optstr = create_dstr();
1133 job->time = time(NULL);
1134 strcpy(job->copies, "1");
1135 gethostname(job->host, 128);
1136 passwd = getpwuid(getuid());
1137 if (passwd)
1138 strlcpy(job->user, passwd->pw_name, 128);
1139 snprintf(job->title, 128, "%s@%s", job->user, job->host);
1140
1141 return job;
1142 }
1143
free_job(jobparams_t * job)1144 void free_job(jobparams_t *job)
1145 {
1146 free_dstr(job->optstr);
1147 free(job);
1148 }
1149
main(int argc,char ** argv)1150 int main(int argc, char** argv)
1151 {
1152 int i;
1153 int verbose = 0, quiet = 0, showdocs = 0;
1154 const char* str;
1155 char *p, *filename;
1156 const char *path;
1157 FILE *genpdqfile = NULL;
1158 FILE *ppdfh = NULL;
1159 char tmp[1024], pstoraster[256];
1160 int havefilter, havepstoraster;
1161 dstr_t *filelist;
1162 list_t * arglist;
1163
1164 arglist = list_create_from_array(argc -1, (void**)&argv[1]);
1165
1166 if (argc == 2 && (arglist_find(arglist, "--version") || arglist_find(arglist, "--help") ||
1167 arglist_find(arglist, "-v") || arglist_find(arglist, "-h"))) {
1168 printf("foomatic rip version "VERSION"\n");
1169 printf("\"man foomatic-rip\" for help.\n");
1170 list_free(arglist);
1171 return 0;
1172 }
1173
1174 filelist = create_dstr();
1175 job = create_job();
1176
1177 jclprepend = NULL;
1178 jclappend = create_dstr();
1179 postpipe = create_dstr();
1180
1181 options_init();
1182
1183 signal(SIGTERM, signal_terminate);
1184 signal(SIGINT, signal_terminate);
1185
1186
1187 config_from_file(CONFIG_PATH "/filter.conf");
1188
1189 /* Command line options for verbosity */
1190 if (arglist_remove_flag(arglist, "-v"))
1191 verbose = 1;
1192 if (arglist_remove_flag(arglist, "-q"))
1193 quiet = 1;
1194 if (arglist_remove_flag(arglist, "-d"))
1195 showdocs = 1;
1196 if (arglist_remove_flag(arglist, "--debug"))
1197 debug = 1;
1198
1199 if (debug) {
1200 sprintf(tmp, "%s-XXXXXX.log", LOG_FILE);
1201 int fd = mkstemps (tmp, 4);
1202 if (fd != -1)
1203 logh = fdopen(fd, "w");
1204 else
1205 logh = stderr;
1206 } else if (quiet && !verbose)
1207 logh = NULL; /* Quiet mode, do not log */
1208 else
1209 logh = stderr; /* Default: log to stderr */
1210
1211 /* Start debug logging */
1212 if (debug) {
1213 /* If we are not in debug mode, we do this later, as we must find out at
1214 first which spooler is used. When printing without spooler we
1215 suppress logging because foomatic-rip is called directly on the
1216 command line and so we avoid logging onto the console. */
1217 _log("foomatic-rip version "VERSION" running...\n");
1218
1219 /* Print the command line only in debug mode, Mac OS X adds very many
1220 options so that CUPS cannot handle the output of the command line
1221 in its log files. If CUPS encounters a line with more than 1024
1222 characters sent into its log files, it aborts the job with an error. */
1223 if (spooler != SPOOLER_CUPS) {
1224 _log("called with arguments: ");
1225 for (i = 1; i < argc -1; i++)
1226 _log("\'%s\', ", argv[i]);
1227 _log("\'%s\'\n", argv[i]);
1228 }
1229 }
1230
1231 if (getenv("PPD")) {
1232 strncpy(job->ppdfile, getenv("PPD"), 256);
1233 spooler = SPOOLER_CUPS;
1234 }
1235
1236 if (getenv("SPOOLER_KEY")) {
1237 spooler = SPOOLER_SOLARIS;
1238 /* set the printer name from the ppd file name */
1239 strncpy_omit(job->ppdfile, getenv("PPD"), 256, omit_specialchars);
1240 file_basename(job->printer, job->ppdfile, 256);
1241 /* TODO read attribute file*/
1242 }
1243
1244 if (getenv("PPR_VERSION"))
1245 spooler = SPOOLER_PPR;
1246
1247 if (getenv("PPR_RIPOPTS")) {
1248 /* PPR 1.5 allows the user to specify options for the PPR RIP with the
1249 "--ripopts" option on the "ppr" command line. They are provided to
1250 the RIP via the "PPR_RIPOPTS" environment variable. */
1251 dstrcatf(job->optstr, "%s ", getenv("PPR_RIPOPTS"));
1252 spooler = SPOOLER_PPR;
1253 }
1254
1255 if (getenv("LPOPTS")) { /* "LPOPTS": Option settings for some LPD implementations (ex: GNUlpr) */
1256 spooler = SPOOLER_GNULPR;
1257 dstrcatf(job->optstr, "%s ", getenv("LPOPTS"));
1258 }
1259
1260 /* Check for LPRng first so we do not pick up bogus ppd files by the -ppd option */
1261 if (spooler != SPOOLER_CUPS && spooler != SPOOLER_PPR &&
1262 spooler != SPOOLER_PPR_INT) {
1263 if (arglist_remove_flag(arglist, "--lprng"))
1264 spooler = SPOOLER_LPRNG;
1265 }
1266
1267 /* 'PRINTCAP_ENTRY' environment variable is : LPRng
1268 the :ppd=/path/to/ppdfile printcap entry should be used */
1269 if (getenv("PRINTCAP_ENTRY")) {
1270 spooler = SPOOLER_LPRNG;
1271 if ((str = strstr(getenv("PRINTCAP_ENTRY"), "ppd=")))
1272 str += 4;
1273 else if ((str = strstr(getenv("PRINTCAP_ENTRY"), "ppdfile=")))
1274 str += 8;
1275 if (str) {
1276 while (isspace(*str)) str++;
1277 p = job->ppdfile;
1278 while (*str != '\0' && !isspace(*str) && *str != '\n' &&
1279 *str != ':') {
1280 if (isprint(*str) && strchr(shellescapes, *str) == NULL)
1281 *p++ = *str;
1282 str++;
1283 }
1284 }
1285 }
1286
1287 /* CUPS calls foomatic-rip only with 5 or 6 positional parameters,
1288 not with named options, like for example "-p <string>". Also PPR
1289 does not used named options. */
1290 if (spooler != SPOOLER_CUPS && spooler != SPOOLER_PPR &&
1291 spooler != SPOOLER_PPR_INT) {
1292 /* Check for LPD/GNUlpr by typical options which the spooler puts onto
1293 the filter's command line (options "-w": text width, "-l": text
1294 length, "-i": indent, "-x", "-y": graphics size, "-c": raw printing,
1295 "-n": user name, "-h": host name) */
1296 if ((str = arglist_get_value(arglist, "-h"))) {
1297 if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG)
1298 spooler = SPOOLER_LPD;
1299 strncpy(job->host, str, 127);
1300 job->host[127] = '\0';
1301 arglist_remove(arglist, "-h");
1302 }
1303 if ((str = arglist_get_value(arglist, "-n"))) {
1304 if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG)
1305 spooler = SPOOLER_LPD;
1306
1307 strncpy(job->user, str, 127);
1308 job->user[127] = '\0';
1309 arglist_remove(arglist, "-n");
1310 }
1311 if (arglist_remove(arglist, "-w") ||
1312 arglist_remove(arglist, "-l") ||
1313 arglist_remove(arglist, "-x") ||
1314 arglist_remove(arglist, "-y") ||
1315 arglist_remove(arglist, "-i") ||
1316 arglist_remove_flag(arglist, "-c")) {
1317 if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG)
1318 spooler = SPOOLER_LPD;
1319 }
1320 /* LPRng delivers the option settings via the "-Z" argument */
1321 if ((str = arglist_get_value(arglist, "-Z"))) {
1322 spooler = SPOOLER_LPRNG;
1323 dstrcatf(job->optstr, "%s ", str);
1324 arglist_remove(arglist, "-Z");
1325 }
1326 /* Job title and options for stock LPD */
1327 if ((str = arglist_get_value(arglist, "-j")) || (str = arglist_get_value(arglist, "-J"))) {
1328 strncpy_omit(job->title, str, 128, omit_shellescapes);
1329 if (spooler == SPOOLER_LPD)
1330 dstrcatf(job->optstr, "%s ", job->title);
1331 if (!arglist_remove(arglist, "-j"))
1332 arglist_remove(arglist, "-J");
1333 }
1334
1335 /* Check for CPS */
1336 if (arglist_remove_flag(arglist, "--cps") > 0)
1337 spooler = SPOOLER_CPS;
1338
1339 /* PPD file name given via the command line
1340 allow duplicates, and use the last specified one */
1341 if (spooler != SPOOLER_GNULPR && spooler != SPOOLER_LPRNG &&
1342 spooler != SPOOLER_LPD) {
1343 while ((str = arglist_get_value(arglist, "-p"))) {
1344 strncpy(job->ppdfile, str, 256);
1345 arglist_remove(arglist, "-p");
1346 }
1347 while ((str = arglist_get_value(arglist, "--ppd"))) {
1348 strncpy(job->ppdfile, str, 256);
1349 arglist_remove(arglist, "--ppd");
1350 }
1351 }
1352
1353 /* Options for spooler-less printing, CPS, or PDQ */
1354 while ((str = arglist_get_value(arglist, "-o"))) {
1355 strncpy_omit(tmp, str, 1024, omit_shellescapes);
1356 dstrcatf(job->optstr, "%s ", tmp);
1357 arglist_remove(arglist, "-o");
1358 /* If we don't print as PPR RIP or as CPS filter, we print
1359 without spooler (we check for PDQ later) */
1360 if (spooler != SPOOLER_PPR && spooler != SPOOLER_CPS)
1361 spooler = SPOOLER_DIRECT;
1362 }
1363
1364 /* Printer for spooler-less printing or PDQ */
1365 if ((str = arglist_get_value(arglist, "-d"))) {
1366 strncpy_omit(job->printer, str, 256, omit_shellescapes);
1367 arglist_remove(arglist, "-d");
1368 }
1369
1370 /* Printer for spooler-less printing, PDQ, or LPRng */
1371 if ((str = arglist_get_value(arglist, "-P"))) {
1372 strncpy_omit(job->printer, str, 256, omit_shellescapes);
1373 arglist_remove(arglist, "-P");
1374 }
1375
1376 /* Were we called from a PDQ wrapper? */
1377 if (arglist_remove_flag(arglist, "--pdq"))
1378 spooler = SPOOLER_PDQ;
1379
1380 /* Were we called to build the PDQ driver declaration file? */
1381 genpdqfile = check_pdq_file(arglist);
1382 if (genpdqfile)
1383 spooler = SPOOLER_PDQ;
1384 }
1385
1386 /* spooler specific initialization */
1387 switch (spooler) {
1388 case SPOOLER_PPR:
1389 init_ppr(arglist, job);
1390 break;
1391
1392 case SPOOLER_CUPS:
1393 init_cups(arglist, filelist, job);
1394 break;
1395
1396 case SPOOLER_LPRNG:
1397 if (job->ppdfile[0] != '\0') break;
1398 case SPOOLER_LPD:
1399 case SPOOLER_GNULPR:
1400 /* Get PPD file name as the last command line argument */
1401 if (arglist->last)
1402 strncpy(job->ppdfile, (char*)arglist->last->data, 256);
1403 break;
1404
1405 case SPOOLER_DIRECT:
1406 case SPOOLER_CPS:
1407 case SPOOLER_PDQ:
1408 init_direct_cps_pdq(arglist, filelist, job);
1409 break;
1410 }
1411
1412 /* Files to be printed (can be more than one for spooler-less printing) */
1413 /* Empty file list -> print STDIN */
1414 dstrtrim(filelist);
1415 if (filelist->len == 0)
1416 dstrcpyf(filelist, "<STDIN>");
1417
1418 /* Check filelist */
1419 p = strtok(strdup(filelist->data), " ");
1420 while (p) {
1421 if (strcmp(p, "<STDIN>") != 0) {
1422 if (p[0] == '-')
1423 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Invalid argument: %s", p);
1424 else if (access(p, R_OK) != 0) {
1425 _log("File %s does not exist/is not readable\n", p);
1426 strclr(p);
1427 }
1428 }
1429 p = strtok(NULL, " ");
1430 }
1431
1432 /* When we print without spooler or with CPS do not log onto STDERR unless
1433 the "-v" ('Verbose') is set or the debug mode is used */
1434 if ((spooler == SPOOLER_DIRECT || spooler == SPOOLER_CPS || genpdqfile) && !verbose && !debug) {
1435 if (logh && logh != stderr)
1436 fclose(logh);
1437 logh = NULL;
1438 }
1439
1440 /* If we are in debug mode, we do this earlier. */
1441 if (!debug) {
1442 _log("foomatic-rip version " VERSION " running...\n");
1443 /* Print the command line only in debug mode, Mac OS X adds very many
1444 options so that CUPS cannot handle the output of the command line
1445 in its log files. If CUPS encounters a line with more than 1024
1446 characters sent into its log files, it aborts the job with an error. */
1447 if (spooler != SPOOLER_CUPS) {
1448 _log("called with arguments: ");
1449 for (i = 1; i < argc -1; i++)
1450 _log("\'%s\', ", argv[i]);
1451 _log("\'%s\'\n", argv[i]);
1452 }
1453 }
1454
1455 /* PPD File */
1456 /* Load the PPD file and build a data structure for the renderer's
1457 command line and the options */
1458 if (!(ppdfh = fopen(job->ppdfile, "r")))
1459 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "Unable to open PPD file %s\n", job->ppdfile);
1460
1461 read_ppd_file(job->ppdfile);
1462
1463 /* We do not need to parse the PostScript job when we don't have
1464 any options. If we have options, we must check whether the
1465 default settings from the PPD file are valid and correct them
1466 if nexessary. */
1467 if (option_count() == 0) {
1468 /* We don't have any options, so we do not need to parse the
1469 PostScript data */
1470 dontparse = 1;
1471 }
1472
1473 /* Is our PPD for a CUPS raster driver */
1474 if (!isempty(cupsfilter)) {
1475 /* Search the filter in cupsfilterpath
1476 The %Y is a placeholder for the option settings */
1477 havefilter = 0;
1478 path = cupsfilterpath;
1479 while ((path = strncpy_tochar(tmp, path, 1024, ":"))) {
1480 strlcat(tmp, "/", 1024);
1481 strlcat(tmp, cupsfilter, 1024);
1482 if (access(tmp, X_OK) == 0) {
1483 havefilter = 1;
1484 strlcpy(cupsfilter, tmp, 256);
1485 strlcat(cupsfilter, " 0 '' '' 0 '%Y%X'", 256);
1486 break;
1487 }
1488 }
1489
1490 if (!havefilter) {
1491 /* We do not have the required filter, so we assume that
1492 rendering this job is supposed to be done on a remote
1493 server. So we do not define a renderer command line and
1494 embed only the option settings (as we had a PostScript
1495 printer). This way the settings are taken into account
1496 when the job is rendered on the server.*/
1497 _log("CUPS filter for this PPD file not found - assuming that job will "
1498 "be rendered on a remote server. Only the PostScript of the options"
1499 "will be inserted into the PostScript data stream.\n");
1500 }
1501 else {
1502 /* use pstoraster script if available, otherwise run Ghostscript directly */
1503 havepstoraster = 0;
1504 path = cupsfilterpath;
1505 while ((path = strncpy_tochar(tmp, path, 1024, ":"))) {
1506 strlcat(tmp, "/pstoraster", 1024);
1507 if (access(tmp, X_OK) == 0) {
1508 havepstoraster = 1;
1509 strlcpy(pstoraster, tmp, 256);
1510 strlcat(pstoraster, " 0 '' '' 0 '%X'", 256);
1511 break;
1512 }
1513 /* gstoraster is the new name for pstoraster */
1514 strlcat(tmp, "/gstoraster", 1024);
1515 if (access(tmp, X_OK) == 0) {
1516 havepstoraster = 1;
1517 strlcpy(pstoraster, tmp, 256);
1518 strlcat(pstoraster, " 0 '' '' 0 '%X'", 256);
1519 break;
1520 }
1521 }
1522 if (!havepstoraster) {
1523 const char **qualifier = NULL;
1524 const char *icc_profile = NULL;
1525
1526 qualifier = get_ppd_qualifier();
1527 _log("INFO: Using qualifer: '%s.%s.%s'\n",
1528 qualifier[0], qualifier[1], qualifier[2]);
1529
1530 #ifdef HAVE_DBUS
1531 /* ask colord for the profile */
1532 icc_profile = colord_get_profile_for_device_id ((const char *) getenv("PRINTER"),
1533 qualifier);
1534 #endif
1535
1536 /* fall back to PPD */
1537 if (icc_profile == NULL) {
1538 _log("INFO: need to look in PPD for matching qualifer\n");
1539 icc_profile = get_icc_profile_for_qualifier(qualifier);
1540 }
1541
1542 if (icc_profile != NULL)
1543 snprintf(cmd, sizeof(cmd),
1544 "-sOutputICCProfile='%s'", icc_profile);
1545 else
1546 cmd[0] = '\0';
1547
1548 snprintf(pstoraster, sizeof(pstoraster), "gs -dQUIET -dDEBUG -dPARANOIDSAFER -dNOPAUSE -dBATCH -dNOINTERPOLATE -dNOMEDIAATTRS -sDEVICE=cups %s -sOutputFile=- -", cmd);
1549 }
1550
1551 /* build Ghostscript/CUPS driver command line */
1552 snprintf(cmd, 1024, "%s | %s", pstoraster, cupsfilter);
1553 _log("INFO: Using command line: %s\n", cmd);
1554
1555 /* Set environment variables */
1556 setenv("PPD", job->ppdfile, 1);
1557 }
1558 }
1559
1560 /* Was the RIP command line defined in the PPD file? If not, we assume a PostScript printer
1561 and do not render/translate the input data */
1562 if (isempty(cmd)) {
1563 strcpy(cmd, "cat%A%B%C%D%E%F%G%H%I%J%K%L%M%Z");
1564 if (dontparse) {
1565 /* No command line, no options, we have a raw queue, don't check
1566 whether the input is PostScript and ignore the "docs" option,
1567 simply pass the input data to the backend.*/
1568 dontparse = 2;
1569 strcpy(printer_model, "Raw queue");
1570 }
1571 }
1572
1573 /* Summary for debugging */
1574 _log("\nParameter Summary\n"
1575 "-----------------\n\n"
1576 "Spooler: %s\n"
1577 "Printer: %s\n"
1578 "Shell: %s\n"
1579 "PPD file: %s\n"
1580 "ATTR file: %s\n"
1581 "Printer model: %s\n",
1582 spooler_name(spooler), job->printer, get_modern_shell(), job->ppdfile, attrpath, printer_model);
1583 /* Print the options string only in debug mode, Mac OS X adds very many
1584 options so that CUPS cannot handle the output of the option string
1585 in its log files. If CUPS encounters a line with more than 1024 characters
1586 sent into its log files, it aborts the job with an error.*/
1587 if (debug || spooler != SPOOLER_CUPS)
1588 _log("Options: %s\n", job->optstr->data);
1589 _log("Job title: %s\n", job->title);
1590 _log("File(s) to be printed:\n");
1591 _log("%s\n\n", filelist->data);
1592 if (getenv("GS_LIB"))
1593 _log("Ghostscript extra search path ('GS_LIB'): %s\n", getenv("GS_LIB"));
1594
1595 /* Process options from command line,
1596 but save the defaults for printing documentation pages first */
1597 optionset_copy_values(optionset("default"), optionset("userval"));
1598 process_cmdline_options();
1599
1600 /* Were we called to build the PDQ driver declaration file? */
1601 if (genpdqfile) {
1602 print_pdq_driver(genpdqfile, optionset("userval"));
1603 fclose(genpdqfile);
1604 exit(EXIT_PRINTED);
1605 }
1606
1607 if (spooler == SPOOLER_PPR_INT) {
1608 snprintf(tmp, 1024, "interfaces/%s", backend);
1609 if (access(tmp, X_OK) != 0)
1610 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "The backend interface "
1611 "/interfaces/%s does not exist/ is not executable!\n", backend);
1612
1613 /* foomatic-rip cannot use foomatic-rip as backend */
1614 if (!strcmp(backend, "foomatic-rip"))
1615 rip_die(EXIT_PRNERR_NORETRY_BAD_SETTINGS, "\"foomatic-rip\" cannot "
1616 "use itself as backend interface!\n");
1617
1618 /* Put the backend interface into the postpipe */
1619 /* TODO
1620 $postpipe = "| ( interfaces/$backend \"$ppr_printer\" ".
1621 "\"$ppr_address\" \"" . join(" ",@backendoptions) .
1622 "\" \"$ppr_jobbreak\" \"$ppr_feedback\" " .
1623 "\"$ppr_codes\" \"$ppr_jobname\" \"$ppr_routing\" " .
1624 "\"$ppr_for\" \"\" )";
1625 */
1626 }
1627
1628 /* no postpipe for CUPS or PDQ, even if one is defined in the PPD file */
1629 if (spooler == SPOOLER_CUPS || spooler == SPOOLER_PDQ)
1630 dstrclear(postpipe);
1631
1632 /* CPS always needs a postpipe, set the default one for local printing if none is set */
1633 if (spooler == SPOOLER_CPS && !postpipe->len)
1634 dstrcpy(postpipe, "| cat - > $LPDDEV");
1635
1636 if (postpipe->len)
1637 _log("Ouput will be redirected to:\n%s\n", postpipe);
1638
1639
1640 /* Print documentation page when asked for */
1641 if (do_docs) {
1642 /* Don't print the supplied files, STDIN will be redirected to the
1643 documentation page generator */
1644 dstrcpyf(filelist, "<STDIN>");
1645
1646 /* Start the documentation page generator */
1647 /* TODO tbd */
1648 }
1649
1650 filename = strtok_r(filelist->data, " ", &p);
1651 while (filename) {
1652 _log("\n================================================\n\n"
1653 "File: %s\n\n"
1654 "================================================\n\n", filename);
1655
1656 /* Do we have a raw queue? */
1657 if (dontparse == 2) {
1658 /* Raw queue, simply pass the input into the postpipe (or to STDOUT
1659 when there is no postpipe) */
1660 _log("Raw printing, executing \"cat %s\"\n\n");
1661 snprintf(tmp, 1024, "cat %s", postpipe->data);
1662 run_system_process("raw-printer", tmp);
1663 continue;
1664 }
1665
1666 /* First, for arguments with a default, stick the default in as
1667 the initial value for the "header" option set, this option set
1668 consists of the PPD defaults, the options specified on the
1669 command line, and the options set in the header part of the
1670 PostScript file (all before the first page begins). */
1671 optionset_copy_values(optionset("userval"), optionset("header"));
1672
1673 if (!print_file(filename, 1))
1674 rip_die(EXIT_PRNERR_NORETRY, "Could not print file %s\n", filename);
1675 filename = strtok_r(NULL, " ", &p);
1676 }
1677
1678 /* Close documentation page generator */
1679 /* if (docgenerator_pid) {
1680 retval = close_docgenerator_handle(dogenerator_handle, docgenerator_pid);
1681 if (!retval != EXIT_PRINTED) {
1682 _log("Error closing documentation page generator\n");
1683 exit(retval);
1684 }
1685 docgenerator_pid = 0;
1686 } */
1687
1688 /* Close the last input file */
1689 fclose(stdin);
1690
1691 /* TODO dump everything in $dat when debug is turned on (necessary?) */
1692
1693 _log("\nClosing foomatic-rip.\n");
1694
1695
1696 /* Cleanup */
1697 free_job(job);
1698 if (genpdqfile && genpdqfile != stdout)
1699 fclose(genpdqfile);
1700 free_dstr(filelist);
1701 options_free();
1702 close_log();
1703
1704 argv_free(jclprepend);
1705 free_dstr(jclappend);
1706 if (backendoptions)
1707 free_dstr(backendoptions);
1708
1709 list_free(arglist);
1710
1711 return EXIT_PRINTED;
1712 }
1713
1714