]>
Commit | Line | Data |
---|---|---|
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 | */ |