~ubuntu-branches/ubuntu/precise/cups/precise

« back to all changes in this revision

Viewing changes to filter/commandtops.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2012-03-22 15:19:01 UTC
  • Revision ID: package-import@ubuntu.com-20120322151901-ocinzgb7te4jhg78
Tags: 1.5.2-8bzr2
debian/patches/commandtops-make-robust-against-broken-postscript.patch:
Updated patch to the upstream state of commandtops.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * "$Id: commandtops.c 9793 2011-05-20 03:49:49Z mike $"
 
2
 * "$Id: commandtops.c 10373 2012-03-21 23:00:05Z mike $"
3
3
 *
4
4
 *   PostScript command filter for CUPS.
5
5
 *
6
 
 *   Copyright 2008-2011 by Apple Inc.
 
6
 *   Copyright 2008-2012 by Apple Inc.
7
7
 *
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...
37
37
 */
38
38
 
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 */
53
53
{
 
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 */
113
114
    */
114
115
 
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]);
121
122
    else
122
 
      fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", line);
 
123
    {
 
124
      _cupsLangPrintFilter(stderr, "ERROR",
 
125
                           _("Invalid printer command \"%s\"."), line);
 
126
      status = 1;
 
127
    }
123
128
  }
124
129
 
125
 
  return (0);
 
130
  return (status);
126
131
}
127
132
 
128
133
 
131
136
 *                      query commands and/or SNMP lookups.
132
137
 */
133
138
 
134
 
static void
 
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 */
137
142
{
 
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 */
146
151
 
147
152
 
148
153
 /*
156
161
  {
157
162
    fputs("DEBUG: Unable to auto-configure PostScript Printer - no "
158
163
          "bidirectional I/O available!\n", stderr);
159
 
    return;
 
164
    return (1);
160
165
  }
161
166
 
162
167
 /*
164
169
  */
165
170
 
166
171
  begin_ps(ppd, user);
 
172
 
 
173
 /*
 
174
  * (STR #4028)
 
175
  *
 
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.
 
179
  */
 
180
 
 
181
  puts("/cups_handleerror {\n"
 
182
       "  $error /newerror false put\n"
 
183
       "  (:PostScript error in \") print cups_query_keyword print (\": ) "
 
184
       "print\n"
 
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"
 
188
       "} bind def\n"
 
189
       "errordict /timeout {} put\n"
 
190
       "/cups_query_keyword (?Unknown) def\n");
167
191
  fflush(stdout);
168
192
 
169
193
 /*
177
201
  }
178
202
  while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen,
179
203
                                  5.0) == CUPS_SC_STATUS_OK && !buffer[0]);
180
 
 /*
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.
185
 
  */
186
 
  puts("/my_handleerror\n"
187
 
        "{\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"
192
 
        "}bind def\n"
193
 
        "errordict/timeout{}put\n"
194
 
        "/query (?Unknown) def\n");
195
 
  fflush(stdout);
 
204
 
196
205
 /*
197
206
  * Then loop through every option in the PPD file and ask for the current
198
207
  * value...
219
228
    */
220
229
 
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(");
224
 
   /*
225
 
    * To prevent our own construct from failing due to unpaired parantheses
226
 
    * within the query code, we take pains to escape thr "(" and ")".
227
 
    */
228
 
    fprintf(stderr, "DEBUG: %s\n", attr->value);
229
 
    bufptr = attr->value;
230
 
    while (*bufptr)
231
 
    {
232
 
        ch = *bufptr++;
233
 
        if (ch == '(' || ch == ')') putchar('\\');
234
 
        putchar(ch);
235
 
    }
236
 
    puts(")def\n{this_query cvx exec}stopped{userdict/my_handleerror get exec}if clear\n");
 
231
 
 
232
    for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++)
 
233
    {
 
234
     /*
 
235
      * Log the query code, breaking at newlines...
 
236
      */
 
237
 
 
238
      if (*valptr == '\n')
 
239
      {
 
240
        *bufptr = '\0';
 
241
        fprintf(stderr, "DEBUG: %s\\n\n", buffer);
 
242
        bufptr = buffer;
 
243
      }
 
244
      else if (*valptr < ' ')
 
245
      {
 
246
        if (bufptr >= (buffer + sizeof(buffer) - 4))
 
247
        {
 
248
          *bufptr = '\0';
 
249
          fprintf(stderr, "DEBUG: %s\n", buffer);
 
250
          bufptr = buffer;
 
251
        }
 
252
 
 
253
        if (*valptr == '\r')
 
254
        {
 
255
          *bufptr++ = '\\';
 
256
          *bufptr++ = 'r';
 
257
        }
 
258
        else if (*valptr == '\t')
 
259
        {
 
260
          *bufptr++ = '\\';
 
261
          *bufptr++ = 't';
 
262
        }
 
263
        else
 
264
        {
 
265
          *bufptr++ = '\\';
 
266
          *bufptr++ = '0' + ((*valptr / 64) & 7);
 
267
          *bufptr++ = '0' + ((*valptr / 8) & 7);
 
268
          *bufptr++ = '0' + (*valptr & 7);
 
269
        }
 
270
      }
 
271
      else
 
272
      {
 
273
        if (bufptr >= (buffer + sizeof(buffer) - 1))
 
274
        {
 
275
          *bufptr = '\0';
 
276
          fprintf(stderr, "DEBUG: %s\n", buffer);
 
277
          bufptr = buffer;
 
278
        }
 
279
 
 
280
        *bufptr++ = *valptr;
 
281
      }
 
282
    }
 
283
 
 
284
    if (bufptr > buffer)
 
285
    {
 
286
      *bufptr = '\0';
 
287
      fprintf(stderr, "DEBUG: %s\n", buffer);
 
288
    }
 
289
 
 
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 ++)
 
