]> git.ipfire.org Git - thirdparty/cups-filters.git/commitdiff
cups-browsed, implicitclass: Let the implicitclass backend use filter functions
authorTill Kamppeter <till.kamppeter@gmail.com>
Wed, 22 Dec 2021 20:08:04 +0000 (17:08 -0300)
committerTill Kamppeter <till.kamppeter@gmail.com>
Wed, 22 Dec 2021 20:08:04 +0000 (17:08 -0300)
Let the implicitclass backend use filter functions instead of calling
filter executables, to make use with the latest development of
cups-filters.

- We use the universal() filter function, as this automatically
  generates and executes a filter chain converting from a given input
  to a given output format.

- In cupsfilters/filter.c we create functions to simplify adding the
  FD_CLOEXEC and O_NONBLOCK (aka O_NDELAY) flags without losing any
  already set flags.

- In the filterChain() filter function we make sure that the file
  descriptors have the close-on-exec flag set, to assure that there
  are no file descriptors left open or accessible by the executables
  called by and of the filter functions in the chain.

- In filterExternalCUPS() we set O_NONBLOCK for stderr, back channel
  and side channel.

- In filterChain(), when closing unneeded file descriptors, we do not
  close FD 0 and FD 1 (stdin and stdout) as accidentally closing stdin
  or stdout can break the data stream connection to/from a backend or
  filter called by filterExternalCUPS() in the filter chain. Also
  check each file descriptor separately for this, instead of only
  checking one file descriptor and then close a group of file
  descriptors.

- cups-browsed now removes the unneeded "*cupsFilter:..." lines from the
  PPD for the local queue generated by cups-browsed, to assure that the
  inserted line for application/vnd.cups-pdf gets used.

NEWS
backend/implicitclass.c
cupsfilters/filter.c
utils/cups-browsed.c

diff --git a/NEWS b/NEWS
index c7267e0d4f3766b922df462a6d0414842727e28d..1624c7b3708a0e1f14bed5b9255ecb334b6af723 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ NEWS - OpenPrinting CUPS Filters v1.27.5 - 2020-06-05
 
 CHANGES IN V2.0.0
 
+       - cups-browsed, implicitclass: Let the implicitclass backend
+         use filter functions instead of calling filter executables.
        - libcupsfilters, universal: Added the universal() filter
          function which allows a single CUPS filter executable which
          auto-creates chains of filter function calls to convert any
index 6be85bf49d6a07d7c721ce494a23e5232191aadd..43e1283241ed705f5c0aaa266ae1a36fd205d8a3 100644 (file)
@@ -31,7 +31,7 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <cupsfilters/pdftoippprinter.h>
+#include <cupsfilters/filter.h>
 
 /*
  * Local globals...
@@ -44,7 +44,8 @@
 static int             job_canceled = 0; /* Set to 1 on SIGTERM */
 
 /*
- * Local functions... */
+ * Local functions...
+ */
 
 static void            sigterm_handler(int sig);
 
