Esempio n. 1
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  int		i,			/* Looping vars */
		list_filters = 0;	/* Just list the filters? */
  const char	*command,		/* Command name */
		*opt,			/* Current option */
		*printer;		/* Printer name */
  mime_type_t	*printer_type,		/* Printer MIME type */
		*prefilter_type;	/* Printer prefilter MIME type */
  char		*srctype,		/* Source type */
		*dsttype,		/* Destination type */
		super[MIME_MAX_SUPER],	/* Super-type name */
		type[MIME_MAX_TYPE];	/* Type name */
  int		compression;		/* Compression of file */
  int		cost;			/* Cost of filters */
  mime_t	*mime;			/* MIME database */
  char		mimedir[1024];		/* MIME directory */
  char		*infile,		/* File to filter */
		*outfile;		/* File to create */
  char		cupsfilesconf[1024];	/* cups-files.conf file */
  const char	*server_root;		/* CUPS_SERVERROOT environment variable */
  mime_type_t	*src,			/* Source type */
		*dst;			/* Destination type */
  cups_array_t	*filters;		/* Filters for the file */
  int		num_options;		/* Number of options */
  cups_option_t	*options;		/* Options */
  const char	*ppdfile;		/* PPD file */
  const char	*title,			/* Title string */
		*user;			/* Username */
  int		all_filters,		/* Use all filters */
		removeppd,		/* Remove PPD file */
		removeinfile;		/* Remove input file */
  int		status;			/* Execution status */


 /*
  * Setup defaults...
  */

  if ((command = strrchr(argv[0], '/')) != NULL)
    command ++;
  else
    command = argv[0];

  printer      = !strcmp(command, "convert") ? "tofile" : "cupsfilter";
  mime         = NULL;
  srctype      = NULL;
  compression  = 0;
  dsttype      = "application/pdf";
  infile       = NULL;
  outfile      = NULL;
  num_options  = 0;
  options      = NULL;
  ppdfile      = NULL;
  title        = NULL;
  user         = cupsUser();
  all_filters  = 0;
  removeppd    = 0;
  removeinfile = 0;

  if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
    server_root = CUPS_SERVERROOT;

  snprintf(cupsfilesconf, sizeof(cupsfilesconf), "%s/cups-files.conf", server_root);

 /*
  * Process command-line arguments...
  */

  _cupsSetLocale(argv);

  for (i = 1; i < argc; i ++)
  {
    if (argv[i][0] == '-')
    {
      if (!strcmp(argv[i], "--list-filters"))
      {
        list_filters = 1;
      }
      else if (!strcmp(argv[i], "--"))
      {
	i ++;
	if (i < argc && !infile)
	  infile = argv[i];
	else
	  usage(NULL);
      }
      else
      {
	for (opt = argv[i] + 1; *opt; opt ++)
	{
	  switch (*opt)
	  {
	    case 'a' : /* Specify option... */
		i ++;
		if (i < argc)
		  num_options = cupsParseOptions(argv[i], num_options, &options);
		else
		  usage(opt);
		break;

	    case 'c' : /* Specify cups-files.conf file location... */
		i ++;
		if (i < argc)
		{
		  if (!strcmp(command, "convert"))
		    num_options = cupsAddOption("copies", argv[i], num_options, &options);
		  else
		    strlcpy(cupsfilesconf, argv[i], sizeof(cupsfilesconf));
		}
		else
		  usage(opt);
		break;

	    case 'd' : /* Specify the real printer name */
		i ++;
		if (i < argc)
		  printer = argv[i];
		else
		  usage(opt);
		break;

	    case 'D' : /* Delete input file after conversion */
		removeinfile = 1;
		break;

	    case 'e' : /* Use every filter from the PPD file */
		all_filters = 1;
		break;

	    case 'f' : /* Specify input file... */
		i ++;
		if (i < argc && !infile)
		  infile = argv[i];
		else
		  usage(opt);
		break;

	    case 'i' : /* Specify source MIME type... */
		i ++;
		if (i < argc)
		{
		  if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
		    usage(opt);

		  srctype = argv[i];
		}
		else
		  usage(opt);
		break;

	    case 'j' : /* Get job file or specify destination MIME type... */
		if (strcmp(command, "convert"))
		{
		  i ++;
		  if (i < argc)
		  {
		    get_job_file(argv[i]);
		    infile = TempFile;
		  }
		  else
		    usage(opt);

		  break;
		}

	    case 'm' : /* Specify destination MIME type... */
		i ++;
		if (i < argc)
		{
		  if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
		    usage(opt);

		  dsttype = argv[i];
		}
		else
		  usage(opt);
		break;

	    case 'n' : /* Specify number of copies... */
		i ++;
		if (i < argc)
		  num_options = cupsAddOption("copies", argv[i], num_options, &options);
		else
		  usage(opt);
		break;

	    case 'o' : /* Specify option(s) or output filename */
		i ++;
		if (i < argc)
		{
		  if (!strcmp(command, "convert"))
		  {
		    if (outfile)
		      usage(NULL);
		    else
		      outfile = argv[i];
		  }
		  else
		    num_options = cupsParseOptions(argv[i], num_options, &options);
		}
		else
		  usage(opt);
		break;

	    case 'p' : /* Specify PPD file... */
	    case 'P' : /* Specify PPD file... */
		i ++;
		if (i < argc)
		  ppdfile = argv[i];
		else
		  usage(opt);
		break;

	    case 't' : /* Specify title... */
	    case 'J' : /* Specify title... */
		i ++;
		if (i < argc)
		  title = argv[i];
		else
		  usage(opt);
		break;

	    case 'u' : /* Delete PPD file after conversion */
		removeppd = 1;
		break;

	    case 'U' : /* Specify username... */
		i ++;
		if (i < argc)
		  user = argv[i];
		else
		  usage(opt);
		break;

	    default : /* Something we don't understand... */
		usage(opt);
		break;
	  }
	}
      }
    }
    else if (!infile)
    {
      if (strcmp(command, "convert"))
	infile = argv[i];
      else
	usage(NULL);
    }
    else
    {
      _cupsLangPuts(stderr,
                    _("cupsfilter: Only one filename can be specified."));
      usage(NULL);
    }
  }

  if (!infile && !srctype)
    usage(NULL);

  if (!title)
  {
    if (!infile)
      title = "(stdin)";
    else if ((title = strrchr(infile, '/')) != NULL)
      title ++;
    else
      title = infile;
  }

 /*
  * Load the cups-files.conf file and create the MIME database...
  */

  if (read_cups_files_conf(cupsfilesconf))
    return (1);

  snprintf(mimedir, sizeof(mimedir), "%s/mime", DataDir);

  mime = mimeLoadTypes(NULL, mimedir);
  mime = mimeLoadTypes(mime, ServerRoot);
  mime = mimeLoadFilters(mime, mimedir, Path);
  mime = mimeLoadFilters(mime, ServerRoot, Path);

  if (!mime)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unable to read MIME database from \"%s\" or "
		      "\"%s\"."),
		    command, mimedir, ServerRoot);
    return (1);
  }

  prefilter_type = NULL;

  if (all_filters)
    printer_type = add_printer_filters(command, mime, printer, ppdfile,
				       &prefilter_type);
  else
    printer_type   = mimeType(mime, "application", "vnd.cups-postscript");

 /*
  * Get the source and destination types...
  */

  if (srctype)
  {
   /* sscanf return value already checked above */
    sscanf(srctype, "%15[^/]/%255s", super, type);
    if ((src = mimeType(mime, super, type)) == NULL)
    {
      _cupsLangPrintf(stderr,
		      _("%s: Unknown source MIME type %s/%s."),
		      command, super, type);
      return (1);
    }
  }
  else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unable to determine MIME type of \"%s\"."),
		    command, infile);
    return (1);
  }

 /* sscanf return value already checked above */
  sscanf(dsttype, "%15[^/]/%255s", super, type);
  if (!_cups_strcasecmp(super, "printer"))
    dst = printer_type;
  else if ((dst = mimeType(mime, super, type)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unknown destination MIME type %s/%s."),
		    command, super, type);
    return (1);
  }

 /*
  * Figure out how to filter the file...
  */

  if (src == dst)
  {
   /*
    * Special case - no filtering needed...
    */

    filters = cupsArrayNew(NULL, NULL);
    cupsArrayAdd(filters, &GZIPFilter);
    GZIPFilter.src = src;
    GZIPFilter.dst = dst;
  }
  else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: No filter to convert from %s/%s to %s/%s."),
		    command, src->super, src->type, dst->super, dst->type);
    return (1);
  }
  else if (compression)
    cupsArrayInsert(filters, &GZIPFilter);

  if (prefilter_type)
  {
   /*
    * Add pre-filters...
    */

    mime_filter_t	*filter,	/* Current filter */
			*prefilter;	/* Current pre-filter */
    cups_array_t	*prefilters = cupsArrayNew(NULL, NULL);
					/* New filters array */


    for (filter = (mime_filter_t *)cupsArrayFirst(filters);
	 filter;
	 filter = (mime_filter_t *)cupsArrayNext(filters))
    {
      if ((prefilter = mimeFilterLookup(mime, filter->src,
                                        prefilter_type)) != NULL)
	cupsArrayAdd(prefilters, prefilter);

      cupsArrayAdd(prefilters, filter);
    }

    cupsArrayDelete(filters);
    filters = prefilters;
  }

  if (list_filters)
  {
   /*
    * List filters...
    */

    mime_filter_t	*filter;	/* Current filter */

    for (filter = (mime_filter_t *)cupsArrayFirst(filters);
	 filter;
	 filter = (mime_filter_t *)cupsArrayNext(filters))
      if (strcmp(filter->filter, "-"))
        _cupsLangPuts(stdout, filter->filter);

    status = 0;
  }
  else
  {
   /*
    * Run filters...
    */

    status = exec_filters(src, filters, infile, outfile, ppdfile, printer, user,
			  title, num_options, options);
  }

 /*
  * Remove files as needed, then exit...
  */

  if (TempFile[0])
    unlink(TempFile);

  if (removeppd && ppdfile)
    unlink(ppdfile);

  if (removeinfile && infile)
    unlink(infile);

  return (status);
}
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping var */
  output_format_t    output_format;     /* Output format */
  int		fd = 0;			/* Copy file descriptor */
  char		*filename,		/* PDF file to convert */
		tempfile[1024];		/* Temporary file */
  char		buffer[8192];		/* Copy buffer */
  int		bytes;			/* Bytes copied */
  int		num_options;		/* Number of options */
  cups_option_t	*options;		/* Options */
  const char	*val;			/* Option value */
  char	        *argv_nt[8];		/* NULL-terminated array of the command
					   line arguments */
  int           optbuflen;
  cups_array_t  *filter_chain;          /* Filter chain to execute */
  int		exit_status = 0;	/* Exit status */
  int		color_printing;		/* Do we print in color? */
  char		*filter, *p;
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Actions for POSIX signals */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
  static const char * const color_mode_option_names[] =
    {	/* Possible names for a color mode option */
      "pwg-raster-document-type",
      "PwgRasterDocumentType",
      "print-color-mode",
      "PrintColorMode",
      "color-space",
      "ColorSpace",
      "color-model",
      "ColorModel",
      NULL
    };


 /*
  * Make sure status messages are not buffered...
  */

  setbuf(stderr, NULL);

 /*
  * Ignore broken pipe signals...
  */

  signal(SIGPIPE, SIG_IGN);

 /*
  * Make sure we have the right number of arguments for CUPS!
  */

  if (argc < 6 || argc > 7)
  {
    fprintf(stderr, "Usage: %s job user title copies options [file]\n",
	    argv[0]);
    return (1);
  }

 /*
  * Register a signal handler to cleanly cancel a job.
  */

