/* Nessus
 * Copyright (C) 1998 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 "../preferences.h"
#include "../plugin_infos.h"
#include "error_dlg.h"
#include "prefs_dialog_scan_opt.h"
#include "readonly.h"
#include "globals.h"

#include "../nessus_i18n.h"

/** Column IDs of scanner TreeView Model. */
enum {
  COL_NAME,
  COL_PLUGIN,
  NUM_COLS
};

/**
 * @brief Set the "active" property of the toggle cell renderer.
 */
static void
active_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
                  GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
{
  struct nessus_plugin *plugin;
  gboolean is_active = FALSE;
  GObject *tree_view = G_OBJECT(data);

  gtk_tree_model_get(model, iter, COL_PLUGIN, &plugin, -1);
  is_active = plugin->enabled == 0 ? 0:1;

  g_object_set(G_OBJECT(cell), "active", is_active, NULL);

  /* the cell is activatable if the tree is not in read-only mode */
  g_object_set(G_OBJECT(cell), "activatable",
      (gboolean)!GPOINTER_TO_INT(g_object_get_data(tree_view, "read-only")),
      NULL);
}

/**
 * @brief Toggle the active/launch flag of a plugin.
 *
 * This function is called when the checkbox in the scanners
 * tree view widget has been toggled by the user.
 *
 * This function expects the tree view in the data parameter.  The
 * path_str must describe the path in the model of that tree view.
 */
static void
prefs_scanner_list_toggle_callback (GtkCellRendererToggle *cell, gchar *path_str,
                                    gpointer data)
{
  GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(data));
  GtkTreeIter iter;
  struct nessus_plugin * plugin;

  gtk_tree_model_get_iter_from_string(model, &iter, path_str);
  gtk_tree_model_get(model, &iter, COL_PLUGIN, &plugin, -1);
  plugin->enabled = ! plugin->enabled;
}

/**
 * @brief Pop up the plugin info dialog.
 * 
 * Called when the user double clicks on a row of the scanner tree view.
 */
static void
scanners_row_activated (GtkTreeView *treeview, GtkTreePath *path,
                        GtkTreeViewColumn *column, gpointer user_data)
{
  GtkTreeModel * model = gtk_tree_view_get_model(treeview);
  GtkTreeIter iter;
  char * plugin_name;

  gtk_tree_model_get_iter(model, &iter, path);
  gtk_tree_model_get(model, &iter, COL_NAME, &plugin_name, -1);

  plugin_info_window_setup(Context->scanners, plugin_name);
}

