/*
 * GkDebconf -- Help to configure packages with debconf
 * Copyleft (C) 2003 Agney Lopes Roth Ferraz <agney@users.sourceforge.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>

#include <gtk/gtk.h>

#include "../config.h"

#include "defines.h"
#include "debconf.h"
#include "interface.h"
#include "files.h"
#include "config.h"

#define TERMCMD "/usr/bin/x-terminal-emulator"
#define GKTERM "/bin/gkdebconf-term"
#define DEBCONFCMD "/usr/sbin/dpkg-reconfigure"
#define CDEBCONFCMD "/usr/lib/cdebconf/dpkg-reconfigure"
#define SUDO "/usr/bin/sudo"
#define ENV "/usr/bin/env"
#define ASKPASS "/usr/bin/ssh-askpass"

extern GtkWidget *main_window;
extern GtkWidget *splash_label;
extern gint errno;
static gchar *debconf_engine = NULL; // What debconf engine is installed (cdebconf | debconf)
static gchar *debconfcmd     = NULL; // Which dpkg-reconfigure (from debconf or cdebconf)

/* stores information about available front ends */
// Web frontend can work if any of web browsers is installed (www-browser virtual package)

// debconf frontends
dfrontend dfes[] = {
                     {"gnome", FALSE, "libgtk3-perl", NULL},
                     {"kde", FALSE, "debconf-kde-helper", NULL},
                     {"dialog", TRUE, "dialog", "whiptail"},
                     {"readline", TRUE, "libterm-readline-gnu-perl", NULL},
                     {"editor", TRUE, NULL, NULL},
                     {"web", FALSE, NULL, NULL}, // virtual package "www-browser"
                     {NULL, FALSE}
                   };
// cdebconf frontends
dfrontend cdfes[] = {
                      {"gtk", FALSE, NULL, NULL},
                      {"newt", TRUE, NULL, NULL},
                      {"text", TRUE, NULL, NULL},
                      {NULL, FALSE}
                    };
gchar *frontend; // Last frontend used

/**
 * file_exists:
 *
 * @file: filename to check.
 *
 * Check if the file exits on the system.
 *
 * Returns 0 if file exits. Anything else otherwise.
 */
void get_debconf()
{
  gchar *query[] = { "/usr/bin/dpkg-query", "--status", "cdebconf", NULL };
  gchar *msg;
  gint ret;

  msg = g_strdup_printf (_("Checking whether\n%s\nis installed"),
                         "cdebconf");
  gtk_label_set_text (GTK_LABEL(splash_label), msg);
  while (gtk_events_pending())
    gtk_main_iteration();
  g_free (msg);
  g_spawn_sync (NULL, query, NULL,
                G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
                NULL, NULL, NULL, NULL, &ret, NULL);
  if (ret == 0)
    {
      debconf_engine = g_strdup_printf("cdebconf");
      debconfcmd = g_strdup_printf(CDEBCONFCMD);
      return;
    }
  else
    {
      msg = g_strdup_printf (_("Using debconf"));
      gtk_label_set_text (GTK_LABEL(splash_label), msg);
      while (gtk_events_pending())
        gtk_main_iteration();
      g_free (msg);
      debconf_engine = g_strdup_printf("debconf");
      debconfcmd = g_strdup_printf(DEBCONFCMD);
      return;
    }
}

/**
 * check_missing:
 *
 * @fe: Frontend name.
 *
 * Check if the package is installed on the system.
 *
        * Returns 0 if package is installed. Anything else otherwise.
 */

int check_missing (gchar *fe)
{
  gchar *msg;
  gint i;
  gint ret ;


  for (i = 0 ; strcmp (dfes[i].name, fe) ; i++)
    ;

  if (dfes[i].dep1 == NULL)
    return 0;

  msg = g_strdup_printf (_("Checking whether\n%s\nis installed"),
                         dfes[i].dep1);
  gtk_label_set_text (GTK_LABEL(splash_label), msg);
  while (gtk_events_pending())
    gtk_main_iteration();
  g_free (msg);
  gchar *query[] = { "/usr/bin/dpkg-query", "--status", dfes[i].dep1, NULL };
  g_spawn_sync (NULL, query, NULL,
                G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
                NULL, NULL, NULL, NULL, &ret, NULL);
  if ( (ret != 0) && (dfes[i].dep2 != NULL) )
    {
      msg = g_strdup_printf (_("Checking whether\n%s\nis installed"),
                             dfes[i].dep2);
      gtk_label_set_text (GTK_LABEL(splash_label), msg);
      while (gtk_events_pending())
        gtk_main_iteration();
      g_free (msg);
      gchar *query[] = { "/usr/bin/dpkg-query", "--status",
                         dfes[i].dep2, NULL };
      g_spawn_sync (NULL, query, NULL,
                    G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
                    NULL, NULL, NULL, NULL, &ret, NULL);
    }

  return ret;
}


/**
 * get_frontends:
 *
 * @menu: Widget that contains menubar where frontends will be added.
 *
 *  Fills the Options menu with the available frontends
 */

