]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - filter/commandtops.c
Fix source file header text duplication text duplication.
[thirdparty/cups.git] / filter / commandtops.c
index 47a49072b12d2be58f7ac810c58f963e30b341e4..07979e03abb76876776f842c03ad9f25d022bf3e 100644 (file)
@@ -1,26 +1,13 @@
 /*
- * "$Id$"
+ * PostScript command filter for CUPS.
  *
- *   PostScript command filter for CUPS.
+ * Copyright 2008-2014 by Apple Inc.
  *
- *   Copyright 2008-2010 by Apple Inc.
- *
- *   These coded instructions, statements, and computer programs are the
- *   property of Apple Inc. and are protected by Federal copyright
- *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- *   which should have been included with this file.  If this file is
- *   file is missing or damaged, see the license at "http://www.cups.org/".
- *
- *
- * Contents:
- *
- *   main()                 - Process a CUPS command file.
- *   auto_configure()       - Automatically configure the printer using
- *                            PostScript query commands and/or SNMP lookups.
- *   begin_ps()             - Send the standard PostScript prolog.
- *   end_ps()               - Send the standard PostScript trailer.
- *   print_self_test_page() - Print a self-test page.
- *   report_levels()        - Report supply levels.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file.  If this file is
+ * missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
@@ -36,7 +23,7 @@
  * Local functions...
  */
 
-static void    auto_configure(ppd_file_t *ppd, const char *user);
+static int     auto_configure(ppd_file_t *ppd, const char *user);
 static void    begin_ps(ppd_file_t *ppd, const char *user);
 static void    end_ps(ppd_file_t *ppd);
 static void    print_self_test_page(ppd_file_t *ppd, const char *user);
@@ -51,6 +38,7 @@ int                                   /* O - Exit status */
 main(int  argc,                                /* I - Number of command-line arguments */
      char *argv[])                     /* I - Command-line arguments */
 {
+  int          status = 0;             /* Exit status */
   cups_file_t  *fp;                    /* Command file */
   char         line[1024],             /* Line from file */
                *value;                 /* Value on line */
@@ -70,7 +58,7 @@ main(int  argc,                               /* I - Number of command-line arguments */
     */
 
     _cupsLangPrintf(stderr,
-                    _("Usage: %s job-id user title copies options file"),
+                    _("Usage: %s job-id user title copies options [file]"),
                     argv[0]);
     return (1);
   }
@@ -112,17 +100,21 @@ main(int  argc,                           /* I - Number of command-line arguments */
     * Parse the command...
     */
 
-    if (!strcasecmp(line, "AutoConfigure"))
-      auto_configure(ppd, argv[2]);
-    else if (!strcasecmp(line, "PrintSelfTestPage"))
+    if (!_cups_strcasecmp(line, "AutoConfigure"))
+      status |= auto_configure(ppd, argv[2]);
+    else if (!_cups_strcasecmp(line, "PrintSelfTestPage"))
       print_self_test_page(ppd, argv[2]);
-    else if (!strcasecmp(line, "ReportLevels"))
+    else if (!_cups_strcasecmp(line, "ReportLevels"))
       report_levels(ppd, argv[2]);
     else
-      fprintf(stderr, "ERROR: Invalid printer command \"%s\"!\n", line);
+    {
+      _cupsLangPrintFilter(stderr, "ERROR",
+                           _("Invalid printer command \"%s\"."), line);
+      status = 1;
+    }
   }
 
-  return (0);
+  return (status);
 }
 
 