#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
  sigset(SIGTERM, cancel_job);
#elif defined(HAVE_SIGACTION)
  memset(&action, 0, sizeof(action));

  sigemptyset(&action.sa_mask);
  action.sa_handler = cancel_job;
  sigaction(SIGTERM, &action, NULL);
#else
  signal(SIGTERM, cancel_job);
#endif /* HAVE_SIGSET */

 /*
  * Copy stdin if needed...
  */

  if (argc == 6)
  {
   /*
    * Copy stdin to a temp file...
    */

    if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
    {
      perror("DEBUG: Unable to copy PDF file");
      return (1);
    }

    fprintf(stderr, "DEBUG: sys5ippprinter - 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';
  }

 /*
  * Get the options from the fifth command line argument
  */

  num_options = cupsParseOptions(argv[5], 0, &options);

 /*
  * Copy the command line arguments into a NULL-terminated array
  */

  for (i = 0; i < 5; i++)
    argv_nt[i] = argv[i];
  /* We copy the contents of argv[5] into a somewhat larger buffer so that
     we can manipulate it */
  optbuflen = strlen(argv[5]) + 256;
  argv_nt[5] = calloc(optbuflen, sizeof(char));
  strcpy(argv_nt[5], (const char*)argv[5]);
  argv_nt[6] = filename;
  argv_nt[7] = NULL;

 /*
  * Create filter chain
  */

  filter_chain = cupsArrayNew(NULL, NULL);

 /*
  * Add the gziptoany filter if installed
  */

  if (filter_present("gziptoany"))
    cupsArrayAdd(filter_chain, "gziptoany");

 /*
  * If the rastertopdf filter is present and the input is in PWG Raster format
  * add the rastertopdf filter to the filter chain to support the PWG Raster
  * input. Same for JPEG input if imagetopdf is present. This way the PPD-less
  * auto-generated print queue emulates an IPP Everywhere printer, as PPDed
  * CUPS queues do.
  */
  
  if (filter_present("rastertopdf") && (val = getenv("CONTENT_TYPE")) != NULL &&
      strcasestr(val, "pwg-raster") != NULL) {
    cupsArrayAdd(filter_chain, "rastertopdf");
  } else if (filter_present("imagetopdf") &&
	     (val = getenv("CONTENT_TYPE")) != NULL &&
	     strcasestr(val, "jpeg") != NULL) {
    cupsArrayAdd(filter_chain, "imagetopdf");
  }

 /*
  * Check the presence of the pdftopdf filter and add it to the filter
  * chain if it is there
  */

  if (filter_present("pdftopdf"))
    cupsArrayAdd(filter_chain, "pdftopdf");

 /*
  * Select the output format: PDF, PostScript, PWG Raster, PCL-XL, and
  * PCL 5c/e
  * Add the needed filters to the filter chain
  */

  if ((val = cupsGetOption("output-format", num_options, options)) != NULL)
  {
    if (strcasestr(val, "raster"))
    {
      output_format = PWGRASTER;
      /* PWG Raster output */
      set_option_in_str(argv_nt[5], optbuflen, "MediaClass", NULL);
      set_option_in_str(argv_nt[5], optbuflen, "media-class", "PwgRaster");
      if (filter_present("gstoraster") && access(CUPS_GHOSTSCRIPT, X_OK) == 0)
	cupsArrayAdd(filter_chain, "gstoraster");
      else
      {
	fprintf(stderr,
		"DEBUG: Filter gstoraster or Ghostscript (%s) missing for \"output-format=%s\", using pdftoraster.\n", CUPS_GHOSTSCRIPT, val);
	if (filter_present("pdftoraster"))
	  cupsArrayAdd(filter_chain, "pdftoraster");
	else
	{
	  fprintf(stderr,
		  "ERROR: Filter pdftoraster missing for \"output-format=%s\"\n", val);
	  exit_status = 1;
	  goto error;
	}
      }
    }
    else if (strcasestr(val, "pdf"))
      output_format = PDF;
    else if (strcasestr(val, "postscript"))
    {
      output_format = POSTSCRIPT;
      if (filter_present("pdftops"))
      {
	cupsArrayAdd(filter_chain, "pdftops");
	if (access(CUPS_GHOSTSCRIPT, X_OK) != 0)
	{
	  fprintf(stderr,
		  "DEBUG: Ghostscript (%s) missing for \"output-format=%s\", using Poppler's pdftops instead.\n", CUPS_GHOSTSCRIPT, val);
	  set_option_in_str(argv_nt[5], optbuflen, "pdftops-renderer",
			    "pdftops");
	}
	else if (access(CUPS_POPPLER_PDFTOPS, X_OK) != 0)
	{
	  fprintf(stderr,
		  "DEBUG: Poppler's pdftops (%s) missing for \"output-format=%s\", using Ghostscript instead.\n", CUPS_POPPLER_PDFTOPS, val);
	  set_option_in_str(argv_nt[5], optbuflen, "pdftops-renderer",
			    "gs");
	}
	else
	  set_option_in_str(argv_nt[5], optbuflen, "pdftops-renderer",
			    "hybrid");
      }
      else
      {
	fprintf(stderr,
		"ERROR: Filter pdftops missing for \"output-format=%s\"\n", val);
	exit_status = 1;
	goto error;
      }
    }
    else if ((p = strcasestr(val, "pcl")) != NULL)
    {
      if (!strcasecmp(p, "pclxl"))
      {
	output_format = PCLXL;
	if (filter_present("gstopxl") && access(CUPS_GHOSTSCRIPT, X_OK) == 0)
	  cupsArrayAdd(filter_chain, "gstopxl");
	else
	{
	  fprintf(stderr,
		  "DEBUG: Filter gstopxl or Ghostscript (%s) missing for \"output-format=%s\", falling back to PCL 5c/e.\n", CUPS_GHOSTSCRIPT, val);
	  output_format = PCL;
	}
      }
      else
      {
	output_format = PCL;
      }
    }
    else
    {
      fprintf(stderr,
	      "ERROR: Invalid value for \"output-format\": \"%s\"\n", val);
      exit_status = 1;
      goto error;
    }
  }
  else
  {
    fprintf(stderr,
	    "ERROR: Missing option \"output-format\".\n");
    exit_status = 1;
    goto error;
  }
  if (output_format == PCL)
  {
    /* We need CUPS Raster as we want to use rastertopclx with unprintable
       margins */
    set_option_in_str(argv_nt[5], optbuflen, "MediaClass", NULL);
    set_option_in_str(argv_nt[5], optbuflen, "media-class", "");
    /* Does the client send info about margins? */
    if (!get_option_in_str(argv_nt[5], "media-left-margin", 0) &&
	!get_option_in_str(argv_nt[5], "media-right-margin", 0) &&
	!get_option_in_str(argv_nt[5], "media-top-margin", 0) &&
	!get_option_in_str(argv_nt[5], "media-bottom-margin", 0))
    {
      /* Set default 12pt margins if there is no info about printer's
	 unprintable margins (100th of mm units, 12.0 * 2540.0 / 72.0 = 423.33)
      */
      set_option_in_str(argv_nt[5], optbuflen, "media-left-margin", "423.33");
      set_option_in_str(argv_nt[5], optbuflen, "media-right-margin", "423.33");
      set_option_in_str(argv_nt[5], optbuflen, "media-top-margin", "423.33");
      set_option_in_str(argv_nt[5], optbuflen, "media-bottom-margin", "423.33");
    }
    /* Check whether the job is requested to be printed in color and if so,
       set the color space to RGB as this is the best color printing support
       in PCL 5c */
    color_printing = 0;
    for (i = 0; color_mode_option_names[i]; i ++)
    {
      p = get_option_in_str(argv_nt[5], color_mode_option_names[i], 1);
      if (p && (strcasestr(p, "RGB") || strcasestr(p, "CMY") ||
		strcasestr(p, "color")))
      {
	color_printing = 1;
	break;
      }
    }
    if (color_printing == 1)
    {
      /* Remove unneeded color mode options */
      for (i = 0; color_mode_option_names[i]; i ++)
	set_option_in_str(argv_nt[5], optbuflen, color_mode_option_names[i],
			  NULL);
      /* Set RGB as color mode */
      set_option_in_str(argv_nt[5], optbuflen, "print-color-mode", "RGB");
    }
    if (filter_present("gstoraster") && access(CUPS_GHOSTSCRIPT, X_OK) == 0)
      cupsArrayAdd(filter_chain, "gstoraster");
    else
    {
      fprintf(stderr,
	      "DEBUG: Filter gstoraster or Ghostscript (%s) missing for \"output-format=%s\", using pdftoraster.\n", CUPS_GHOSTSCRIPT, val);
      if (filter_present("pdftoraster"))
	cupsArrayAdd(filter_chain, "pdftoraster");
      else
      {
	fprintf(stderr,
		"ERROR: Filter pdftoraster missing for \"output-format=%s\"\n", val);
	exit_status = 1;
	goto error;
      }
    }
    if (filter_present("rastertopclx"))
      cupsArrayAdd(filter_chain, "rastertopclx");
    else
    {
      fprintf(stderr,
	      "ERROR: Filter rastertopclx missing for \"output-format=%s\"\n", val);
      exit_status = 1;
      goto error;
    }
  }

  fprintf(stderr,
	  "DEBUG: Printer supports output formats: %s\nDEBUG: Using following CUPS filter chain to convert input data to the %s format:",
	  val,
	  output_format == PDF ? "PDF" :
	  (output_format == POSTSCRIPT ? "Postscript" :
	   (output_format == PWGRASTER ? "PWG Raster" :
	    (output_format == PCLXL ? "PCL XL" :
	     (output_format == PCL ? "PCL 5c/e" : "unknown")))));
  for (filter = (char *)cupsArrayFirst(filter_chain);
       filter;
       filter = (char *)cupsArrayNext(filter_chain))
    fprintf(stderr, " %s", filter);
  fprintf(stderr, "\n");

 /*
  * Execute the filter chain
  */

  exit_status = exec_filters(filter_chain, (char **)argv_nt);

 /*
  * Cleanup and exit...
  */

  error:

  if (tempfile[0])
    unlink(tempfile);

  return (exit_status);
}
Esempio n. 3
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line args */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping vars */
  const char	*command,		/* Command name */
		*opt;			/* Current option */
  char		*srctype,		/* Source type */
		*dsttype,		/* Destination type */
		super[MIME_MAX_SUPER],	/* Super-type name */
		type[MIME_MAX_TYPE];	/* Type name */
  int		compression;		/* Compression of file */
  int		cost;			/* Cost of filters */
  mime_t	*mime;			/* MIME database */
  char		*infile,		/* File to filter */
		*outfile;		/* File to create */
  char		cupsdconf[1024];	/* cupsd.conf file */
  const char	*server_root;		/* CUPS_SERVERROOT environment variable */
  mime_type_t	*src,			/* Source type */
		*dst;			/* Destination type */
  cups_array_t	*filters;		/* Filters for the file */
  int		num_options;		/* Number of options */
  cups_option_t	*options;		/* Options */
  const char	*ppdfile;		/* PPD file */
  const char	*title,			/* Title string */
		*user;			/* Username */
  int		removeppd,		/* Remove PPD file */
		removeinfile;		/* Remove input file */
  int		status;			/* Execution status */


 /*
  * Setup defaults...
  */

  if ((command = strrchr(argv[0], '/')) != NULL)
    command ++;
  else
    command = argv[0];

  mime         = NULL;
  srctype      = NULL;
  compression  = 0;
  dsttype      = "application/pdf";
  infile       = NULL;
  outfile      = NULL;
  num_options  = 0;
  options      = NULL;
  ppdfile      = NULL;
  title        = NULL;
  user         = cupsUser();
  removeppd    = 0;
  removeinfile = 0;

  if ((server_root = getenv("CUPS_SERVERROOT")) == NULL)
    server_root = CUPS_SERVERROOT;

  snprintf(cupsdconf, sizeof(cupsdconf), "%s/cupsd.conf", server_root);

 /*
  * Process command-line arguments...
  */

  _cupsSetLocale(argv);

  for (i = 1; i < argc; i ++)
    if (argv[i][0] == '-')
    {
      for (opt = argv[i] + 1; *opt; opt ++)
        switch (*opt)
	{
	  case '-' : /* Next argument is a filename... */
	      i ++;
	      if (i < argc && !infile)
	        infile = argv[i];
	      else
	        usage(command, opt);
	      break;

          case 'a' : /* Specify option... */
	      i ++;
	      if (i < argc)
	        num_options = cupsParseOptions(argv[i], num_options, &options);
	      else
	        usage(command, opt);
	      break;

          case 'c' : /* Specify cupsd.conf file location... */
	      i ++;
	      if (i < argc)
	      {
	        if (!strcmp(command, "convert"))
		  num_options = cupsAddOption("copies", argv[i], num_options,
					      &options);
		else
		  strlcpy(cupsdconf, argv[i], sizeof(cupsdconf));
	      }
	      else
	        usage(command, opt);
	      break;

	  case 'D' : /* Delete input file after conversion */
	      removeinfile = 1;
	      break;

          case 'f' : /* Specify input file... */
	      i ++;
	      if (i < argc && !infile)
	        infile = argv[i];
	      else
	        usage(command, opt);
	      break;

          case 'i' : /* Specify source MIME type... */
	      i ++;
	      if (i < argc)
	      {
	        if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
		  usage(command, opt);

                srctype = argv[i];
	      }
	      else
	        usage(command, opt);
	      break;

          case 'j' : /* Specify destination MIME type... */
          case 'm' : /* Specify destination MIME type... */
	      i ++;
	      if (i < argc)
	      {
	        if (sscanf(argv[i], "%15[^/]/%255s", super, type) != 2)
		  usage(command, opt);

                dsttype = argv[i];
	      }
	      else
	        usage(command, opt);
	      break;

          case 'n' : /* Specify number of copies... */
	      i ++;
	      if (i < argc)
	        num_options = cupsAddOption("copies", argv[i], num_options,
		                            &options);
	      else
	        usage(command, opt);
	      break;

          case 'o' : /* Specify option(s) or output filename */
	      i ++;
	      if (i < argc)
	      {
	        if (!strcmp(command, "convert"))
		{
		  if (outfile)
		    usage(command, NULL);
		  else
		    outfile = argv[i];
		}
		else
	          num_options = cupsParseOptions(argv[i], num_options,
		                                 &options);
	      }
	      else
	        usage(command, opt);
	      break;

          case 'p' : /* Specify PPD file... */
          case 'P' : /* Specify PPD file... */
	      i ++;
	      if (i < argc)
	        ppdfile = argv[i];
	      else
	        usage(command, opt);
	      break;

          case 't' : /* Specify title... */
          case 'J' : /* Specify title... */
	      i ++;
	      if (i < argc)
	        title = argv[i];
	      else
	        usage(command, opt);
	      break;

	  case 'u' : /* Delete PPD file after conversion */
	      removeinfile = 1;
	      break;

          case 'U' : /* Specify username... */
	      i ++;
	      if (i < argc)
	        user = argv[i];
	      else
	        usage(command, opt);
	      break;

	  default : /* Something we don't understand... */
	      usage(command, opt);
	      break;
	}
    }
    else if (!infile)
    {
      if (strcmp(command, "convert"))
	infile = argv[i];
      else
      {
	_cupsLangPuts(stderr,
		      _("convert: Use the -f option to specify a file to "
		        "convert.\n"));
	usage(command, NULL);
      }
    }
    else
    {
      _cupsLangPuts(stderr,
                    _("cupsfilter: Only one filename can be specified!\n"));
      usage(command, NULL);
    }

  if (!infile && !srctype)
    usage(command, NULL);

  if (!title)
  {
    if (!infile)
      title = "(stdin)";
    else if ((title = strrchr(infile, '/')) != NULL)
      title ++;
    else
      title = infile;
  }

 /*
  * Load the cupsd.conf file and create the MIME database...
  */

  if (read_cupsd_conf(cupsdconf))
    return (1);

  if ((mime = mimeLoad(ServerRoot, Path)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unable to read MIME database from \"%s\"!\n"),
		    command, ServerRoot);
    return (1);
  }

 /*
  * Get the source and destination types...
  */

  if (srctype)
  {
    sscanf(srctype, "%15[^/]/%255s", super, type);
    if ((src = mimeType(mime, super, type)) == NULL)
    {
      _cupsLangPrintf(stderr,
		      _("%s: Unknown source MIME type %s/%s!\n"),
		      command, super, type);
      return (1);
    }
  }
  else if ((src = mimeFileType(mime, infile, infile, &compression)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unable to determine MIME type of \"%s\"!\n"),
		    command, infile);
    return (1);
  }

  sscanf(dsttype, "%15[^/]/%255s", super, type);
  if ((dst = mimeType(mime, super, type)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: Unknown destination MIME type %s/%s!\n"),
		    command, super, type);
    return (1);
  }

 /*
  * Figure out how to filter the file...
  */

  if (src == dst)
  {
   /*
    * Special case - no filtering needed...
    */

    filters = cupsArrayNew(NULL, NULL);
    cupsArrayAdd(filters, &GZIPFilter);
  }
  else if ((filters = mimeFilter(mime, src, dst, &cost)) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("%s: No filter to convert from %s/%s to %s/%s!\n"),
		    command, src->super, src->type, dst->super, dst->type);
    return (1);
  }
  else if (compression)
    cupsArrayInsert(filters, &GZIPFilter);

 /*
  * Do it!
  */

  status = exec_filters(filters, infile, outfile, ppdfile,
                        !strcmp(command, "convert") ? "tofile" : "cupsfilter",
			user, title, num_options, options);

 /*
  * Remove files as needed, then exit...
  */

  if (removeppd && ppdfile)
    unlink(ppdfile);

  if (removeinfile && infile)
    unlink(infile);

  return (status);
}