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