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