@@ -92,19 +93,11 @@ main(int  argc,                             /* I - Number of command-line args */
   const char *ptr1 = NULL;
   char *ptr2,*ptr3,*ptr4;
   const char *job_id;
-  char    *filename,    /* PDF file to convert */
-           tempfile[1024],
-           tempfile_filter[1024];   /* Temporary file */
   int i;
   char dest_host[1024];        /* Destination host */
   ipp_t *request, *response;
   ipp_attribute_t *attr;
-  int     bytes;      /* Bytes copied */
   char uri[HTTP_MAX_URI];
-  char    *argv_nt[8];
-  int     outbuflen, filefd, savestdout, exit_status, dup_status;
-  char buf[1024];
-  const char *serverbin;
   static const char *pattrs[] =
                 {
                   "printer-defaults"
@@ -241,11 +234,17 @@ main(int  argc,                           /* I - Number of command-line args */
       return (CUPS_BACKEND_RETRY_CURRENT);
     } else {
       /* We have the destination host name now, do the job */
-      const char *title;
+      char *title;
       int num_options = 0;
       cups_option_t *options = NULL;
-      int fd;
-      char buffer[8192];
+      int fd, nullfd;
+      filter_data_t filter_data;
+      filter_input_output_format_t input_output_format;
+      filter_external_cups_t ipp_backend_params;
+      filter_filter_in_chain_t universal_in_chain,
+                              ipp_in_chain;
+      cups_array_t *filter_chain;
+      int retval;
 
       fprintf(stderr, "DEBUG: Received destination host name from cups-browsed: printer-uri %s\n",
              ptr1);
@@ -290,125 +289,95 @@ main(int  argc,                          /* I - Number of command-line args */
       fprintf(stderr,"DEBUG: Received job for the printer with the destination uri - %s, Final-document format for the printer - %s and requested resolution - %s\n",
              printer_uri, document_format, resolution);
 
-      /* We need to send modified arguments to the IPP backend */
-      if (argc == 6) {
-       /* Copy stdin to a temp file...*/
-       if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0){
-         fprintf(stderr,"Debug: Can't Read PDF file.\n");
-         return CUPS_BACKEND_FAILED;
-       }
-       fprintf(stderr, "Debug: implicitclass - copying to temp print file \"%s\"\n",
-               tempfile);
-       while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0)
-         bytes = write(fd, buffer, bytes);
-       close(fd);
-       filename = tempfile;
-      } else {
-       /* Use the filename on the command-line... */
-       filename    = argv[6];
-       tempfile[0] = '\0';
-      }
-
-      /* Copying the argument to a new char** which will be sent to the filter
-        and the ipp backend */
-      argv_nt[0] = calloc(strlen(printer_uri) + 8, sizeof(char));
-      strcpy(argv_nt[0], printer_uri);
-      for (i = 1; i < 5; i++)
-       argv_nt[i] = argv[i];
-
-      /* Few new options will be added to the argv[5]*/
-      outbuflen = strlen(argv[5]) + 256;
-      argv_nt[5] = calloc(outbuflen, sizeof(char));
-      strcpy(argv_nt[5], (const char*)argv[5]);
-
-      /* Filter pdftoippprinter.c will read the input from this file*/
-      argv_nt[6] = filename;
-      argv_nt[7] = NULL;
-      set_option_in_str(argv_nt[5], outbuflen, "output-format",
-                       document_format);
-      set_option_in_str(argv_nt[5], outbuflen, "Resolution",resolution);
-      set_option_in_str(argv_nt[5], outbuflen, "cups-browsed-dest-printer",NULL);
-      set_option_in_str(argv_nt[5], outbuflen, "cups-browsed",NULL);
+      /* Adjust option list for the universal() filter function call */
+      num_options = cupsAddOption("Resolution", resolution,
+                                 num_options, &options);
+      num_options = cupsRemoveOption("cups-browsed-dest-printer",
+                                    num_options, &options);
+      num_options = cupsRemoveOption("cups-browsed",
+                                    num_options, &options);
+
+      /* Set up filter data record to be used by the filter functions to
+        process the job */
+      filter_data.printer = calloc(strlen(printer_uri) + 8, sizeof(char));
+      strcpy(filter_data.printer, printer_uri);
+      filter_data.job_id = atoi(argv[1]);
+      filter_data.job_user = argv[2];
+      filter_data.job_title = title;
+      filter_data.copies = atoi(argv[4]);
+      filter_data.job_attrs = NULL;        /* We use command line options */
+      filter_data.printer_attrs = NULL;    /* We use the queue's PPD file */
+      filter_data.num_options = num_options;
+      filter_data.options = options;       /* Command line options from 5th arg */
+      filter_data.ppdfile = getenv("PPD"); /* PPD file name in the "PPD"
+                                             environment variable. */
+      filter_data.ppd = filter_data.ppdfile ?
+       ppdOpenFile(filter_data.ppdfile) : NULL;
+      /* Load PPD file */
+      filter_data.back_pipe[0] = -1;       /* CUPS back channel not supported */
+      filter_data.back_pipe[1] = -1;
+      filter_data.side_pipe[0] = -1;       /* CUPS side channel not supported */
+      filter_data.side_pipe[1] = -1;
+      filter_data.logfunc = cups_logfunc;  /* Logging scheme of CUPS */
+      filter_data.logdata = NULL;
+      filter_data.iscanceledfunc = cups_iscanceledfunc; /* Job-is-canceled
+                                                          function */
+      filter_data.iscanceleddata = &job_canceled;
+      filterOpenBackAndSidePipes(&filter_data);
+
+      /* Parameters (input/output MIME types) for universal() call */
+      input_output_format.input_format = "application/vnd.cups-pdf";
+      input_output_format.output_format = document_format;
+
+      /* Parameters for filterExternalCUPS() call for IPP backend */
+      ipp_backend_params.filter = "ipp";
+      ipp_backend_params.is_backend = 1;
+      ipp_backend_params.device_uri = printer_uri;
+      ipp_backend_params.num_options = 0;
+      ipp_backend_params.options = NULL;
+      ipp_backend_params.envp = NULL;
+
+      /* Filter chain entry for the universal() filter function call */
+      universal_in_chain.function = universal;
+      universal_in_chain.parameters = &input_output_format;
+      universal_in_chain.name = "Filters";
+
+      /* Filter chain entry for the IPP CUPS backend call */
+      ipp_in_chain.function = filterExternalCUPS;
+      ipp_in_chain.parameters = &ipp_backend_params;
+      ipp_in_chain.name = "Backend";
+
+      filter_chain = cupsArrayNew(NULL, NULL);
+      cupsArrayAdd(filter_chain, &universal_in_chain);
+      cupsArrayAdd(filter_chain, &ipp_in_chain);
+
+      /* DEVICE_URI environment variable */
       setenv("DEVICE_URI",printer_uri, 1);
-      fprintf(stderr, "Setting the device uri to  %s\n",printer_uri);
-      fprintf(stderr, "Changed the argv[5] to %s\n",argv_nt[5]);
-
-      filefd = cupsTempFd(tempfile_filter, sizeof(tempfile_filter));
-
-      /* The output of the last filter in pdftoippprinter will be
-         written to this file. We could have sent the output directly
-         to the backend, but having this temperory file will help us
-         find whether the filter worked correctly and what was the
-         document-format of the filtered output.*/
-      savestdout = dup(1);
-      dup_status = dup2(filefd, 1);
-      if(dup_status < 0) {
-        fprintf(stderr, "Could not write the output of pdftoippprinter printer to tmp file\n");
-        return CUPS_BACKEND_FAILED;
-      }
-      close(filefd);
-
-      /* Calling pdftoippprinter.c filter*/
-      apply_filters(7,argv_nt);
-
-      /* Reset stdout to standard */
-      dup2(savestdout, 1);
-      close(savestdout);
-
-      /* We will send the filtered output of the pdftoippprinter.c to
-        the IPP Backend*/
-      argv_nt[6] = tempfile_filter;
-      fprintf(stderr, "DEBUG: The filtered output of pdftoippprinter is written to file %s\n",
-             tempfile_filter);
-
-      /* Setting the final content type to the best pdl supported by
-        the printer.*/
-      if(!strcmp(document_format,"pdf"))
-       setenv("FINAL_CONTENT_TYPE", "application/pdf", 1);
-      else if(!strcmp(document_format,"raster"))
-       setenv("FINAL_CONTENT_TYPE", "image/pwg-raster", 1);
-      else if(!strcmp(document_format,"apple-raster"))
-       setenv("FINAL_CONTENT_TYPE", "image/urf", 1);
-      else if(!strcmp(document_format,"pclm"))
-       setenv("FINAL_CONTENT_TYPE", "application/PCLm", 1);
-      else if(!strcmp(document_format,"pclxl"))
-       setenv("FINAL_CONTENT_TYPE", "application/vnd.hp-pclxl", 1);
-      else if(!strcmp(document_format,"postscript"))
-       setenv("FINAL_CONTENT_TYPE", "application/postscript", 1);
-      else if(!strcmp(document_format,"pcl"))
-       setenv("FINAL_CONTENT_TYPE", "application/pcl", 1);
 
+      /* FINAL_CONTENT_TYPE environment variable */
+      setenv("FINAL_CONTENT_TYPE", document_format, 1);
+
+      /* Mark the defaults and option settings in the PPD file */
+      ppdMarkDefaults(filter_data.ppd);
+      ppdMarkOptions(filter_data.ppd, num_options, options);
+
+      /* We call the IPP CUPS backend at the end of the chain, so we have
+        no output */
+      nullfd = open("/dev/null", O_WRONLY);
+
+      /* Call the filter chain to run the needed filters and the backend */
+      retval = filterChain(fd, nullfd, fd != 0 ? 1 : 0, &filter_data,
+                          filter_chain);
+
+      filterCloseBackAndSidePipes(&filter_data);
+
+      /* Clean up */
+      cupsArrayDelete(filter_chain);
       ippDelete(response);
-      fprintf(stderr, "Passing the following arguments to the ipp backend\n");
-      /* Arguments sent to the ipp backend */
-      for (i = 0; i < 7; i ++) {
-       fprintf(stderr, "argv[%d]: %s\n", i, argv_nt[i]);
-      }
 
-      /* The implicitclass backend will send the job directly to the
-        ipp backend*/
-
-      pid_t pid = fork();
-      if (pid == 0) {
-       serverbin = getenv("CUPS_SERVERBIN");
-       if (serverbin == NULL)
-         serverbin = CUPS_SERVERBIN;
-       snprintf(buf, sizeof(buf) - 1, "%s/backend/ipp", serverbin);
-       fprintf(stderr, "DEBUG: Started IPP Backend (%s) with pid: %d\n",
-               buf, getpid());
-       execv(buf, argv_nt);
-       fprintf(stderr, "ERROR: Could not start IPP Backend (%s): %d %s\n",
-               buf, errno, strerror(errno));
-       return CUPS_BACKEND_FAILED;
-      } else {
-       int status;
-       waitpid(pid, &status, 0);
-       if (WIFEXITED(status)) {
-         exit_status = WEXITSTATUS(status);
-         fprintf(stderr, "DEBUG: The IPP Backend exited with the status %d\n",
-                 exit_status);
-       }
-       return exit_status;
+      if (retval) {
+       fprintf(stderr, "ERROR: Job processing failed.\n");
+       return (CUPS_BACKEND_FAILED);
       }
     }
   } else if (argc != 1) {
index b12ac62ccc5da860510b7a537f8fba681e51ba0f..06b5cb8a4ab0a00d97b0cbbe5313e7f923f80218 100644 (file)
@@ -35,6 +35,30 @@ typedef struct filter_function_pid_s    /* Filter in filter chain */
 } filter_function_pid_t;
 
 
+/*
+ * 'fcntl_add_cloexec()' - Add FD_CLOEXEC flag to the flags
+ *                         of a given file descriptor.
+ */
+
+int                       /* Return value of fcntl() */
+fcntl_add_cloexec(int fd) /* File descriptor to add FD_CLOEXEC to */
+{
+  return fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+}
+
+
+/*
+ * 'fcntl_add_nodelay()' - Add O_NODELAY flag to the flags
+ *                         of a given file descriptor.
+ */
+
+int                        /* Return value of fcntl() */
+fcntl_add_nonblock(int fd) /* File descriptor to add O_NONBLOCK to */
+{
+  return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+}
+
+
 /*
  * 'cups_logfunc()' - Output log messages on stderr, compatible to CUPS,
  *                    meaning that the debug level is represented by a
@@ -611,10 +635,12 @@ filterChain(int inputfd,         /* I - File descriptor input stream */
        filter = next, current = 1 - current) {
     next = (filter_filter_in_chain_t *)cupsArrayNext(filter_chain);
 
-    if (filterfds[1 - current][1] > 1) {
+    if (filterfds[1 - current][0] > 1) {
       close(filterfds[1 - current][0]);
-      close(filterfds[1 - current][1]);
       filterfds[1 - current][0] = -1;
+    }
+    if (filterfds[1 - current][1] > 1) {
+      close(filterfds[1 - current][1]);
       filterfds[1 - current][1] = -1;
     }
 
@@ -626,6 +652,8 @@ filterChain(int inputfd,         /* I - File descriptor input stream */
                     strerror(errno));
        return (1);
       }
+      fcntl_add_cloexec(filterfds[1 - current][0]);
+      fcntl_add_cloexec(filterfds[1 - current][1]);
     } else
       filterfds[1 - current][1] = outputfd;
 
