]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/commandtops.c
Merge changes from CUPS 1.5svn-r9049 (private header support)
[thirdparty/cups.git] / filter / commandtops.c
1 /*
2 * "$Id$"
3 *
4 * PostScript command filter for CUPS.
5 *
6 * Copyright 2008-2010 by Apple Inc.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Apple Inc. and are protected by Federal copyright
10 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
11 * which should have been included with this file. If this file is
12 * file is missing or damaged, see the license at "http://www.cups.org/".
13 *
14 *
15 * Contents:
16 *
17 * main() - Process a CUPS command file.
18 * auto_configure() - Automatically configure the printer using
19 * PostScript query commands and/or SNMP lookups.
20 * begin_ps() - Send the standard PostScript prolog.
21 * end_ps() - Send the standard PostScript trailer.
22 * print_self_test_page() - Print a self-test page.
23 * report_levels() - Report supply levels.
24 */
25
26 /*
27 * Include necessary headers...
28 */
29
30 #include <cups/cups.h>
31 #include <cups/string-private.h>
32 #include <cups/sidechannel.h>
33
34
35 /*
36 * Local functions...
37 */
38
39 static void auto_configure(ppd_file_t *ppd, const char *user);
40 static void begin_ps(ppd_file_t *ppd, const char *user);
41 static void end_ps(ppd_file_t *ppd);
42 static void print_self_test_page(ppd_file_t *ppd, const char *user);
43 static void report_levels(ppd_file_t *ppd, const char *user);
44
45
46 /*
47 * 'main()' - Process a CUPS command file.
48 */
49
50 int /* O - Exit status */
51 main(int argc, /* I - Number of command-line arguments */
52 char *argv[]) /* I - Command-line arguments */
53 {
54 cups_file_t *fp; /* Command file */
55 char line[1024], /* Line from file */
56 *value; /* Value on line */
57 int linenum; /* Line number in file */
58 ppd_file_t *ppd; /* PPD file */
59
60
61 /*
62 * Check for valid arguments...
63 */
64
65 if (argc < 6 || argc > 7)
66 {
67 /*
68 * We don't have the correct number of arguments; write an error message
69 * and return.
70 */
71
72 fputs("ERROR: commandtops job-id user title copies options [file]\n", stderr);
73 return (1);
74 }
75
76 /*
77 * Open the PPD file...
78 */
79
80 if ((ppd = ppdOpenFile(getenv("PPD"))) == NULL)
81 {
82 fputs("ERROR: Unable to open PPD file!\n", stderr);
83 return (1);
84 }
85
86 /*
87 * Open the command file as needed...
88 */
89
90 if (argc == 7)
91 {
92 if ((fp = cupsFileOpen(argv[6], "r")) == NULL)
93 {
94 perror("ERROR: Unable to open command file - ");
95 return (1);
96 }
97 }
98 else
99 fp = cupsFileStdin();
100
101 /*
102 * Read the commands from the file and send the appropriate commands...
103 */
104
105 linenum = 0;
106
107 while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum))
108 {
109 /*
110 * Parse the command...
111 */
112
113 if (!strcasecmp(line, "AutoConfigure"))
114 auto_configure(ppd, argv[2]);
115 else if (!strcasecmp(line, "PrintSelfTestPage"))
116 print_self_test_page(ppd, argv[2]);
117 else if (!strcasecmp(line, "ReportLevels"))
118 report_levels(ppd, argv[2]);
119 else
120 fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", line);
121 }
122
123 return (0);
124 }
125
126
127 /*
128 * 'auto_configure()' - Automatically configure the printer using PostScript
129 * query commands and/or SNMP lookups.
130 */
131
132 static void
133 auto_configure(ppd_file_t *ppd, /* I - PPD file */
134 const char *user) /* I - Printing user */
135 {
136 ppd_option_t *option; /* Current option in PPD */
137 ppd_attr_t *attr; /* Query command attribute */
138 char buffer[1024], /* String buffer */
139 *bufptr; /* Pointer into buffer */
140 ssize_t bytes; /* Number of bytes read */
141 int datalen; /* Side-channel data length */
142
143
144 /*
145 * See if the backend supports bidirectional I/O...
146 */
147
148 datalen = 1;
149 if (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_BIDI, buffer, &datalen,
150 30.0) != CUPS_SC_STATUS_OK ||
151 buffer[0] != CUPS_SC_BIDI_SUPPORTED)
152 {
153 fputs("DEBUG: Unable to auto-configure PostScript Printer - no "
154 "bidirectional I/O available!\n", stderr);
155 return;
156 }
157
158 /*
159 * Put the printer in PostScript mode...
160 */
161
162 begin_ps(ppd, user);
163
164 /*
165 * Then loop through every option in the PPD file and ask for the current
166 * value...
167 */
168
169 fputs("DEBUG: Auto-configuring PostScript printer...\n", stderr);
170
171 for (option = ppdFirstOption(ppd); option; option = ppdNextOption(ppd))
172 {
173 /*
174 * See if we have a query command for this option...
175 */
176
177 snprintf(buffer, sizeof(buffer), "?%s", option->keyword);
178
179 if ((attr = ppdFindAttr(ppd, buffer, NULL)) == NULL || !attr->value)
180 {
181 fprintf(stderr, "DEBUG: Skipping %s option...\n", option->keyword);
182 continue;
183 }
184
185 /*
186 * Send the query code to the printer...
187 */
188
189 fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword);
190 fputs(attr->value, stdout);
191 fflush(stdout);
192
193 datalen = 0;
194 cupsSideChannelDoRequest(CUPS_SC_CMD_DRAIN_OUTPUT, buffer, &datalen, 5.0);
195
196 /*
197 * Read the response data...
198 */
199
200 while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer) - 1, 5.0)) > 0)
201 {
202 /*
203 * Trim whitespace from both ends...
204 */
205
206 buffer[bytes] = '\0';
207
208 for (bufptr = buffer + bytes - 1; bufptr >= buffer; bufptr --)
209 if (isspace(*bufptr & 255))
210 *bufptr = '\0';
211 else
212 break;
213
214 for (bufptr = buffer; isspace(*bufptr & 255); bufptr ++);
215
216 /*
217 * Skip blank lines...
218 */
219
220 if (!*bufptr)
221 continue;
222
223 /*
224 * Write out the result and move on to the next option...
225 */
226
227 fprintf(stderr, "DEBUG: Default%s=%s\n", option->keyword, bufptr);
228 fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, bufptr);
229 break;
230 }
231 }
232
233 /*
234 * Finish the job...
235 */
236
237 end_ps(ppd);
238 }
239
240
241 /*
242 * 'begin_ps()' - Send the standard PostScript prolog.
243 */
244
245 static void
246 begin_ps(ppd_file_t *ppd, /* I - PPD file */
247 const char *user) /* I - Username */
248 {
249 (void)user;
250
251 if (ppd->jcl_begin)
252 {
253 fputs(ppd->jcl_begin, stdout);
254 fputs(ppd->jcl_ps, stdout);
255 }
256
257 puts("%!");
258 puts("userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
259 fflush(stdout);
260 }
261
262
263 /*
264 * 'end_ps()' - Send the standard PostScript trailer.
265 */
266
267 static void
268 end_ps(ppd_file_t *ppd) /* I - PPD file */
269 {
270 if (ppd->jcl_end)
271 fputs(ppd->jcl_end, stdout);
272 else
273 putchar(0x04);
274
275 fflush(stdout);
276 }
277
278
279 /*
280 * 'print_self_test_page()' - Print a self-test page.
281 */
282
283 static void
284 print_self_test_page(ppd_file_t *ppd, /* I - PPD file */
285 const char *user) /* I - Printing user */
286 {
287 /*
288 * Put the printer in PostScript mode...
289 */
290
291 begin_ps(ppd, user);
292
293 /*
294 * Send a simple file the draws a box around the imageable area and shows
295 * the product/interpreter information...
296 */
297
298 puts("% You are using the wrong driver for your printer!\n"
299 "0 setgray\n"
300 "2 setlinewidth\n"
301 "initclip newpath clippath gsave stroke grestore pathbbox\n"
302 "exch pop exch pop exch 9 add exch 9 sub moveto\n"
303 "/Courier findfont 12 scalefont setfont\n"
304 "0 -12 rmoveto gsave product show grestore\n"
305 "0 -12 rmoveto gsave version show ( ) show revision 20 string cvs show "
306 "grestore\n"
307 "0 -12 rmoveto gsave serialnumber 20 string cvs show grestore\n"
308 "showpage");
309
310 /*
311 * Finish the job...
312 */
313
314 end_ps(ppd);
315 }
316
317
318 /*
319 * 'report_levels()' - Report supply levels.
320 */
321
322 static void
323 report_levels(ppd_file_t *ppd, /* I - PPD file */
324 const char *user) /* I - Printing user */
325 {
326 /*
327 * Put the printer in PostScript mode...
328 */
329
330 begin_ps(ppd, user);
331
332 /*
333 * Don't bother sending any additional PostScript commands, since we just
334 * want the backend to have enough time to collect the supply info.
335 */
336
337 /*
338 * Finish the job...
339 */
340
341 end_ps(ppd);
342 }
343
344
345 /*
346 * End of "$Id$".
347 */