~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to filter/foomatic-rip/spooler.c

  • Committer: Package Import Robot
  • Author(s): Didier Raboud
  • Date: 2015-01-15 18:06:05 UTC
  • mfrom: (1.2.25)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: package-import@ubuntu.com-20150115180605-fnfbqv85k3y5zggk
Tags: upstream-1.0.62
ImportĀ upstreamĀ versionĀ 1.0.62

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* spooler.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 "spooler.h"
 
25
#include "foomaticrip.h"
 
26
#include "util.h"
 
27
#include "options.h"
 
28
#include <stdlib.h>
 
29
#include <unistd.h>
 
30
 
 
31
const char *spooler_name(int spooler)
 
32
{
 
33
    switch (spooler) {
 
34
        case SPOOLER_CUPS: return "cups";
 
35
        case SPOOLER_DIRECT: return "direct";
 
36
    };
 
37
    return "<unknown>";
 
38
}
 
39
 
 
40
/*  This piece of PostScript code (initial idea 2001 by Michael
 
41
    Allerhand (michael.allerhand at ed dot ac dot uk, vastly
 
42
    improved by Till Kamppeter in 2002) lets Ghostscript output
 
43
    the page accounting information which CUPS needs on standard
 
44
    error.
 
45
    Redesign by Helge Blischke (2004-11-17):
 
46
    - As the PostScript job itself may define BeginPage and/or EndPage
 
47
    procedures, or the alternate pstops filter may have inserted
 
48
    such procedures, we make sure that the accounting routine
 
49
    will safely coexist with those. To achieve this, we force
 
50
    - the accountint stuff to be inserted at the very end of the
 
51
        PostScript job's setup section,
 
52
    - the accounting stuff just using the return value of the
 
53
        existing EndPage procedure, if any (and providing a default one
 
54
        if not).
 
55
    - As PostScript jobs may contain calls to setpagedevice "between"
 
56
    pages, e.g. to change media type, do in-job stapling, etc.,
 
57
    we cannot rely on the "showpage count since last pagedevice
 
58
    activation" but instead count the physical pages by ourselves
 
59
    (in a global dictionary).
 
60
*/
 
61
const char *accounting_prolog_code =
 
62
    "[{\n"
 
63
    "%% Code for writing CUPS accounting tags on standard error\n"
 
64
    "\n"
 
65
    "/cupsPSLevel2 % Determine whether we can do PostScript level 2 or newer\n"
 
66
    "    systemdict/languagelevel 2 copy\n"
 
67
    "    known{get exec}{pop pop 1}ifelse 2 ge\n"
 
68
    "def\n"
 
69
    "\n"
 
70
    "cupsPSLevel2\n"
 
71
    "{                    % in case of level 2 or higher\n"
 
72
    "    currentglobal true setglobal    % define a dictioary foomaticDict\n"
 
73
    "    globaldict begin        % in global VM and establish a\n"
 
74
    "    /foomaticDict            % pages count key there\n"
 
75
    "    <<\n"
 
76
    "        /PhysPages 0\n"
 
77
    "    >>def\n"
 
78
    "    end\n"
 
79
    "    setglobal\n"
 
80
    "}if\n"
 
81
    "\n"
 
82
    "/cupsGetNumCopies { % Read the number of Copies requested for the current\n"
 
83
    "            % page\n"
 
84
    "    cupsPSLevel2\n"
 
85
    "    {\n"
 
86
    "    % PS Level 2+: Get number of copies from Page Device dictionary\n"
 
87
    "    currentpagedevice /NumCopies get\n"
 
88
    "    }\n"
 
89
    "    {\n"
 
90
    "    % PS Level 1: Number of copies not in Page Device dictionary\n"
 
91
    "    null\n"
 
92
    "    }\n"
 
93
    "    ifelse\n"
 
94
    "    % Check whether the number is defined, if it is \"null\" use #copies \n"
 
95
    "    % instead\n"
 
96
    "    dup null eq {\n"
 
97
    "    pop #copies\n"
 
98
    "    }\n"
 
