/* Nessus
 * Copyright (C) 1999, 2000 Renaud Deraison
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * In addition, as a special exception, Renaud Deraison
 * gives permission to link the code of this program with any
 * version of the OpenSSL library which is distributed under a
 * license identical to that listed in the included COPYING.OpenSSL
 * file, and distribute linked combinations including the two.
 * You must obey the GNU General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * this file, you may extend this exception to your version of the
 * file, but you are not obligated to do so.  If you do not wish to
 * do so, delete this exception statement from your version.
 */

#include <includes.h>

#ifdef USE_GTK
#include <gtk/gtk.h>
#include "nessus_plugin.h"
#include "context.h"
#include "comm.h"
#include "prefs_dialog_plugins_prefs.h"
#include "listnotebook.h"

#include "nessus_i18n.h"


static GtkWidget * pprefs_add_notebook_page(struct arglist *, char *, int);
static void pprefs_add_entry(struct arglist *, struct arglist *, char *, GtkWidget*);
static void pprefs_add_password(struct arglist *, struct arglist *, char *, GtkWidget*);
static void pprefs_add_file(struct arglist *, struct arglist *, char *, GtkWidget*);
static void pprefs_add_checkbox(struct arglist *, struct arglist *, char *, GtkWidget*);
static void pprefs_add_radio(struct arglist *, struct arglist *, char *, GtkWidget*);



static void
create_plugin_prefs_containers(ctrls)
  struct arglist *ctrls;
{
  GtkWidget *listnotebook;
  GtkWidget *cred_s_window, *cred_vbox;

  listnotebook = listnotebook_new(FALSE, TRUE);
  gtk_container_set_border_width(GTK_CONTAINER(listnotebook), 10);

  cred_s_window = gtk_scrolled_window_new(NULL, NULL);
  gtk_container_border_width(GTK_CONTAINER(cred_s_window), 10);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(cred_s_window),
      GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  cred_vbox = gtk_vbox_new(FALSE, FALSE);
  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(cred_s_window),
      cred_vbox);
  gtk_widget_show(cred_vbox);

  /* On the first call we have to add the values, on subsequent calls we
   * just set them */
  if (arg_get_value(ctrls, "PLUGIN_PREFS") != NULL)
  {
    arg_set_value(ctrls, "PLUGIN_PREFS", -1, listnotebook);
    arg_set_value(ctrls, "SCROLLED_WINDOW_CREDENTIALS", -1, cred_s_window);
    arg_set_value(ctrls, "VBOX_CREDENTIALS", -1, cred_vbox);
  }
  else
  {
    arg_add_value(ctrls, "PLUGIN_PREFS", ARG_PTR, -1, listnotebook);
    arg_add_value(ctrls, "VBOX_CREDENTIALS", ARG_PTR, -1, cred_vbox);
    arg_add_value(ctrls, "SCROLLED_WINDOW_CREDENTIALS", ARG_PTR, -1,
	cred_s_window);
  }
}


struct arglist *
prefs_dialog_plugins_prefs()
{
  struct arglist *ctrls = emalloc(sizeof(struct arglist));
  GtkWidget *frame, * cred_frame;
  GtkWidget *plugin_prefs, * cred_s_window;

  frame = gtk_frame_new(_("Advanced Plugins preferences"));
  gtk_container_border_width(GTK_CONTAINER(frame), 10);
  gtk_widget_show(frame);
  arg_add_value(ctrls, "FRAME", ARG_PTR, -1, frame);


  cred_frame = gtk_frame_new(_("Credentials"));
  gtk_container_border_width(GTK_CONTAINER(cred_frame), 10);
  gtk_widget_show(cred_frame);
  arg_add_value(ctrls, "FRAME_CREDENTIALS", ARG_PTR, -1, cred_frame);

  create_plugin_prefs_containers(ctrls);

  plugin_prefs = arg_get_value(ctrls, "PLUGIN_PREFS");
  gtk_container_add(GTK_CONTAINER(frame), plugin_prefs);
  gtk_widget_show(plugin_prefs);
  cred_s_window = arg_get_value(ctrls, "SCROLLED_WINDOW_CREDENTIALS");
  gtk_container_add(GTK_CONTAINER(cred_frame), cred_s_window);
  gtk_widget_show(cred_s_window);

  return (ctrls);
}

static int is_credentials(char * plugin_name, char * preference_name)
{
 if ( strcmp(plugin_name, "SSH settings") == 0 )
        return 1;
 else if ( strcmp(plugin_name, "Kerberos configuration") == 0 )
        return 1;
 else if ( strcmp(plugin_name, "Login configurations") == 0 ) 
        {
         if ( preference_name == NULL ) return 0;
         if ( strncmp(preference_name, "SMB", 3) == 0 )
                return 1;
        }
 return 0;
}


