2
* "$Id: commandtops.c 9793 2011-05-20 03:49:49Z mike $"
2
* "$Id: commandtops.c 10373 2012-03-21 23:00:05Z mike $"
4
4
* PostScript command filter for CUPS.
6
* Copyright 2008-2011 by Apple Inc.
6
* Copyright 2008-2012 by Apple Inc.
8
8
* These coded instructions, statements, and computer programs are the
9
9
* property of Apple Inc. and are protected by Federal copyright
36
36
* Local functions...
39
static void auto_configure(ppd_file_t *ppd, const char *user);
39
static int auto_configure(ppd_file_t *ppd, const char *user);
40
40
static void begin_ps(ppd_file_t *ppd, const char *user);
41
41
static void end_ps(ppd_file_t *ppd);
42
42
static void print_self_test_page(ppd_file_t *ppd, const char *user);
51
51
main(int argc, /* I - Number of command-line arguments */
52
52
char *argv[]) /* I - Command-line arguments */
54
int status = 0; /* Exit status */
54
55
cups_file_t *fp; /* Command file */
55
56
char line[1024], /* Line from file */
56
57
*value; /* Value on line */
115
116
if (!_cups_strcasecmp(line, "AutoConfigure"))
116
auto_configure(ppd, argv[2]);
117
status |= auto_configure(ppd, argv[2]);
117
118
else if (!_cups_strcasecmp(line, "PrintSelfTestPage"))
118
119
print_self_test_page(ppd, argv[2]);
119
120
else if (!_cups_strcasecmp(line, "ReportLevels"))
120
121
report_levels(ppd, argv[2]);
122
fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", line);
124
_cupsLangPrintFilter(stderr, "ERROR",
125
_("Invalid printer command \"%s\"."), line);
131
136
* query commands and/or SNMP lookups.
139
static int /* O - Exit status */
135
140
auto_configure(ppd_file_t *ppd, /* I - PPD file */
136
141
const char *user) /* I - Printing user */
143
int status = 0; /* Exit status */
138
144
ppd_option_t *option; /* Current option in PPD */
139
145
ppd_attr_t *attr; /* Query command attribute */
146
const char *valptr; /* Pointer into attribute value */
140
147
char buffer[1024], /* String buffer */
141
148
*bufptr; /* Pointer into buffer */
142
149
ssize_t bytes; /* Number of bytes read */
143
150
int datalen; /* Side-channel data length */
144
int ch; /* single character equivalent */
145
char *tempptr; /* Pointer into buffer */
166
171
begin_ps(ppd, user);
176
* As a lot of PPDs contain bad PostScript query code, we need to prevent one
177
* bad query sequence from affecting all auto-configuration. The following
178
* error handler allows us to log PostScript errors to cupsd.
181
puts("/cups_handleerror {\n"
182
" $error /newerror false put\n"
183
" (:PostScript error in \") print cups_query_keyword print (\": ) "
185
" $error /errorname get 128 string cvs print\n"
186
" (; offending command:) print $error /command get 128 string cvs "
187
"print (\n) print flush\n"
189
"errordict /timeout {} put\n"
190
"/cups_query_keyword (?Unknown) def\n");
178
202
while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen,
179
203
5.0) == CUPS_SC_STATUS_OK && !buffer[0]);
181
* As a lot of printer vendor supplied PPDs have exhibited erroneous PostScript
182
* constructs in query code sequences, we make auto configuring (almost) bomb proof even
183
* against syntax errors in PostScript code.
184
* As a first step, we establish our own PS error handler.
186
puts("/my_handleerror\n"
188
" $error/newerror false put\n"
189
" (:PostScript error in \")print query print (\": )print\n"
190
" $error/errorname get 128 string cvs print\n"
191
" (; offending command:)print $error/command get 128 string cvs print (\n)print flush\n"
193
"errordict/timeout{}put\n"
194
"/query (?Unknown) def\n");
197
206
* Then loop through every option in the PPD file and ask for the current
221
230
fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword);
222
fprintf(stdout, "/query (?%s)def\n", option->keyword); /* pass the keyword for error reporting */
223
puts("/this_query(");
225
* To prevent our own construct from failing due to unpaired parantheses
226
* within the query code, we take pains to escape thr "(" and ")".
228
fprintf(stderr, "DEBUG: %s\n", attr->value);
229
bufptr = attr->value;
233
if (ch == '(' || ch == ')') putchar('\\');
236
puts(")def\n{this_query cvx exec}stopped{userdict/my_handleerror get exec}if clear\n");
232
for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++)
235
* Log the query code, breaking at newlines...
241
fprintf(stderr, "DEBUG: %s\\n\n", buffer);
244
else if (*valptr < ' ')
246
if (bufptr >= (buffer + sizeof(buffer) - 4))
249
fprintf(stderr, "DEBUG: %s\n", buffer);
258
else if (*valptr == '\t')
266
*bufptr++ = '0' + ((*valptr / 64) & 7);
267
*bufptr++ = '0' + ((*valptr / 8) & 7);
268
*bufptr++ = '0' + (*valptr & 7);
273
if (bufptr >= (buffer + sizeof(buffer) - 1))
276
fprintf(stderr, "DEBUG: %s\n", buffer);
287
fprintf(stderr, "DEBUG: %s\n", buffer);
290
printf("/cups_query_keyword (?%s) def\n", option->keyword);
291
/* Set keyword for error reporting */
292
fputs("{ (", stdout);
293
for (valptr = attr->value; *valptr; valptr ++)
295
if (*valptr == '(' || *valptr == ')' || *valptr == '\\')
299
fputs(") cvx exec } stopped { cups_handleerror } if clear\n", stdout);
300
/* Send query code */
243
307
* Read the response data...
247
311
buffer[0] = '\0';
248
312
while ((bytes = cupsBackChannelRead(bufptr,
249
313
sizeof(buffer) - (bufptr - buffer) - 1,
252
*(bufptr + bytes) = '\0';
255
317
* No newline at the end? Go on reading ...
259
323
if (bytes == 0 ||
260
(bufptr - buffer < sizeof(buffer) - 1 &&
261
*(bufptr - 1) != '\r' && *(bufptr - 1) != '\n'))
324
(bufptr > buffer && bufptr[-1] != '\r' && bufptr[-1] != '\n'))
328
* Trim whitespace and control characters from both ends...
264
331
bytes = bufptr - buffer;
267
* Trim whitespace and control characters from both ends...
270
333
for (bufptr --; bufptr >= buffer; bufptr --)
271
334
if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255))
276
339
for (bufptr = buffer; isspace(*bufptr & 255) || iscntrl(*bufptr & 255);
279
fprintf(stderr, "DEBUG: Got \"%s\" (%d bytes)\n", bufptr, (int)bytes);
344
_cups_strcpy(buffer, bufptr);
348
fprintf(stderr, "DEBUG: Got %d bytes.\n", (int)bytes);
282
351
* Skip blank lines...
293
* PostScript code for this option in the PPD is broken...
358
* Check the response...
295
if ((tempptr = strchr(bufptr, ':')) != NULL)
361
if ((bufptr = strchr(buffer, ':')) != NULL)
297
fprintf(stderr, "DEBUG%s\n", tempptr); /* the interpreter's error message */
298
fprintf(stderr, "ERROR: PostScript error in query for option %s, default for this option not set.\n", option->keyword);
364
* PostScript code for this option in the PPD is broken; show the
365
* interpreter's error message that came back...
368
fprintf(stderr, "DEBUG%s\n", bufptr);
303
373
* Verify the result is a valid option choice...
306
if (!ppdFindChoice(option, bufptr))
376
if (!ppdFindChoice(option, buffer))
308
/* Consider "Unknown" as not configured in the printer */
309
if (!strcasecmp(bufptr, "Unknown"))
312
"WARNING: Printer answered query for the setting of option %s with \"Unknown\", default for this option not set.\n",
378
if (!strcasecmp(buffer, "Unknown"))
317
382
buffer[0] = '\0';
322
387
* Write out the result and move on to the next option...
325
fprintf(stderr, "DEBUG: Default%s=%s\n", option->keyword, bufptr);
326
fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, bufptr);
390
fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, buffer);
403
481
* the product/interpreter information...
406
puts("% You are using the wrong driver for your printer!\n"
484
puts("\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
486
"\r%%%% If you can read this, you are using the wrong driver for your "
488
"\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
408
491
"2 setlinewidth\n"
409
492
"initclip newpath clippath gsave stroke grestore pathbbox\n"