@@ -131,12 +123,14 @@ main(int  argc,                           /* I - Number of command-line arguments */
  *                      query commands and/or SNMP lookups.
  */
 
-static void
+static int                             /* O - Exit status */
 auto_configure(ppd_file_t *ppd,                /* I - PPD file */
                const char *user)       /* I - Printing user */
 {
+  int          status = 0;             /* Exit status */
   ppd_option_t *option;                /* Current option in PPD */
   ppd_attr_t   *attr;                  /* Query command attribute */
+  const char   *valptr;                /* Pointer into attribute value */
   char         buffer[1024],           /* String buffer */
                *bufptr;                /* Pointer into buffer */
   ssize_t      bytes;                  /* Number of bytes read */
@@ -154,7 +148,7 @@ auto_configure(ppd_file_t *ppd,             /* I - PPD file */
   {
     fputs("DEBUG: Unable to auto-configure PostScript Printer - no "
           "bidirectional I/O available!\n", stderr);
-    return;
+    return (1);
   }
 
  /*
@@ -163,6 +157,38 @@ auto_configure(ppd_file_t *ppd,            /* I - PPD file */
 
   begin_ps(ppd, user);
 
+ /*
+  * (STR #4028)
+  *
+  * As a lot of PPDs contain bad PostScript query code, we need to prevent one
+  * bad query sequence from affecting all auto-configuration.  The following
+  * error handler allows us to log PostScript errors to cupsd.
+  */
+
+  puts("/cups_handleerror {\n"
+       "  $error /newerror false put\n"
+       "  (:PostScript error in \") print cups_query_keyword print (\": ) "
+       "print\n"
+       "  $error /errorname get 128 string cvs print\n"
+       "  (; offending command:) print $error /command get 128 string cvs "
+       "print (\n) print flush\n"
+       "} bind def\n"
+       "errordict /timeout {} put\n"
+       "/cups_query_keyword (?Unknown) def\n");
+  fflush(stdout);
+
+ /*
+  * Wait for the printer to become connected...
+  */
+
+  do
+  {
+    sleep(1);
+    datalen = 1;
+  }
+  while (cupsSideChannelDoRequest(CUPS_SC_CMD_GET_CONNECTED, buffer, &datalen,
+                                  5.0) == CUPS_SC_STATUS_OK && !buffer[0]);
+
  /*
   * Then loop through every option in the PPD file and ask for the current
   * value...
@@ -189,7 +215,76 @@ auto_configure(ppd_file_t *ppd,            /* I - PPD file */
     */
 
     fprintf(stderr, "DEBUG: Querying %s...\n", option->keyword);
-    fputs(attr->value, stdout);
+
+    for (bufptr = buffer, valptr = attr->value; *valptr; valptr ++)
+    {
+     /*
+      * Log the query code, breaking at newlines...
+      */
+
+      if (*valptr == '\n')
+      {
+        *bufptr = '\0';
+        fprintf(stderr, "DEBUG: %s\\n\n", buffer);
+        bufptr = buffer;
+      }
+      else if (*valptr < ' ')
+      {
+        if (bufptr >= (buffer + sizeof(buffer) - 4))
+        {
+         *bufptr = '\0';
+         fprintf(stderr, "DEBUG: %s\n", buffer);
+         bufptr = buffer;
+        }
+
+        if (*valptr == '\r')
+        {
+          *bufptr++ = '\\';
+          *bufptr++ = 'r';
+        }
+        else if (*valptr == '\t')
+        {
+          *bufptr++ = '\\';
+          *bufptr++ = 't';
+        }
+        else
+        {
+          *bufptr++ = '\\';
+          *bufptr++ = '0' + ((*valptr / 64) & 7);
+          *bufptr++ = '0' + ((*valptr / 8) & 7);
+          *bufptr++ = '0' + (*valptr & 7);
+        }
+      }
+      else
+      {
+        if (bufptr >= (buffer + sizeof(buffer) - 1))
+        {
+         *bufptr = '\0';
+         fprintf(stderr, "DEBUG: %s\n", buffer);
+         bufptr = buffer;
+        }
+
+       *bufptr++ = *valptr;
+      }
+    }
+
+    if (bufptr > buffer)
+    {
+      *bufptr = '\0';
+      fprintf(stderr, "DEBUG: %s\n", buffer);
+    }
+
+    printf("/cups_query_keyword (?%s) def\n", option->keyword);
+                                       /* Set keyword for error reporting */
+    fputs("{ (", stdout);
+    for (valptr = attr->value; *valptr; valptr ++)
+    {
+      if (*valptr == '(' || *valptr == ')' || *valptr == '\\')
+        putchar('\\');
+      putchar(*valptr);
+    }
+    fputs(") cvx exec } stopped { cups_handleerror } if clear\n", stdout);
+                                       /* Send query code */
     fflush(stdout);
 
     datalen = 0;
@@ -199,44 +294,117 @@ auto_configure(ppd_file_t *ppd,          /* I - PPD file */
     * Read the response data...
     */
 
-    while ((bytes = cupsBackChannelRead(buffer, sizeof(buffer) - 1, 5.0)) > 0)
+    bufptr    = buffer;
+    buffer[0] = '\0';
+    while ((bytes = cupsBackChannelRead(bufptr, sizeof(buffer) - (size_t)(bufptr - buffer) - 1, 10.0)) > 0)
     {
      /*
-      * Trim whitespace from both ends...
+      * No newline at the end? Go on reading ...
+      */
+
+      bufptr += bytes;
+      *bufptr = '\0';
+
+      if (bytes == 0 ||
+          (bufptr > buffer && bufptr[-1] != '\r' && bufptr[-1] != '\n'))
+       continue;
+
+     /*
+      * Trim whitespace and control characters from both ends...
       */
 
-      buffer[bytes] = '\0';
+      bytes = bufptr - buffer;
 
-      for (bufptr = buffer + bytes - 1; bufptr >= buffer; bufptr --)
-        if (isspace(*bufptr & 255))
+      for (bufptr --; bufptr >= buffer; bufptr --)
+        if (isspace(*bufptr & 255) || iscntrl(*bufptr & 255))
          *bufptr = '\0';
        else
          break;
 
-      for (bufptr = buffer; isspace(*bufptr & 255); bufptr ++);
+      for (bufptr = buffer; isspace(*bufptr & 255) || iscntrl(*bufptr & 255);
+          bufptr ++);
+
+      if (bufptr > buffer)
+      {
+        _cups_strcpy(buffer, bufptr);
+       bufptr = buffer;
+      }
+
+      fprintf(stderr, "DEBUG: Got %d bytes.\n", (int)bytes);
 
      /*
       * Skip blank lines...
       */
 
-      if (!*bufptr)
+      if (!buffer[0])
+        continue;
+
+     /*
+      * Check the response...
+      */
+
+      if ((bufptr = strchr(buffer, ':')) != NULL)
+      {
+       /*
+        * PostScript code for this option in the PPD is broken; show the
+        * interpreter's error message that came back...
+        */
+
+       fprintf(stderr, "DEBUG%s\n", bufptr);
+       break;
+      }
+
+     /*
+      * Verify the result is a valid option choice...
+      */
+
+      if (!ppdFindChoice(option, buffer))
+      {
+       if (!strcasecmp(buffer, "Unknown"))
+         break;
+
+       bufptr    = buffer;
+       buffer[0] = '\0';
         continue;
+      }
 
      /*
       * Write out the result and move on to the next option...
       */
 
-      fprintf(stderr, "DEBUG: Default%s=%s\n", option->keyword, bufptr);
-      fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, bufptr);
+      fprintf(stderr, "PPD: Default%s=%s\n", option->keyword, buffer);
       break;
     }
+
+   /*
+    * Printer did not answer this option's query
+    */
+
+    if (bytes <= 0)
+    {
+      fprintf(stderr,
+             "DEBUG: No answer to query for option %s within 10 seconds.\n",
+             option->keyword);
+      status = 1;
+    }
   }
 
  /*
   * Finish the job...
   */
 
+  fflush(stdout);
   end_ps(ppd);
+
+ /*
+  * Return...
+  */
+
+  if (status)
+    _cupsLangPrintFilter(stderr, "WARNING",
+                         _("Unable to configure printer options."));
+
+  return (0);
 }
 
 
@@ -258,6 +426,7 @@ begin_ps(ppd_file_t *ppd,           /* I - PPD file */
 
   puts("%!");
   puts("userdict dup(\\004)cvn{}put (\\004\\004)cvn{}put\n");
+
   fflush(stdout);
 }
 
@@ -297,7 +466,12 @@ print_self_test_page(ppd_file_t *ppd,      /* I - PPD file */
   * the product/interpreter information...
   */
 
-  puts("% You are using the wrong driver for your printer!\n"
+  puts("\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
+       "%%%%%%%%%%%%%\n"
+       "\r%%%% If you can read this, you are using the wrong driver for your "
+       "printer. %%%%\n"
+       "\r%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"
+       "%%%%%%%%%%%%%\n"
        "0 setgray\n"
        "2 setlinewidth\n"
        "initclip newpath clippath gsave stroke grestore pathbbox\n"
@@ -342,8 +516,3 @@ report_levels(ppd_file_t *ppd,              /* I - PPD file */
 
   end_ps(ppd);
 }
-
-
-/*
- * End of "$Id$".
- */