void
prefs_dialog_plugins_prefs_fill(context, ctrls, plugins)
  struct context *context;
  struct arglist *ctrls;
  struct nessus_plugin *plugins;
{
  struct arglist *pprefs = arg_get_value(context->prefs, "PLUGINS_PREFS");
  struct nessus_plugin *plugs = plugins;
  int credentials;
  GtkWidget *notebook_vbox = NULL;

  while(plugs != NULL )
  {
    struct arglist *prefs;

    if((prefs = plugs->plugin_prefs) != NULL )
    {
      credentials = is_credentials(plugs->name, NULL);
      if ( credentials == 0 )
	notebook_vbox = pprefs_add_notebook_page(ctrls, plugs->name, 0);

      while(prefs && prefs->next)
      {
	char *type, *value;
	GtkWidget *vbox;

	credentials = is_credentials(plugs->name, prefs->name);
	if (credentials == 0)
	  vbox = notebook_vbox;
	else
	  vbox = arg_get_value(ctrls, "VBOX_CREDENTIALS");

	type = arg_get_value(prefs->value, "type");
	value = arg_get_value(prefs->value, "value");
	if(type)
	{
	  if(!strcmp(type, PREF_ENTRY))
	    pprefs_add_entry(pprefs, prefs, value, vbox);
	  else if(!strcmp(type, PREF_PASSWORD))
	    pprefs_add_password(pprefs, prefs, value, vbox);
	  else if(!strcmp(type, PREF_RADIO))
	    pprefs_add_radio(pprefs, prefs, value, vbox);
	  else if(!strcmp(type, PREF_CHECKBOX))
	    pprefs_add_checkbox(pprefs, prefs, value, vbox);
	  else if(!strcmp(type, PREF_FILE))
	    pprefs_add_file(pprefs, prefs, value, vbox);
	}
	prefs = prefs->next;
      }
    }
    plugs = plugs->next;
  }

  listnotebook_select_page(arg_get_value(ctrls, "PLUGIN_PREFS"), 0);
}

/*
 * Clean up the plugin preferences and plugin
 * preferences widgets
 */
void
prefs_plugins_reset(ctrls, plugins)
  struct arglist *ctrls;
  struct nessus_plugin *plugins;
{
  struct arglist *prefs;

  while(plugins != NULL )
  {
    prefs =  plugins->plugin_prefs;
    if(prefs != NULL )
      while(prefs && prefs->next)
      {
	struct arglist *v;

	/*
	 * We keep the first three fields and destroy the others
	 */
	v = prefs->value;	/* value */
	v = v->next;		/* type */
	v = v->next;		/* fullname */
	arg_free(v->next);
	v->next = emalloc(sizeof(struct arglist));
	prefs = prefs->next;
      }
    plugins = plugins->next;
  }
}

/*
 * Redraw the plugins preferences
 */
void
prefs_plugins_prefs_redraw(context, ctrls)
  struct context *context;
  struct arglist *ctrls;
{
  GtkWidget *frame, *cred_frame;
  GtkWidget *plugin_prefs, *cred_s_window;
  GtkWidget *cred_vbox;

  frame = arg_get_value(ctrls, "FRAME");
  plugin_prefs = arg_get_value(ctrls, "PLUGIN_PREFS");
  cred_frame = arg_get_value(ctrls, "FRAME_CREDENTIALS");
  cred_s_window = arg_get_value(ctrls, "SCROLLED_WINDOW_CREDENTIALS");
  cred_vbox = arg_get_value(ctrls, "VBOX_CREDENTIALS");

  gtk_widget_hide(plugin_prefs);
  gtk_widget_hide(cred_s_window);
  gtk_container_remove(GTK_CONTAINER(frame), plugin_prefs);
  gtk_container_remove(GTK_CONTAINER(cred_frame), cred_s_window);

  plugin_prefs = context->plugin_prefs_widget;
  cred_s_window = context->plugin_prefs_cred_swindow;
  cred_vbox = context->plugin_prefs_cred_vbox;
  if(plugin_prefs != NULL && cred_s_window != NULL )
  {
    arg_set_value(ctrls, "PLUGIN_PREFS", -1, plugin_prefs);
    arg_set_value(ctrls, "SCROLLED_WINDOW_CREDENTIALS", -1, cred_s_window);
    arg_set_value(ctrls, "VBOX_CREDENTIALS", -1, cred_vbox);
  }
  else
  {
    create_plugin_prefs_containers(ctrls);
    plugin_prefs = arg_get_value(ctrls, "PLUGIN_PREFS");
    cred_s_window = arg_get_value(ctrls, "SCROLLED_WINDOW_CREDENTIALS");
    cred_vbox = arg_get_value(ctrls, "VBOX_CREDENTIALS");

    if((context->plugins && context->plugins->next)
	|| (context->scanners && context->scanners->next))
    {
      g_object_ref(plugin_prefs);
      g_object_ref(cred_s_window);
      context->plugin_prefs_widget = plugin_prefs;
      context->plugin_prefs_cred_swindow = cred_s_window;
      context->plugin_prefs_cred_vbox = cred_vbox;

      prefs_plugins_reset(ctrls, context->scanners);
      prefs_plugins_reset(ctrls, context->plugins);
      prefs_dialog_plugins_prefs_fill(context, ctrls, context->scanners);
      prefs_dialog_plugins_prefs_fill(context, ctrls, context->plugins);
    }
  }
  gtk_container_add(GTK_CONTAINER(frame), plugin_prefs);
  gtk_widget_show(plugin_prefs);
  gtk_container_add(GTK_CONTAINER(cred_frame), cred_s_window);
  gtk_widget_show(cred_s_window);
}