99
    "    if\n"
 
100
    "    % Check whether the number is defined now, if it is still \"null\" use 1\n"
 
101
    "    % instead\n"
 
102
    "    dup null eq {\n"
 
103
    "    pop 1\n"
 
104
    "    } if\n"
 
105
    "} bind def\n"
 
106
    "\n"
 
107
    "/cupsWrite { % write a string onto standard error\n"
 
108
    "    (%stderr) (w) file\n"
 
109
    "    exch writestring\n"
 
110
    "} bind def\n"
 
111
    "\n"
 
112
    "/cupsFlush    % flush standard error to make it sort of unbuffered\n"
 
113
    "{\n"
 
114
    "    (%stderr)(w)file flushfile\n"
 
115
    "}bind def\n"
 
116
    "\n"
 
117
    "cupsPSLevel2\n"
 
118
    "{                % In language level 2, we try to do something reasonable\n"
 
119
    "  <<\n"
 
120
    "    /EndPage\n"
 
121
    "    [                    % start the array that becomes the procedure\n"
 
122
    "      currentpagedevice/EndPage 2 copy known\n"
 
123
    "      {get}                    % get the existing EndPage procedure\n"
 
124
    "      {pop pop {exch pop 2 ne}bind}ifelse    % there is none, define the default\n"
 
125
    "      /exec load                % make sure it will be executed, whatever it is\n"
 
126
    "      /dup load                    % duplicate the result value\n"
 
127
    "      {                    % true: a sheet gets printed, do accounting\n"
 
128
    "        currentglobal true setglobal        % switch to global VM ...\n"
 
129
    "        foomaticDict begin            % ... and access our special dictionary\n"
 
130
    "        PhysPages 1 add            % count the sheets printed (including this one)\n"
 
131
    "        dup /PhysPages exch def        % and save the value\n"
 
132
    "        end                    % leave our dict\n"
 
133
    "        exch setglobal                % return to previous VM\n"
 
134
    "        (PAGE: )cupsWrite             % assemble and print the accounting string ...\n"
 
135
    "        16 string cvs cupsWrite            % ... the sheet count ...\n"
 
136
    "        ( )cupsWrite                % ... a space ...\n"
 
137
    "        cupsGetNumCopies             % ... the number of copies ...\n"
 
138
    "        16 string cvs cupsWrite            % ...\n"
 
139
    "        (\\n)cupsWrite                % ... a newline\n"
 
140
    "        cupsFlush\n"
 
141
    "      }/if load\n"
 
142
    "                    % false: current page gets discarded; do nothing    \n"
 
143
    "    ]cvx bind                % make the array executable and apply bind\n"
 
144
    "  >>setpagedevice\n"
 
145
    "}\n"
 
146
    "{\n"
 
147
    "    % In language level 1, we do no accounting currently, as there is no global VM\n"
 
148
    "    % the contents of which are undesturbed by save and restore. \n"
 
149
    "    % If we may be sure that showpage never gets called inside a page related save / restore pair\n"
 
150
    "    % we might implement an hack with showpage similar to the one above.\n"
 
151
    "}ifelse\n"
 
152
    "\n"
 
153
    "} stopped cleartomark\n";
 
154
 
 
155
 
 
156
void init_cups(list_t *arglist, dstr_t *filelist, jobparams_t *job)
 
