//
// spooler.c
//
// Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
// Copyright (C) 2008 Lars Karlitski (formerly Uebernickel) <lars@karlitski.net>
//
// This file is part of foomatic-rip.
//
// Licensed under Apache License v2.0.  See the file "LICENSE" for more
// information.
//

#include "spooler.h"
#include "foomaticrip.h"
#include "util.h"
#include "options.h"
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>


const char *
spooler_name(int spooler)
{
  switch (spooler)
  {
    case SPOOLER_CUPS:
        return ("cups");
    case SPOOLER_DIRECT:
        return ("direct");
  };
  return ("<unknown>");
}


void
init_cups(list_t *arglist,
	  dstr_t *filelist,
	  jobparams_t *job)
{
  char path [PATH_MAX] = "";
  char cups_jobid [128];
  char cups_user [128];
  char cups_jobtitle [2048];
  char cups_copies [128];
  int cups_options_len;
  char *cups_options;
  const char *pname;
  char cups_filename [256];

  if (getenv("CUPS_FONTPATH"))
    strncpy(path, getenv("CUPS_FONTPATH"), PATH_MAX - 1);
  else if (getenv("CUPS_DATADIR"))
  {
    strncpy(path, getenv("CUPS_DATADIR"), PATH_MAX - 1);
    strncat(path, "/fonts", PATH_MAX - strlen(path) - 1);
  }
  if (getenv("GS_LIB"))
  {
    strncat(path, ":", PATH_MAX - strlen(path) - 1);
    strncat(path, getenv("GS_LIB"), PATH_MAX - strlen(path) - 1);
  }
  setenv("GS_LIB", path, 1);

  // Get all command line parameters
  strncpy_omit(cups_jobid, arglist_get(arglist, 0), 128, omit_shellescapes);
  strncpy_omit(cups_user, arglist_get(arglist, 1), 128, omit_shellescapes);
  strncpy_omit(cups_jobtitle, arglist_get(arglist, 2), 2048,
	       omit_shellescapes);
  strncpy_omit(cups_copies, arglist_get(arglist, 3), 128, omit_shellescapes);

  cups_options_len = strlen(arglist_get(arglist, 4));
  cups_options = malloc(cups_options_len + 1);
  strncpy_omit(cups_options, arglist_get(arglist, 4), cups_options_len + 1,
	       omit_shellescapes);

  // Common job parameters
  strcpy(job->id, cups_jobid);
  strcpy(job->title, cups_jobtitle);
  strcpy(job->user, cups_user);
  strcpy(job->copies, cups_copies);
  dstrcatf(job->optstr, " %s", cups_options);

  // Check for and handle inputfile vs stdin
  if (list_item_count(arglist) > 4)
  {
    strncpy_omit(cups_filename, arglist_get(arglist, 5), 256,
		 omit_shellescapes);
    if (cups_filename[0] != '-')
    {
      // We get input from a file
      dstrcatf(filelist, "%s ", cups_filename);
      _log("Getting input from file %s\n", cups_filename);
    }
  }

  // On which queue are we printing?
  // CUPS puts the print queue name into the PRINTER environment variable
  // when calling filters.
  pname = getenv("PRINTER");
  if (pname == NULL)
    pname = "unknown";
  strncpy(job->printer, pname, 256);
  job->printer[255] = '\0';

  free(cups_options);
}