static GtkWidget *
pprefs_add_notebook_page(ctrls, name, credentials)
  struct arglist *ctrls;
  char *name;
  int credentials;
{
  GtkWidget *vbox = NULL;

  if (credentials == 0)
  {
    GtkWidget *listnotebook = arg_get_value(ctrls, "PLUGIN_PREFS");
    GtkWidget *s_window = gtk_scrolled_window_new(NULL, NULL);

    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(s_window),
	GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
    gtk_widget_show(s_window);
    vbox = gtk_vbox_new(FALSE, FALSE);
    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(s_window), vbox);
    gtk_widget_show(vbox);

    listnotebook_add_page(listnotebook, s_window, name, NULL);
  }

  return vbox;
}


static int
file_dialog_hide(GtkWidget * filew, GtkWidget * nul)
{
  gtk_widget_hide(filew);
  gtk_widget_destroy(filew);
  return 0;
}


static int
file_selected(GtkWidget * nul, GtkWidget * filew)
{
  struct arglist *c;
  GtkWidget *entry;
  char *fname =
      (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(filew));
  gtk_widget_hide(filew);
  c = gtk_object_get_data(GTK_OBJECT(filew), "data");
  entry = arg_get_value(c, "ENTRY");
  gtk_entry_set_text(GTK_ENTRY(entry), fname);
  return 0;
}
static int
select_file(GtkWidget * b, struct arglist *ctrls)
{

  GtkWidget *filew = gtk_file_selection_new(_("Select file"));

  gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filew)->ok_button),
      "clicked", (GtkSignalFunc) file_selected, filew);
  gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(filew)->
	  cancel_button), "clicked", GTK_SIGNAL_FUNC(file_dialog_hide),
      GTK_OBJECT(filew));
  gtk_object_set_data(GTK_OBJECT(filew), "data", ctrls);
  gtk_widget_show(filew);
  return 0;
}


static void
pprefs_add_entry(pprefs, pref, value, vbox)
  struct arglist *pprefs;
  struct arglist *pref;
  char *value;
  GtkWidget *vbox;
{
  GtkWidget *entry, *text, *box;
  char *name = pref->name;
  char *fullname = arg_get_value(pref->value, "fullname");

  if(pprefs)
  {
    int type;

    if((type = arg_get_type(pprefs, fullname)) >= 0)
    {
      value = arg_get_value(pprefs, fullname);
      if(type == ARG_INT)
      {
	if(value)
	  value = strdup("yes");
	else
	  value = strdup("no");
      }
    }
  }
  box = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
  gtk_widget_show(box);

  text = gtk_label_new(name);
  gtk_box_pack_start(GTK_BOX(box), text, TRUE, TRUE, 5);
  gtk_widget_show(text);

  entry = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(entry), value);
  gtk_box_pack_end(GTK_BOX(box), entry, TRUE, TRUE, 5);
  gtk_widget_show(entry);
  arg_add_value(pref->value, "ENTRY", ARG_PTR, -1, entry);
}


static void
pprefs_add_password(pprefs, pref, value, vbox)
  struct arglist *pprefs;
  struct arglist *pref;
  char *value;
  GtkWidget *vbox;
{
  GtkWidget *entry, *text, *box;
  char *name = pref->name;
  char *fullname = arg_get_value(pref->value, "fullname");

  if(pprefs)
  {
    int type;

    if((type = arg_get_type(pprefs, fullname)) >= 0)
    {
      value = arg_get_value(pprefs, fullname);
      if(type == ARG_INT)
      {
	if(value)
	  value = strdup("yes");
	else
	  value = strdup("no");
      }
    }
  }
  box = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
  gtk_widget_show(box);

  text = gtk_label_new(name);
  gtk_box_pack_start(GTK_BOX(box), text, TRUE, TRUE, 5);
  gtk_widget_show(text);

  entry = gtk_entry_new();
  gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
  gtk_entry_set_text(GTK_ENTRY(entry), value);
  gtk_box_pack_end(GTK_BOX(box), entry, TRUE, TRUE, 5);
  gtk_widget_show(entry);
  arg_add_value(pref->value, "ENTRY", ARG_PTR, -1, entry);
}