294
    {
 
295
      if (*valptr == '(' || *valptr == ')' || *valptr == '\\')
 
296
        putchar('\\');
 
297
      putchar(*valptr);
 
298
    }
 
299
    fputs(") cvx exec } stopped { cups_handleerror } if clear\n", stdout);
 
300
                                        /* Send query code */
237
301
    fflush(stdout);
238
302
 
239
303
    datalen = 0;
243
307
    * Read the response data...
244
308
    */
245
309
 
246
 
    bufptr = buffer;
 
310
    bufptr    = buffer;
247
311
    buffer[0] = '\0';
248
312
    while ((bytes = cupsBackChannelRead(bufptr,
249
313
                                        sizeof(buffer) - (bufptr - buffer) - 1,
250
314
                                        10.0)) > 0)
251
315
    {
252
 
      *(bufptr + bytes) = '\0';
253
 
 
254
316
     /*
255
317
      * No newline at the end? Go on reading ...
256
318
      */
257
319
 
258
320
      bufptr += bytes;
 
321
      *bufptr = '\0';
 
322
 
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'))
262
325
        continue;
263
326
 
 
327
     /*
 
328
      * Trim whitespace and control characters from both ends...
 
329
      */
 
330
 
264
331
      bytes = bufptr - buffer;
265
332
 
266
 
     /*
267
 
      * Trim whitespace and control characters from both ends...
268
 
      */
269
 
 
270
333
      for (bufptr --; bufptr >= buffer; bufptr --)
271
334
        if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255))
272
335
          *bufptr = '\0';
276
339
      for (bufptr = buffer; isspace(*bufptr & 255) || iscntrl(*bufptr & 255);
277
340
           bufptr ++);
278
341
 
279
 
      fprintf(stderr, "DEBUG: Got \"%s\" (%d bytes)\n", bufptr, (int)bytes);
 
342
      if (bufptr > buffer)
 
343
      {
 
344
        _cups_strcpy(buffer, bufptr);
 
345
        bufptr = buffer;
 
346
      }
 