struct arglist *
prefs_dialog_scan_opt (struct context *context)
{
 GtkWidget * frame;
 GtkWidget * table;
 GtkWidget * ping_hosts;
 GtkWidget * optimize_test;
 GtkWidget * safe_checks;
 GtkWidget * use_mac_addr;
 GtkWidget * reverse_lookup;
 GtkWidget * box;
 GtkWidget * label;
 GtkWidget * port_range;
 GtkWidget * unscanned_as_closed;
 GtkWidget * entry;
 GtkWidget * scanners_window;
 GtkListStore      * store;
 GtkWidget         * tree;
 GtkCellRenderer   * renderer;
 GtkTreeViewColumn * column;

 struct arglist * ctrls = emalloc(sizeof(struct arglist));
 
 frame = gtk_frame_new(_("General scan options"));
 gtk_container_border_width(GTK_CONTAINER(frame), 10);
 arg_add_value(ctrls, "FRAME", ARG_PTR, -1, frame);
 read_only_set_recurse(frame);
 
 gtk_widget_show(frame);
 
 
 box = gtk_vbox_new(FALSE, 5);
 read_only_set_recurse(box);
 
 gtk_container_add(GTK_CONTAINER(frame), box);
 gtk_container_border_width(GTK_CONTAINER(box), 10);
 gtk_widget_show(box);
 
 
 ping_hosts = gtk_check_button_new_with_label(_("Determine if hosts are alive before testing them"));
 arg_add_value(ctrls, "PING_HOSTS", ARG_PTR, -1, ping_hosts);
 /*gtk_box_pack_start(GTK_BOX(box), ping_hosts, FALSE, FALSE, 0);
 gtk_widget_show(ping_hosts);*/
 

 
 table = gtk_table_new(5, 2, FALSE);
 gtk_box_pack_start(GTK_BOX(box), table, FALSE, FALSE, 0);
 gtk_widget_show(table);
 

 gtk_table_set_row_spacing(GTK_TABLE(table), 0, 10);
 label = gtk_label_new(_("Port range:"));
 gtk_misc_set_alignment((GtkMisc *)label, 0, 1);
 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0,1);
 gtk_widget_show(label);
 
 port_range = gtk_entry_new();
 gtk_table_attach_defaults(GTK_TABLE(table), port_range, 1,2,0,1);
 gtk_widget_show(port_range);
 arg_add_value(ctrls, "PORT_RANGE", ARG_PTR, -1, port_range);
 
 unscanned_as_closed = gtk_check_button_new_with_label(_("Consider unscanned ports as closed"));
 arg_add_value(ctrls, "UNSCANNED_CLOSED", ARG_PTR, -1, unscanned_as_closed);
 gtk_table_attach_defaults(GTK_TABLE(table), unscanned_as_closed, 0,2,1,2);
 gtk_widget_show(unscanned_as_closed);
 
 
 
 
 
 gtk_table_set_row_spacing(GTK_TABLE(table), 1, 10);
 label = gtk_label_new(_("Hosts to test concurrently:"));
 gtk_misc_set_alignment((GtkMisc *)label, 0, 1);
 gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,2,3);
 gtk_widget_show(label);
 
 entry = gtk_spin_button_new_with_range (1.0f, 1000.0f, 1.0f);
 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1,2,2,3);
 gtk_widget_show(entry);
 arg_add_value(ctrls, "MAX_HOSTS", ARG_PTR, -1, entry);
 
 gtk_table_set_row_spacing(GTK_TABLE(table), 2, 10);
 label = gtk_label_new(_("Checks to perform concurrently:"));
 gtk_misc_set_alignment((GtkMisc *)label, 0, 1);
 gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,3,4);
 gtk_widget_show(label);
 
 entry = gtk_spin_button_new_with_range (1.0f, 1000.0f, 1.0f);
 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1,2,3,4);
 gtk_widget_show(entry);
 arg_add_value(ctrls, "MAX_CHECKS", ARG_PTR, -1, entry);
 
 

 label = gtk_label_new(_("Path to the CGIs:"));
 gtk_misc_set_alignment((GtkMisc *)label, 0, 1);
 gtk_table_attach_defaults(GTK_TABLE(table), label, 0,1,4,5);
 gtk_widget_show(label);
 
 entry = gtk_entry_new();
 gtk_table_attach_defaults(GTK_TABLE(table), entry, 1,2,4,5);
 gtk_widget_show(entry);
 arg_add_value(ctrls, "CGI_PATH", ARG_PTR, -1, entry);
 
 
 reverse_lookup = gtk_check_button_new_with_label(_("Do a reverse lookup on the IP before testing it"));
 arg_add_value(ctrls, "REVERSE_LOOKUP", ARG_PTR, -1, reverse_lookup);
 gtk_box_pack_start(GTK_BOX(box), reverse_lookup, FALSE, FALSE, 0);
 gtk_widget_show(reverse_lookup);
 
 optimize_test = gtk_check_button_new_with_label(_("Optimize the test"));
 arg_add_value(ctrls, "OPTIMIZE_TEST", ARG_PTR, -1, optimize_test);
 gtk_box_pack_start(GTK_BOX(box), optimize_test, FALSE, FALSE, 0);
 gtk_widget_show(optimize_test);
 
 
 safe_checks = gtk_check_button_new_with_label(_("Safe checks"));
 arg_add_value(ctrls, "SAFE_CHECKS", ARG_PTR, -1, safe_checks);
 gtk_box_pack_start(GTK_BOX(box), safe_checks, FALSE, FALSE, 0);
 gtk_widget_show(safe_checks);
 
 use_mac_addr = gtk_check_button_new_with_label(_("Designate hosts by their MAC address"));
 arg_add_value(ctrls, "USE_MAC_ADDR", ARG_PTR, -1, use_mac_addr);
 gtk_box_pack_start(GTK_BOX(box), use_mac_addr, FALSE, FALSE, 0);
 gtk_widget_show(use_mac_addr);
 
 label = gtk_label_new(_("Port scanner:"));
 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
 gtk_misc_set_alignment((GtkMisc *)label, 0, 1);
 gtk_widget_show(label);

  store = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);

  arg_add_value(ctrls, "SCANNERS_LIST", ARG_PTR, -1, store);

  tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));

  renderer = gtk_cell_renderer_text_new();
  column = gtk_tree_view_column_new_with_attributes (_("Name"),
    renderer, "text", COL_NAME, NULL);
  gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
  g_signal_connect(G_OBJECT(tree), "row-activated",
    G_CALLBACK(scanners_row_activated), NULL);

  renderer = gtk_cell_renderer_toggle_new();
  g_signal_connect(renderer, "toggled",
    G_CALLBACK(prefs_scanner_list_toggle_callback), tree);
  column = gtk_tree_view_column_new_with_attributes(_("Active"), renderer,
    NULL);
  gtk_tree_view_column_set_cell_data_func(column, renderer, active_data_func,
    tree, NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
  g_object_set_data(G_OBJECT(column), "colnum", GINT_TO_POINTER(1));
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
  gtk_widget_show(tree);

  fill_scanner_list(context, store);

  scanners_window = gtk_scrolled_window_new(NULL,NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scanners_window),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_box_pack_end(GTK_BOX(box), scanners_window, TRUE, TRUE, 0);
  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scanners_window),
    tree);
  gtk_widget_show(scanners_window);

 return(ctrls);
}

/**
 * @brief Clean the store and then fill it with the Scanners of the given
 * @brief context.
 */
void
fill_scanner_list (struct context *context, GtkListStore *store)
{
  GtkTreeIter   iter;
  struct nessus_plugin * scans = context->scanners;

  gtk_list_store_clear(store);

  while (scans != NULL )
  {
    gtk_list_store_append(store, &iter);  /* Acquire an iterator */
    gtk_list_store_set(store, &iter,
      COL_NAME, scans->name,
      COL_PLUGIN, scans,
      -1);
    scans = scans->next;
  }
}

void
prefs_dialog_scan_opt_readonly (struct arglist * ctrls, gboolean readonly)
{
  read_only_set_read_only(GTK_WIDGET(arg_get_value(ctrls, "FRAME")),
      readonly);
}

#endif /* USE_GTK */