@@ -638,8 +666,10 @@ filterChain(int inputfd,         /* I - File descriptor input stream */
 
       infd = filterfds[current][0];
       outfd = filterfds[1 - current][1];
-      close(filterfds[current][1]);
-      close(filterfds[1 - current][0]);
+      if (filterfds[current][1] > 1)
+       close(filterfds[current][1]);
+      if (filterfds[1 - current][0] > 1)
+       close(filterfds[1 - current][0]);
 
       if (infd < 0)
        infd = open("/dev/null", O_RDONLY);
@@ -685,15 +715,14 @@ filterChain(int inputfd,         /* I - File descriptor input stream */
   * Close remaining pipes...
   */
 
-  if (filterfds[0][1] > 1) {
+  if (filterfds[0][0] > 1)
     close(filterfds[0][0]);
+  if (filterfds[0][1] > 1)
     close(filterfds[0][1]);
-  }
-
-  if (filterfds[1][1] > 1) {
+  if (filterfds[1][0] > 1)
     close(filterfds[1][0]);
+  if (filterfds[1][1] > 1)
     close(filterfds[1][1]);
-  }
 
  /*
   * Wait for the children to exit...
@@ -1155,20 +1184,37 @@ filterExternalCUPS(int inputfd,         /* I - File descriptor input stream */
     */
 
     if (inputfd != 0) {
-      if (inputfd < 0)
+      if (inputfd < 0) {
         inputfd = open("/dev/null", O_RDONLY);
+       if (log) log(ld, FILTER_LOGLEVEL_ERROR,
+                    "filterExternalCUPS (%s): No input file descriptor supplied for CUPS filter - %s",
+                  filter_name, strerror(errno));
+      }
 
       if (inputfd > 0) {
-        dup2(inputfd, 0);
+       fcntl_add_cloexec(inputfd);
+        if (dup2(inputfd, 0) < 0) {
+         if (log) log(ld, FILTER_LOGLEVEL_ERROR,
+                      "filterExternalCUPS (%s): Failed to connect input file descriptor with CUPS filter's stdin - %s",
+                      filter_name, strerror(errno));
+         goto fd_error;
+       } else
+         if (log) log(ld, FILTER_LOGLEVEL_DEBUG,
+                      "filterExternalCUPS (%s): Connected input file descriptor %d to CUPS filter's stdin.",
+                      filter_name, inputfd);
        close(inputfd);
       }
-    }
+    } else
+      if (log) log(ld, FILTER_LOGLEVEL_DEBUG,
+                  "filterExternalCUPS (%s): Input comes from stdin, letting the filter grab stdin directly",
+                  filter_name);
 
     if (outputfd != 1) {
       if (outputfd < 0)
         outputfd = open("/dev/null", O_WRONLY);
 
       if (outputfd > 1) {
+       fcntl_add_cloexec(outputfd);
        dup2(outputfd, 1);
        close(outputfd);
       }
@@ -1178,14 +1224,17 @@ filterExternalCUPS(int inputfd,         /* I - File descriptor input stream */
       /* Send stderr to the Nirwana if we are running gziptoany, as
         gziptoany emits a false "PAGE: 1 1" */
       if ((fd = open("/dev/null", O_RDWR)) > 2) {
+       fcntl_add_cloexec(fd);
        dup2(fd, 2);
        close(fd);
       } else
         close(fd);
-    } else
+    } else {
       /* Send stderr into pipe for logging */
+      fcntl_add_cloexec(stderrpipe[1]);
       dup2(stderrpipe[1], 2);
-    fcntl(2, F_SETFL, O_NDELAY);
+      fcntl_add_nonblock(2);
+    }
     close(stderrpipe[0]);
     close(stderrpipe[1]);
 
@@ -1194,29 +1243,28 @@ filterExternalCUPS(int inputfd,         /* I - File descriptor input stream */
       if (backfd != 3 && backfd >= 0) {
        dup2(backfd, 3);
        close(backfd);
-       fcntl(3, F_SETFL, O_NDELAY);
+       fcntl_add_nonblock(3);
       } else if (backfd < 0) {
        if ((backfd = open("/dev/null", O_RDWR)) > 3) {
          dup2(backfd, 3);
          close(backfd);
-       }
-       else
+       } else
          close(backfd);
-       fcntl(3, F_SETFL, O_NDELAY);
+       fcntl_add_nonblock(3);
       }
 
       /* Side channel */
       if (sidefd != 4 && sidefd >= 0) {
        dup2(sidefd, 4);
        close(sidefd);
-       fcntl(4, F_SETFL, O_NDELAY);
+       fcntl_add_nonblock(4);
       } else if (sidefd < 0) {
        if ((sidefd = open("/dev/null", O_RDWR)) > 4) {
          dup2(sidefd, 4);
          close(sidefd);
        } else
          close(sidefd);
-       fcntl(4, F_SETFL, O_NDELAY);
+       fcntl_add_nonblock(4);
       }
     }
 
