]>
Commit | Line | Data |
---|---|---|
7a14d768 MS |
1 | /* |
2 | * "$Id$" | |
3 | * | |
4 | * PostScript command filter for CUPS. | |
5 | * | |
f14324a7 | 6 | * Copyright 2008-2011 by Apple Inc. |
7a14d768 MS |
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 | * | |
75bd9771 MS |
17 | * main() - Process a CUPS command file. |
18 | * auto_configure() - Automatically configure the printer using | |
19 | * PostScript query commands and/or SNMP lookups. | |
4509bb49 MS |
20 | * begin_ps() - Send the standard PostScript prolog. |
21 | * end_ps() - Send the standard PostScript trailer. | |
75bd9771 MS |
22 | * print_self_test_page() - Print a self-test page. |
23 | * report_levels() - Report supply levels. | |
7a14d768 MS |
24 | */ |
25 | ||
26 | /* | |
27 | * Include necessary headers... | |
28 | */ | |
29 | ||
0837b7e8 | 30 | #include <cups/cups-private.h> |
aaf19ab0 | 31 | #include <cups/ppd.h> |
7a14d768 MS |
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); | |
4509bb49 MS |
40 | static void begin_ps(ppd_file_t *ppd, const char *user); |
41 | static void end_ps(ppd_file_t *ppd); | |
7a14d768 MS |
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 | ||
0837b7e8 MS |
72 | _cupsLangPrintf(stderr, |
73 | _("Usage: %s job-id user title copies options file"), | |
74 | argv[0]); | |
7a14d768 MS |
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 | ||
88f9aafc | 115 | if (!_cups_strcasecmp(line, "AutoConfigure")) |
7a14d768 | 116 | auto_configure(ppd, argv[2]); |
88f9aafc | 117 | else if (!_cups_strcasecmp(line, "PrintSelfTestPage")) |
7a14d768 | 118 | print_self_test_page(ppd, argv[2]); |
88f9aafc | 119 | else if (!_cups_strcasecmp(line, "ReportLevels")) |
7a14d768 MS |
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 | ||
4509bb49 | 164 | begin_ps(ppd, user); |
f14324a7 MS |
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]); | |
7a14d768 MS |
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 | ||
f14324a7 | 215 | while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer) - 1, 90.0)) > 0) |
7a14d768 MS |
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 | ||
f14324a7 MS |
231 | fprintf(stderr, "DEBUG: Got \"%s\" (%d bytes)\n", bufptr, (int)bytes); |
232 | ||
7a14d768 MS |
233 | /* |
234 | * Skip blank lines... | |
235 | */ | |
236 | ||
237 | if (!*bufptr) | |
238 | continue; | |
239 | ||
f14324a7 MS |
240 | /* |
241 | * Verify the result is a valid option choice... | |
242 | */ | |
243 | ||
244 | if (!ppdFindChoice(option, bufptr)) | |
245 | continue; | |
246 | ||
7a14d768 MS |
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 | ||
4509bb49 MS |
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 | { | |
c168a833 MS |
294 | if (ppd->jcl_end) |
295 | fputs(ppd->jcl_end, stdout); | |
7a14d768 MS |
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 | ||
4509bb49 | 315 | begin_ps(ppd, user); |
7a14d768 MS |
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 | ||
4509bb49 | 338 | end_ps(ppd); |
7a14d768 MS |
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 | ||
4509bb49 | 354 | begin_ps(ppd, user); |
7a14d768 | 355 | |
75bd9771 | 356 | /* |
4509bb49 MS |
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. | |
75bd9771 MS |
359 | */ |
360 | ||
7a14d768 MS |
361 | /* |
362 | * Finish the job... | |
363 | */ | |
364 | ||
4509bb49 | 365 | end_ps(ppd); |
7a14d768 MS |
366 | } |
367 | ||
368 | ||
369 | /* | |
370 | * End of "$Id$". | |
371 | */ |