157
{
 
158
    char path [1024] = "";
 
159
    char cups_jobid [128];
 
160
    char cups_user [128];
 
161
    char cups_jobtitle [128];
 
162
    char cups_copies [128];
 
163
    int cups_options_len;
 
164
    char *cups_options;
 
165
    char cups_filename [256];
 
166
 
 
167
    if (getenv("CUPS_FONTPATH"))
 
168
        strcpy(path, getenv("CUPS_FONTPATH"));
 
169
    else if (getenv("CUPS_DATADIR")) {
 
170
        strcpy(path, getenv("CUPS_DATADIR"));
 
171
        strcat(path, "/fonts");
 
172
    }
 
173
    if (getenv("GS_LIB")) {
 
174
        strcat(path, ":");
 
175
        strcat(path, getenv("GS_LIB"));
 
176
    }
 
177
    setenv("GS_LIB", path, 1);
 
178
 
 
179
    /* Get all command line parameters */
 
180
    strncpy_omit(cups_jobid, arglist_get(arglist, 0), 128, omit_shellescapes);
 
181
    strncpy_omit(cups_user, arglist_get(arglist, 1), 128, omit_shellescapes);
 
182
    strncpy_omit(cups_jobtitle, arglist_get(arglist, 2), 128, omit_shellescapes);
 
183
    strncpy_omit(cups_copies, arglist_get(arglist, 3), 128, omit_shellescapes);
 
184
 
 
185
    cups_options_len = strlen(arglist_get(arglist, 4));
 
186
    cups_options = malloc(cups_options_len + 1);
 
187
    strncpy_omit(cups_options, arglist_get(arglist, 4), cups_options_len + 1, omit_shellescapes);
 
188
 
 
189
    /* Common job parameters */
 
190
    strcpy(job->id, cups_jobid);
 
191
    strcpy(job->title, cups_jobtitle);
 
192
    strcpy(job->user, cups_user);
 
193
    strcpy(job->copies, cups_copies);
 
194
    dstrcatf(job->optstr, " %s", cups_options);
 
195
 
 
196
    /* Check for and handle inputfile vs stdin */
 
197
    if (list_item_count(arglist) > 4) {
 
198
        strncpy_omit(cups_filename, arglist_get(arglist, 5), 256, omit_shellescapes);
 
199
        if (cups_filename[0] != '-') {
 
200
            /* We get input from a file */
 
201
            dstrcatf(filelist, "%s ", cups_filename);
 
202
            _log("Getting input from file %s\n", cups_filename);
 
203
        }
 
204
    }
 
205
 
 
206
    accounting_prolog = accounting_prolog_code;
 
207
 
 
208
    /* On which queue are we printing?
 
209
       CUPS gives the PPD file the same name as the printer queue,
 
210
       so we can get the queue name from the name of the PPD file. */
 
211
    file_basename(job->printer, job->ppdfile, 256);
 
212
 
 
213
    free(cups_options);
 
214
}
 
215
 
 
216
/* used by init_direct to find a ppd file */
 
217
int find_ppdfile(const char *user_default_path, jobparams_t *job)
 
218
{
 
219
    /* Search also common spooler-specific locations, this way a printer
 
220
       configured under a certain spooler can also be used without spooler */
 
221
 
 
222
    strcpy(job->ppdfile, job->printer);
 
223
    if (access(job->ppdfile, R_OK) == 0)
 
224
        return 1;
 
225
 
 
226
    snprintf(job->ppdfile, 256, "%s.ppd", job->printer); /* current dir */
 
227
    if (access(job->ppdfile, R_OK) == 0)
 
228
        return 1;
 
229
    snprintf(job->ppdfile, 256, "%s/%s.ppd", user_default_path, job->printer); /* user dir */
 
230
    if (access(job->ppdfile, R_OK) == 0)
 
231
        return 1;
 
232
    snprintf(job->ppdfile, 256, "%s/direct/%s.ppd", CONFIG_PATH, job->printer); /* system dir */
 
233
    if (access(job->ppdfile, R_OK) == 0)
 
234
        return 1;
 
235
    snprintf(job->ppdfile, 256, "%s/%s.ppd", CONFIG_PATH, job->printer); /* system dir */
 
236
    if (access(job->ppdfile, R_OK) == 0)
 
237
        return 1;
 
238
    snprintf(job->ppdfile, 256, "/etc/cups/ppd/%s.ppd", job->printer); /* CUPS config dir */
 
239
    if (access(job->ppdfile, R_OK) == 0)
 
240
        return 1;
 
241
    snprintf(job->ppdfile, 256, "/usr/local/etc/cups/ppd/%s.ppd", job->printer); /* CUPS config dir */
 
242
    if (access(job->ppdfile, R_OK) == 0)
 
243
        return 1;
 
244
 
 
245
    /* nothing found */
 
246
    job->ppdfile[0] = '\0';
 
247
    return 0;
 
248
}
 