347
 
 
348
      fprintf(stderr, "DEBUG: Got %d bytes.\n", (int)bytes);
280
349
 
281
350
     /*
282
351
      * Skip blank lines...
283
352
      */
284
353
 
285
 
      if (!*bufptr)
286
 
      {
287
 
        bufptr = buffer;
288
 
        buffer[0] = '\0';
 
354
      if (!buffer[0])
289
355
        continue;
290
 
      }
291
356
 
292
357
     /*
293
 
      * PostScript code for this option in the PPD is broken...
 
358
      * Check the response...
294
359
      */
295
 
      if ((tempptr = strchr(bufptr, ':')) != NULL)
 
360
 
 
361
      if ((bufptr = strchr(buffer, ':')) != NULL)
296
362
      {
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);
 
363
       /*
 
364
        * PostScript code for this option in the PPD is broken; show the
 
365
        * interpreter's error message that came back...
 
366
        */
 
367
 
 
368
        fprintf(stderr, "DEBUG%s\n", bufptr);
299
369
        break;
300
370
      }
301
371
 
303
373
      * Verify the result is a valid option choice...
304
374
      */
305
375
 
306
 
      if (!ppdFindChoice(option, bufptr))
 
376
      if (!ppdFindChoice(option, buffer))
307
377
      {
308
 
        /* Consider "Unknown" as not configured in the printer */
309
 
        if (!strcasecmp(bufptr, "Unknown"))
310
 
        {
311
 
          fprintf(stderr,
312
 
                  "WARNING: Printer answered query for the setting of option %s with \"Unknown\", default for this option not set.\n",
313
 
                  option->keyword);
 
378
        if (!strcasecmp(buffer, "Unknown"))
314
379
          break;
315
 
        }
316
 
        bufptr = buffer;
 
380
 
 
381
        bufptr    = buffer;
317
382
        buffer[0] = '\0';
318
383
        continue;
319
384
      }
322
387
      * Write out the result and move on to the next option...
323
388
      */
324
389
 
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);
327
391
      break;
328
392
    }
329
393
 
332
396
    */
333
397
 
334
398
    if (bytes <= 0)
 
399
    {
335
400
      fprintf(stderr,
336
 
              "ERROR: Printer timed out on option %s, default for this option not set.\n",
 
401
              "DEBUG: No answer to query for option %s within 10 seconds.\n",
337
402
              option->keyword);
 
403
      status = 1;
 
404
    }
338
405
  }
339
406
 
340
407
 /*
343
410
 
344
411
  fflush(stdout);
345
412
  end_ps(ppd);
 
413
 
 
414
 /*
 
415
  * Return...
 
416
  */
 
417
 
 
418
  if (status)
 
419
    _cupsLangPrintFilter(stderr, "WARNING",
 
420
                         _("Unable to configure printer options."));
 
421
 
 
422
  return (0);
346
423
}
347
424
 
348
425
 
364
441
 
365
442
  puts("%!");
366
443
  puts("userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
 
444
 
367
445
  fflush(stdout);
368
446
}
369
447
 
403
481
  * the product/interpreter information...
404
482
  */
405
483
 
406
 
  puts("% You are using the wrong driver for your printer!\n"
 
484
  puts("\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
 
485
       "%%%%%%%%%%%%%\n"
 
486
       "\r%%%% If you can read this, you are using the wrong driver for your "
 
487
       "printer. %%%%\n"
 
488
       "\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
 
489
       "%%%%%%%%%%%%%\n"
407
490
       "0 setgray\n"
408
491
       "2 setlinewidth\n"
409
492
       "initclip newpath clippath gsave stroke grestore pathbbox\n"
451
534
 
452
535
 
453
536
/*
454
 
 * End of "$Id: commandtops.c 9793 2011-05-20 03:49:49Z mike $".
 
537
 * End of "$Id: commandtops.c 10373 2012-03-21 23:00:05Z mike $".
455
538
 */