void
get_frontends (GtkWidget *menu)
{
  GSList *group = NULL;
  GtkWidget *item;
  GtkWidget *opts_menu;
  gchar *message, *tooltip;
  gchar *fe, *remember_fe, *str_item, *libgnome_alert;
  gint i;


  frontend = NULL;
  gboolean missing_active = FALSE;

  remember_fe = read_config ("remember-frontend");
  if (!strcmp (remember_fe, "yes"))
    {
      fe = read_config ("last-frontend");
      if (strcmp (fe, "none"))
        frontend = g_ascii_strdown (fe, -1);
      g_free(fe);
    }

  /* first item is set active automaticaly
  * if no other item made active
  */

  if (!frontend)
    frontend = g_ascii_strdown (dfes[0].name, -1);

  g_free (remember_fe);
  get_debconf();
  if (strcmp(debconf_engine, "debconf") == 0)
    {
      for (i = 0 ; dfes[i].name != NULL ; i++)
        {
          str_item = g_strconcat(dfes[i].name, _(" frontend"), NULL);
          item = gtk_radio_menu_item_new_with_label (group, str_item);
          group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
          gtk_widget_show (item);
          opts_menu = g_object_get_data (G_OBJECT (menu), "frontends");
          gtk_menu_shell_append (GTK_MENU_SHELL (opts_menu), item);
          tooltip = g_strconcat (_("Select "), str_item, NULL);
          gtk_widget_set_tooltip_text (item, tooltip);
          g_free (tooltip);
          g_free(str_item);

          if (check_missing(dfes[i].name) == 0)
            {
              g_signal_connect ((gpointer) item, "activate",
                                G_CALLBACK (fe_select), (gpointer) g_strdup(dfes[i].name));

              if (!strcmp(dfes[i].name, frontend) || missing_active)
                {
                  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
                  missing_active = FALSE;
                }
            }
          else
            {
              if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
                missing_active = TRUE;

              /* If gnome or kde frontend not found displays warning, because
                 gkdebconf is graphical and should be used with a graphical frontend
              */
              libgnome_alert = read_config ("libgnome-alert");
              if ((g_ascii_strcasecmp(dfes[i].name, "gnome") == 0) && (strcmp(libgnome_alert,"no") != 0))
                {
                  message = g_strdup_printf (_("You should install '%s' package if you need\nuser-friendly configuration tool."),
                                             dfes[i].dep1);
                  gk_dialog_for_gconf ("libgnome-alert", message);

                }
              gtk_widget_set_state_flags (item, GTK_STATE_FLAG_INSENSITIVE,
                                          FALSE);
            }
        }
    }
  else
    {
      for (i = 0 ; cdfes[i].name != NULL ; i++)
        {
          str_item = g_strconcat(cdfes[i].name, _(" frontend"), NULL);
          item = gtk_radio_menu_item_new_with_label (group, str_item);
          group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
          gtk_widget_show (item);
          opts_menu = g_object_get_data (G_OBJECT (menu), "frontends");
          gtk_menu_shell_append (GTK_MENU_SHELL (opts_menu), item);
          tooltip = g_strconcat (_("Select "), str_item, NULL);
          gtk_widget_set_tooltip_text (item, tooltip);
          g_free (tooltip);
          g_free(str_item);

          g_signal_connect ((gpointer) item, "activate",
                            G_CALLBACK (fe_select), (gpointer) g_strdup(cdfes[i].name));

          if (!strcmp(cdfes[i].name, frontend) || missing_active)
            {
              gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
              missing_active = FALSE;
            }
                        libgnome_alert = read_config ("libgnome-alert");
                        if (!missing_active && strcmp(libgnome_alert,"no") &&
                                (g_ascii_strcasecmp(cdfes[i].name, "gtk") == 0))
                                 {
                  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
                  missing_active = FALSE;
                                  frontend = g_ascii_strdown (cdfes[i].name, -1);
                }
        }
    }
}

/**
 * get_frontends:
 *
 * @entry: GTK_ENTRY where frontend is.
 * @user_data: The frontend name.
 *
 *  Mostly a callback to the frontend selection menu items
 */

void
fe_select (GtkMenuItem *entry, gpointer user_data)
{

  strcpy (frontend, user_data);
  write_config ("last-frontend", frontend);

}

/**
 * run_config:
 *
 * @cf: Package name to reconfigure.
 *
 *  Run dpk-reconfigure.
 */

int
run_config (gchar *cf)
{
  gushort need_term = FALSE;
  gushort gk_ask_for_root = FALSE;
  gchar *call_command = NULL;
  gint i, cmdret;
  /*
    hides the main window immediately
  */

  gtk_widget_hide (main_window);

  while (gtk_events_pending())
    gtk_main_iteration();
  if (strcmp(debconf_engine,"debconf") == 0){
    for (i = 0 ; strcmp(frontend, dfes[i].name) ; i++);
    need_term = dfes[i].need_term;
  } else {
    for (i = 0 ; strcmp(frontend, cdfes[i].name) ; i++);
    need_term = cdfes[i].need_term;
  }

  if (getuid() != 0)
    gk_ask_for_root = TRUE;

  if (need_term == TRUE)
    {
      gchar gkterm[256];

      strcpy (gkterm, PREFIX);
      strcat (gkterm, GKTERM);

      call_command = g_strdup_printf ("%s -e %s %s %s",
                                      TERMCMD, gkterm,
                                      frontend, cf);
    }
  else
    {
      if (gk_ask_for_root)
        call_command = g_strdup_printf ("%s SUDO_ASKPASS=%s %s -EA %s -f%s %s",
                                        ENV, ASKPASS, SUDO, debconfcmd, frontend,
                                        cf);
      else
        call_command = g_strdup_printf ("%s -f%s %s",
                                        debconfcmd, frontend,
                                        cf);
    }

  //  printf("Engine=%s\nFrontend=%s\nCalling '%s'\n\n",
  //         debconf_engine, frontend, call_command);
  cmdret = system (call_command);
  gtk_widget_show (main_window);

  if (cmdret != 0)
    {
      gk_dialog (GTK_MESSAGE_ERROR,
                 _("The configuration script returned an\n"
                   "error status."));
    }

  if (call_command)
    g_free (call_command);

  return 0;
}
