~ubuntu-branches/ubuntu/natty/foomatic-filters/natty

« back to all changes in this revision

Viewing changes to .pc/foomatic-rip-read-multiple-input-files.patch/foomaticrip.c

  • Committer: Bazaar Package Importer
  • Author(s): Till Kamppeter
  • Date: 2010-02-18 16:24:03 UTC
  • mfrom: (1.1.35 upstream) (2.1.11 sid)
  • Revision ID: james.westby@ubuntu.com-20100218162403-0tzm44ffs20hlnbi
Tags: 4.0.7-0ubuntu1
* New upstream release
   - foomatic-rip printed only the first file supplied on the command line
     when multiple files are supplied (spooler-less printing mode,
     LP: #676680).
* debian/patches/foomatic-rip-read-multiple-input-files.patch: Removed
  patches with fix backported from upstream.

Show diffs side-by-side

added added

removed removed

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