static void
pprefs_add_file(pprefs, pref, value, vbox)
  struct arglist *pprefs;
  struct arglist *pref;
  char *value;
  GtkWidget *vbox;
{
  GtkWidget *entry, *text, *box;
  GtkWidget *hbox, *button;
  char *name = pref->name;
  char *fullname = arg_get_value(pref->value, "fullname");

  if(pprefs)
  {
    int type;

    if((type = arg_get_type(pprefs, fullname)) >= 0)
    {
      value = arg_get_value(pprefs, fullname);
      if(type == ARG_INT)
      {
	if(value)
	  value = strdup("yes");
	else
	  value = strdup("no");
      }
    }
  }
  box = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
  gtk_widget_show(box);

  text = gtk_label_new(name);
  gtk_box_pack_start(GTK_BOX(box), text, TRUE, TRUE, 5);
  gtk_widget_show(text);

  hbox = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_end(GTK_BOX(box), hbox, TRUE, TRUE, 5);
  gtk_widget_show(hbox);

  entry = gtk_entry_new();
  gtk_entry_set_text(GTK_ENTRY(entry), value);
  gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 5);
  gtk_widget_show(entry);
  arg_add_value(pref->value, "ENTRY", ARG_PTR, -1, entry);

  button = gtk_button_new_with_label(_("Select..."));
  gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 5);
  gtk_signal_connect(GTK_OBJECT(button), "clicked",
      (GtkSignalFunc) select_file, pref->value);

  gtk_widget_show(button);
}



static void
pprefs_add_radio(pprefs, pref, value, vbox)
  struct arglist *pprefs;
  struct arglist *pref;
  char *value;
  GtkWidget *vbox;
{
  GtkWidget *orig;
  GtkWidget *button, *first_button;
  GtkWidget *label;
  char *t;
  GSList *list = NULL;
  char *fullname = arg_get_value(pref->value, "fullname");
  char *def = NULL;

  if(pprefs)
  {
    int type;

    if((type = arg_get_type(pprefs, fullname)) >= 0)
    {
      def = arg_get_value(pprefs, fullname);
      if(type == ARG_INT)
      {
	if(def)
	  def = strdup("yes");
	else
	  def = strdup("no");
      }
    }
  }


  label = gtk_label_new(pref->name);
  gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
  gtk_widget_show(label);

  t = strchr(value, ';');
  if(t)
    t[0] = '\0';
  first_button = orig = gtk_radio_button_new_with_label(NULL, value);
  gtk_box_pack_start(GTK_BOX(vbox), orig, FALSE, FALSE, 5);
  gtk_object_set_data(GTK_OBJECT(orig), "name", value);
  gtk_widget_show(orig);
  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(orig), TRUE);
  value = t + sizeof(char);
  if(t)
    while(value)
    {
      if((t = strchr(value, ';')))
	t[0] = '\0';
      button =
	  gtk_radio_button_new_with_label(gtk_radio_button_group
	  (GTK_RADIO_BUTTON(orig)), value);
      gtk_object_set_data(GTK_OBJECT(button), "name", value);
      if(def && !strcmp(def, value))
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
      gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 5);
      gtk_widget_show(button);
      if(t)
	value = t + sizeof(char);
      else
	value = NULL;
    }
  list = gtk_radio_button_group(GTK_RADIO_BUTTON(orig));

  arg_add_value(pref->value, "RADIOBUTTONS", ARG_PTR, -1, list);
}

static void
pprefs_add_checkbox(pprefs, pref, value, vbox)
  struct arglist *pprefs;
  struct arglist *pref;
  char *value;
  GtkWidget *vbox;
{
  GtkWidget *box;
  GtkWidget *button;
  char *name = pref->name;
  char *def = NULL;
  char *fullname = arg_get_value(pref->value, "fullname");

  if(pprefs)
  {
    int type;

    if((type = arg_get_type(pprefs, fullname)) >= 0)
    {
      def = arg_get_value(pprefs, fullname);
      if(type == ARG_INT)
      {
	if(def)
	  def = strdup("yes");
	else
	  def = strdup("no");
      }
    }
  }
  box = gtk_hbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 5);
  gtk_widget_show(box);

  button = gtk_check_button_new_with_label(estrdup(name));
  gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 5);
  gtk_widget_show(button);
  if(def)
  {
    if(!strcmp(def, "yes"))
      gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE);
    else
      gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), FALSE);
  }
  else
    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), !strcmp(value, "yes"));
  arg_add_value(pref->value, "CHECKBOX", ARG_PTR, -1, button);
}
#endif