// used by init_direct to find a ppd file
int
find_ppdfile(const char *user_default_path,
	     jobparams_t *job)
{
  // Search also common spooler-specific locations, this way a printer
  // configured under a certain spooler can also be used without spooler

  strcpy(job->ppdfile, job->printer);
  if (access(job->ppdfile, R_OK) == 0)
    return (1);

  snprintf(job->ppdfile, 2048, "%s.ppd", job->printer); // current dir
  if (access(job->ppdfile, R_OK) == 0)
    return (1);
  snprintf(job->ppdfile, 2048, "%s/%s.ppd", user_default_path, job->printer);
                                                        // user dir
  if (access(job->ppdfile, R_OK) == 0)
    return (1);
  snprintf(job->ppdfile, 2048, "%s/direct/%s.ppd", CONFIG_PATH, job->printer);
                                                        // system dir
  if (access(job->ppdfile, R_OK) == 0)
    return (1);
  snprintf(job->ppdfile, 2048, "%s/%s.ppd", CONFIG_PATH, job->printer);
                                                        // system dir
  if (access(job->ppdfile, R_OK) == 0)
    return (1);
  snprintf(job->ppdfile, 2048, "/etc/cups/ppd/%s.ppd", job->printer);
                                                        // CUPS config dir
  if (access(job->ppdfile, R_OK) == 0)
    return (1);
  snprintf(job->ppdfile, 2048, "/usr/local/etc/cups/ppd/%s.ppd", job->printer);
                                                        // CUPS config dir
  if (access(job->ppdfile, R_OK) == 0)
    return (1);

  // nothing found
  job->ppdfile[0] = '\0';
  return (0);
}


// search 'configfile' for 'key', copy value into dest, return success
int
configfile_find_option(const char *configfile,
		       const char *key,
		       char *dest,
		       size_t destsize)
{
  FILE *fh;
  char line [1024];
  char *p;

  dest[0] = '\0';

  if (!(fh = fopen(configfile, "r")))
    return (0);

  while (fgets(line, 1024, fh))
  {
    if (!prefixcmp(line, "default"))
    {
      p = strchr(line, ':');
      if (p)
      {
	strncpy_omit(dest, p + 1, destsize, omit_whitespace_newline);
	if (dest[0])
	  break;
      }
    }
  }
  fclose(fh);
  return (dest[0] != '\0');
}


// tries to find a default printer name in various config files and copies the
// result into the global var 'printer'. Returns success
int
find_default_printer(const char *user_default_path,
		     jobparams_t *job)
{
  char configfile [1024];
  char *key = "default";

  if (configfile_find_option("./.directconfig", key, job->printer, 256))
    return (1);
  if (configfile_find_option("./directconfig", key, job->printer, 256))
    return (1);
  if (configfile_find_option("./.config", key, job->printer, 256))
    return (1);
  strlcpy(configfile, user_default_path, 1024);
  strlcat(configfile, "/direct/.config", 1024);
  if (configfile_find_option(configfile, key, job->printer, 256))
    return (1);
  strlcpy(configfile, user_default_path, 1024);
  strlcat(configfile, "/direct.conf", 1024);
  if (configfile_find_option(configfile, key, job->printer, 256))
    return (1);
  if (configfile_find_option(CONFIG_PATH "/direct/.config", key, job->printer,
			     256))
    return (1);
  if (configfile_find_option(CONFIG_PATH "/direct.conf", key, job->printer,
			     256))
    return (1);

  return (0);
}


void
init_direct(list_t *arglist,
	    dstr_t *filelist,
	    jobparams_t *job)
{
  char tmp [1024];
  listitem_t *i;
  char user_default_path [PATH_MAX];

  strlcpy(user_default_path, getenv("HOME"), 256);
  strlcat(user_default_path, "/.foomatic/", 256);

  // Which files do we want to print?
  for (i = arglist->first; i; i = i->next)
  {
    strncpy_omit(tmp, (char*)i->data, 1024, omit_shellescapes);
    dstrcatf(filelist, "%s ", tmp);
  }

  if (job->ppdfile[0] == '\0')
  {
    if (job->printer[0] == '\0')
    {
      // No printer definition file selected, check whether we have a
      // default printer defined
      find_default_printer(user_default_path, job);
    }

    // Neither in a config file nor on the command line a printer was selected
    if (!job->printer[0])
    {
      _log("No printer definition (option \"-P <name>\") specified!\n");
      exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
    }

    // Search for the PPD file
    if (!find_ppdfile(user_default_path, job))
    {
      _log("There is no readable PPD file for the printer %s, is it configured?\n",
	   job->printer);
      exit(EXIT_PRNERR_NORETRY_BAD_SETTINGS);
    }
  }
}