249
 
 
250
/* search 'configfile' for 'key', copy value into dest, return success */
 
251
int configfile_find_option(const char *configfile, const char *key, char *dest, size_t destsize)
 
252
{
 
253
    FILE *fh;
 
254
    char line [1024];
 
255
    char *p;
 
256
 
 
257
    dest[0] = '\0';
 
258
 
 
259
    if (!(fh = fopen(configfile, "r")))
 
260
        return 0;
 
261
 
 
262
    while (fgets(line, 1024, fh)) {
 
263
        if (!prefixcmp(line, "default")) {
 
264
            p = strchr(line, ':');
 
265
            if (p) {
 
266
                strncpy_omit(dest, p + 1, destsize, omit_whitespace_newline);
 
267
                if (dest[0])
 
268
                    break;
 
269
            }
 
270
        }
 
271
    }
 
272
    fclose(fh);
 
273
    return dest[0] != '\0';
 
274
}
 
275
 
 
276
/* tries to find a default printer name in various config files and copies the
 
277
 * result into the global var 'printer'. Returns success */
 
278
int find_default_printer(const char *user_default_path, jobparams_t *job)
 
279
{
 
280
    char configfile [1024];
 
281
    char *key = "default";
 
282
 
 
283
    if (configfile_find_option("./.directconfig", key, job->printer, 256))
 
284
        return 1;
 
285
    if (configfile_find_option("./directconfig", key, job->printer, 256))
 
286
        return 1;
 
287
    if (configfile_find_option("./.config", key, job->printer, 256))
 
288
        return 1;
 
289
    strlcpy(configfile, user_default_path, 1024);
 
290
    strlcat(configfile, "/direct/.config", 1024);
 
291
    if (configfile_find_option(configfile, key, job->printer, 256))
 
292
        return 1;
 
293
    strlcpy(configfile, user_default_path, 1024);
 
294
    strlcat(configfile, "/direct.conf", 1024);
 
295
    if (configfile_find_option(configfile, key, job->printer, 256))
 
296
        return 1;
 
297
    if (configfile_find_option(CONFIG_PATH "/direct/.config", key, job->printer, 256))
 
298
        return 1;
 
299
    if (configfile_find_option(CONFIG_PATH "/direct.conf", key, job->printer, 256))
 
300
        return 1;
 
301
 
 
302
    return 0;
 
303
}
 
304
 
 
305
void init_direct(list_t *arglist, dstr_t *filelist, jobparams_t *job)
 
306
{
 
307
    char tmp [1024];
 
308
    listitem_t *i;
 
309
    char user_default_path [PATH_MAX];
 
310
 
 
311
    strlcpy(user_default_path, getenv("HOME"), 256);
 
312
    strlcat(user_default_path, "/.foomatic/", 256);
 
313
 
 
314
    /* Which files do we want to print? */
 
315
    for (i = arglist->first; i; i = i->next) {
 
316
        strncpy_omit(tmp, (char*)i->data, 1024, omit_shellescapes);
 
317
        dstrcatf(filelist, "%s ", tmp);
 
318
    }
 
319
 
 
320
    if (job->ppdfile[0] == '\0') {
 
321
        if (job->printer[0] == '\0') {
 
322
            /* No printer definition file selected, check whether we have a
 
323
               default printer defined */
 
324
            find_default_printer(user_default_path, job);
 
325
        }
 
326
 
 
327
        /* Neither in a config file nor on the command line a printer was selected */
 
328
        if (!job->printer[0]) {
 
329
            _log("No printer definition (option \"-P <name>\") specified!\n");
 
330
            exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
 
331
        }
 
332
 
 
333
        /* Search for the PPD file */
 
334
        if (!find_ppdfile(user_default_path, job)) {
 
335
            _log("There is no readable PPD file for the printer %s, is it configured?\n", job->printer);
 
336
            exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
 
337
        }
 
338
    }
 
339
}
 
340