@@ -1231,6 +1279,7 @@ filterExternalCUPS(int inputfd,         /* I - File descriptor input stream */
                 filter_name, params->is_backend ? "backend" : "filter",
                 filter_path, strerror(errno));
 
+  fd_error:
     exit(errno);
   } else if (pid > 0) {
     if (log) log(ld, FILTER_LOGLEVEL_INFO,
@@ -1246,6 +1295,10 @@ filterExternalCUPS(int inputfd,         /* I - File descriptor input stream */
     status = 1;
     goto out;
   }
+  if (inputfd >= 0)
+    close(inputfd);
+  if (outputfd >= 0)
+    close(outputfd);
 
  /*
   * Log the filter's stderr
@@ -1429,12 +1482,10 @@ filterOpenBackAndSidePipes(
   * Set the "close on exec" flag on each end of the pipe...
   */
 
-  if (fcntl(data->back_pipe[0], F_SETFD,
-           fcntl(data->back_pipe[0], F_GETFD) | FD_CLOEXEC))
+  if (fcntl_add_cloexec(data->back_pipe[0]))
     goto out;
 
-  if (fcntl(data->back_pipe[1], F_SETFD,
-           fcntl(data->back_pipe[1], F_GETFD) | FD_CLOEXEC))
+  if (fcntl_add_cloexec(data->back_pipe[1]))
     goto out;
 
  /*
@@ -1448,18 +1499,14 @@ filterOpenBackAndSidePipes(
   * Make the side channel FDs non-blocking...
   */
 
-  if (fcntl(data->side_pipe[0], F_SETFL,
-           fcntl(data->side_pipe[0], F_GETFL) | O_NONBLOCK))
+  if (fcntl_add_nonblock(data->side_pipe[0]))
     goto out;
-  if (fcntl(data->side_pipe[1], F_SETFL,
-           fcntl(data->side_pipe[1], F_GETFL) | O_NONBLOCK))
+  if (fcntl_add_nonblock(data->side_pipe[1]))
     goto out;
 
-  if (fcntl(data->side_pipe[0], F_SETFD,
-           fcntl(data->side_pipe[0], F_GETFD) | FD_CLOEXEC))
+  if (fcntl_add_cloexec(data->side_pipe[0]))
     goto out;
-  if (fcntl(data->side_pipe[1], F_SETFD,
-           fcntl(data->side_pipe[1], F_GETFD) | FD_CLOEXEC))
+  if (fcntl_add_cloexec(data->side_pipe[1]))
     goto out;
 
   if (log) log(ld, FILTER_LOGLEVEL_DEBUG,
index a75fce1c0440314b46d970c2bbe0e7275d79fb15..50210775d4afee68d851cb9f4b3c7df19547b495 100644 (file)
@@ -6532,22 +6532,22 @@ on_job_state (CupsNotifier *object,
       document_format = (char *)malloc(sizeof(char) * 32);
       if (cupsArrayFind(pdl_list, "application/vnd.cups-pdf") ||
          cupsArrayFind(pdl_list, "application/pdf"))
-       strcpy(document_format, "pdf");
+       strcpy(document_format, "application/vnd.cups-pdf");
       else if (cupsArrayFind(pdl_list, "image/urf"))
-       strcpy(document_format, "apple-raster");
+       strcpy(document_format, "image/urf");
       else if (cupsArrayFind(pdl_list, "image/pwg-raster"))
-       strcpy(document_format, "raster");
+       strcpy(document_format, "image/pwg-raster");
       else if (cupsArrayFind(pdl_list, "application/PCLm"))
-       strcpy(document_format, "pclm");
+       strcpy(document_format, "application/PCLm");
       else if (cupsArrayFind(pdl_list, "application/vnd.hp-pclxl"))
-       strcpy(document_format, "pclxl");
+       strcpy(document_format, "application/vnd.hp-pclxl");
       else if (cupsArrayFind(pdl_list, "application/vnd.cups-postscript") ||
               cupsArrayFind(pdl_list, "application/postscript"))
-       strcpy(document_format, "postscript");
+       strcpy(document_format, "application/postscript");
       else if (cupsArrayFind(pdl_list, "application/vnd.hp-pcl") ||
               cupsArrayFind(pdl_list, "application/pcl") ||
               cupsArrayFind(pdl_list, "application/x-pcl"))
-       strcpy(document_format, "pcl");
+       strcpy(document_format, "application/pcl");
 
       if (pdl_list)
         cupsArrayDelete(pdl_list);
@@ -7685,7 +7685,8 @@ void create_queue(void* arg) {
   ipp_t         *request;
   time_t        current_time;
   int           i, ap_remote_queue_id_line_inserted,
-                want_raw, num_cluster_printers = 0;
+                new_cupsfilter_line_inserted, want_raw,
+                num_cluster_printers = 0;
   char          *disabled_str;
   char          ppdgenerator_msg[1024];
   char          *ppdfile;
@@ -8293,9 +8294,31 @@ void create_queue(void* arg) {
                 loadedppd, p->queue_name,
                 " and doing client-side filtering of the job" ,
                 buf);
+    new_cupsfilter_line_inserted = 0;
     ap_remote_queue_id_line_inserted = 0;
     while (cupsFileGets(in, line, sizeof(line))) {
-      if (!strncmp(line, "*Default", 8)) {
+      if (!strncmp(line, "*cupsFilter:", 12) ||
+         !strncmp(line, "*cupsFilter2:", 13)) {
+       /* "*cupfFilter(2): ..." line: Remove it and replace the first
+          one by a line which makes the data get converted to PDF
+          (application/vnd.cups-pdf, pdftopdf filter applied) before
+          being passed on to the backend */
+       if (new_cupsfilter_line_inserted == 0) {
+         cupsFilePrintf(out, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 0 -\"\n");
+         new_cupsfilter_line_inserted = 1;
+       }
+       /* Find the end of the "*cupsFilter(2): ..." entry in the
+          case it spans more than one line */
+       do {
+         if (strlen(line) != 0) {
+           char *ptr = line + strlen(line) - 1;
+           while(isspace(*ptr) && ptr > line)
+             ptr --;
+           if (*ptr == '"')
+             break;
+         }
+       } while (cupsFileGets(in, line, sizeof(line)));
+      } else if (!strncmp(line, "*Default", 8)) {
        strncpy(keyword, line + 8, sizeof(keyword) - 1);
        if ((strlen(line) + 8) > 1023)
          keyword[1023] = '\0';
@@ -8386,7 +8409,8 @@ void create_queue(void* arg) {
          strncpy(p->nickname, ptr, nickname_len);
       }
     }
-    cupsFilePrintf(out,"*cupsFilter2: \"application/vnd.cups-pdf application/pdf 0 -\"\n");
+    if (new_cupsfilter_line_inserted == 0)
+      cupsFilePrintf(out, "*cupsFilter2: \"application/vnd.cups-pdf application/pdf 0 -\"\n");
 
     cupsFileClose(in);
     cupsFileClose(out);