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