1 /* spooler.c
2  *
3  * Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
4  * Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
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 #include <limits.h>
31 
spooler_name(int spooler)32 const char *spooler_name(int spooler)
33 {
34     switch (spooler) {
35         case SPOOLER_CUPS: return "cups";
36         case SPOOLER_DIRECT: return "direct";
37     };
38     return "<unknown>";
39 }
40 
init_cups(list_t * arglist,dstr_t * filelist,jobparams_t * job)41 void init_cups(list_t *arglist, dstr_t *filelist, jobparams_t *job)
42 {
43     char path [PATH_MAX] = "";
44     char cups_jobid [128];
45     char cups_user [128];
46     char cups_jobtitle [2048];
47     char cups_copies [128];
48     int cups_options_len;
49     char *cups_options;
50     const char *pname;
51     char cups_filename [256];
52 
53     if (getenv("CUPS_FONTPATH"))
54         strncpy(path, getenv("CUPS_FONTPATH"), PATH_MAX - 1);
55     else if (getenv("CUPS_DATADIR")) {
56        strncpy(path, getenv("CUPS_DATADIR"), PATH_MAX - 1);
57        strncat(path, "/fonts", PATH_MAX - strlen(path) - 1);
58     }
59     if (getenv("GS_LIB")) {
60         strncat(path, ":", PATH_MAX - strlen(path) - 1);
61         strncat(path, getenv("GS_LIB"), PATH_MAX - strlen(path) - 1);
62     }
63     setenv("GS_LIB", path, 1);
64 
65     /* Get all command line parameters */
66     strncpy_omit(cups_jobid, arglist_get(arglist, 0), 128, omit_shellescapes);
67     strncpy_omit(cups_user, arglist_get(arglist, 1), 128, omit_shellescapes);
68     strncpy_omit(cups_jobtitle, arglist_get(arglist, 2), 2048,
69 		 omit_shellescapes);
70     strncpy_omit(cups_copies, arglist_get(arglist, 3), 128, omit_shellescapes);
71 
72     cups_options_len = strlen(arglist_get(arglist, 4));
73     cups_options = malloc(cups_options_len + 1);
74     strncpy_omit(cups_options, arglist_get(arglist, 4), cups_options_len + 1,
75 		 omit_shellescapes);
76 
77     /* Common job parameters */
78     strcpy(job->id, cups_jobid);
79     strcpy(job->title, cups_jobtitle);
80     strcpy(job->user, cups_user);
81     strcpy(job->copies, cups_copies);
82     dstrcatf(job->optstr, " %s", cups_options);
83 
84     /* Check for and handle inputfile vs stdin */
85     if (list_item_count(arglist) > 4) {
86         strncpy_omit(cups_filename, arglist_get(arglist, 5), 256, omit_shellescapes);
87         if (cups_filename[0] != '-') {
88             /* We get input from a file */
89             dstrcatf(filelist, "%s ", cups_filename);
90             _log("Getting input from file %s\n", cups_filename);
91         }
92     }
93 
94     /* On which queue are we printing?
95        CUPS puts the print queue name into the PRINTER environment variable
96        when calling filters. */
97     pname = getenv("PRINTER");
98     if (pname == NULL)
99       pname = "unknown";
100     strncpy(job->printer, pname, 256);
101     job->printer[255] = '\0';
102 
103     free(cups_options);
104 }
105 
106 /* used by init_direct to find a ppd file */
find_ppdfile(const char * user_default_path,jobparams_t * job)107 int find_ppdfile(const char *user_default_path, jobparams_t *job)
108 {
109     /* Search also common spooler-specific locations, this way a printer
110        configured under a certain spooler can also be used without spooler */
111 
112     strcpy(job->ppdfile, job->printer);
113     if (access(job->ppdfile, R_OK) == 0)
114         return 1;
115 
116     snprintf(job->ppdfile, 2048, "%s.ppd", job->printer); /* current dir */
117     if (access(job->ppdfile, R_OK) == 0)
118         return 1;
119     snprintf(job->ppdfile, 2048, "%s/%s.ppd", user_default_path, job->printer); /* user dir */
120     if (access(job->ppdfile, R_OK) == 0)
121         return 1;
122     snprintf(job->ppdfile, 2048, "%s/direct/%s.ppd", CONFIG_PATH, job->printer); /* system dir */
123     if (access(job->ppdfile, R_OK) == 0)
124         return 1;
125     snprintf(job->ppdfile, 2048, "%s/%s.ppd", CONFIG_PATH, job->printer); /* system dir */
126     if (access(job->ppdfile, R_OK) == 0)
127         return 1;
128     snprintf(job->ppdfile, 2048, "/etc/cups/ppd/%s.ppd", job->printer); /* CUPS config dir */
129     if (access(job->ppdfile, R_OK) == 0)
130         return 1;
131     snprintf(job->ppdfile, 2048, "/usr/local/etc/cups/ppd/%s.ppd", job->printer); /* CUPS config dir */
132     if (access(job->ppdfile, R_OK) == 0)
133         return 1;
134 
135     /* nothing found */
136     job->ppdfile[0] = '\0';
137     return 0;
138 }
139 
140 /* search 'configfile' for 'key', copy value into dest, return success */
configfile_find_option(const char * configfile,const char * key,char * dest,size_t destsize)141 int configfile_find_option(const char *configfile, const char *key, char *dest, size_t destsize)
142 {
143     FILE *fh;
144     char line [1024];
145     char *p;
146 
147     dest[0] = '\0';
148 
149     if (!(fh = fopen(configfile, "r")))
150         return 0;
151 
152     while (fgets(line, 1024, fh)) {
153         if (!prefixcmp(line, "default")) {
154             p = strchr(line, ':');
155             if (p) {
156                 strncpy_omit(dest, p + 1, destsize, omit_whitespace_newline);
157                 if (dest[0])
158                     break;
159             }
160         }
161     }
162     fclose(fh);
163     return dest[0] != '\0';
164 }
165 
166 /* tries to find a default printer name in various config files and copies the
167  * result into the global var 'printer'. Returns success */
find_default_printer(const char * user_default_path,jobparams_t * job)168 int find_default_printer(const char *user_default_path, jobparams_t *job)
169 {
170     char configfile [1024];
171     char *key = "default";
172 
173     if (configfile_find_option("./.directconfig", key, job->printer, 256))
174         return 1;
175     if (configfile_find_option("./directconfig", key, job->printer, 256))
176         return 1;
177     if (configfile_find_option("./.config", key, job->printer, 256))
178         return 1;
179     strlcpy(configfile, user_default_path, 1024);
180     strlcat(configfile, "/direct/.config", 1024);
181     if (configfile_find_option(configfile, key, job->printer, 256))
182         return 1;
183     strlcpy(configfile, user_default_path, 1024);
184     strlcat(configfile, "/direct.conf", 1024);
185     if (configfile_find_option(configfile, key, job->printer, 256))
186         return 1;
187     if (configfile_find_option(CONFIG_PATH "/direct/.config", key, job->printer, 256))
188         return 1;
189     if (configfile_find_option(CONFIG_PATH "/direct.conf", key, job->printer, 256))
190         return 1;
191 
192     return 0;
193 }
194 
init_direct(list_t * arglist,dstr_t * filelist,jobparams_t * job)195 void init_direct(list_t *arglist, dstr_t *filelist, jobparams_t *job)
196 {
197     char tmp [1024];
198     listitem_t *i;
199     char user_default_path [PATH_MAX];
200 
201     strlcpy(user_default_path, getenv("HOME"), 256);
202     strlcat(user_default_path, "/.foomatic/", 256);
203 
204     /* Which files do we want to print? */
205     for (i = arglist->first; i; i = i->next) {
206         strncpy_omit(tmp, (char*)i->data, 1024, omit_shellescapes);
207         dstrcatf(filelist, "%s ", tmp);
208     }
209 
210     if (job->ppdfile[0] == '\0') {
211         if (job->printer[0] == '\0') {
212             /* No printer definition file selected, check whether we have a
213                default printer defined */
214             find_default_printer(user_default_path, job);
215         }
216 
217         /* Neither in a config file nor on the command line a printer was selected */
218         if (!job->printer[0]) {
219             _log("No printer definition (option \"-P <name>\") specified!\n");
220             exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
221         }
222 
223         /* Search for the PPD file */
224         if (!find_ppdfile(user_default_path, job)) {
225             _log("There is no readable PPD file for the printer %s, is it configured?\n", job->printer);
226             exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
227         }
228     }
229 }
230 
231