/* $Id: prefs_report.c,v 1.1.1.1 2005/09/10 17:36:46 renaud Exp $
 *
 * Copyright (C) 2004 by Intevation GmbH
 * Author(s):
 * Jan-Oliver Wagner <jan@intevation.de> (2004)
 *
 * This program is free software under the GNU GPL (>=v2)
 * Read the file COPYING coming with the software for details.
 *
 * In addition, as a special exception, Intevation GmbH gives
 * permission to link the code of this program with the OpenSSL
 * library (or with modified versions of OpenSSL that use the same
 * license as OpenSSL), 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>

#include <gtk/gtk.h>

#include "preferences.h"
#include "nessus_i18n.h"
#include "report_save.h"
#include "data_mining.h"
#include "xstuff.h"

#include "xpm/computer.xpm"
#include "xpm/network.xpm"
#include "xpm/warning_small.xpm"
#include "xpm/info_small.xpm"
#include "xpm/error_small.xpm"
#include "xpm/nothing.xpm"

#define n(x) (x ? x:"")

static GtkWidget * Lists[4];

typedef void (*func_fill_t)(struct arglist *, GtkWidget*);

/*
 * Our sort functions
 */

static int
cmp_hosts(a, b)
  char * a, * b;
{
  struct in_addr ia, ib;

  if(!a && !b)return 0;

  if(!a)
    return 1;
  if(!b)
    return -1;

  if(inet_aton(a, &ia) == 0)
    return strcmp(a, b);

  if(inet_aton(b, &ib) == 0)
  {
    return strcmp(a, b);
  }

  return -(ntohl(ia.s_addr) - ntohl(ib.s_addr));
}

static int
cmp_vulns(a, b)
  char * a, * b;
{
  int level_a, level_b;

  if(!a) 
    return -1;
  else if(!b)
    return 1;

  if(strstr(a, "Hole"))level_a = 3;
  else if(strstr(a, "Warning"))level_a = 2;
  else if(strstr(a, "Note"))level_a = 1;
  else level_a = 0;

  if(strstr(b, "Hole"))level_b = 3;
  else if(strstr(b, "Warning"))level_b = 2;
  else if(strstr(b, "Note"))level_b = 1;
  else level_b = 0;

  return level_a - level_b; 
}

/*
 * Utilities
 */

static void 
replace_data(obj, key, value)
  GtkObject* obj;
  char * key;
  char * value;
{
  char * old = gtk_object_get_data(obj, key);
  if(old)efree(&old);
  gtk_object_set_data(obj, key, value);
}

/*
 * Converts a multiple subset (with field AND severity) to 
 * a sorted, uniq'ed one.
 *
 * The function name is set to 'x' just to simplify its use 
 * throughout the code
 */
static struct subset *
x(subset)
  struct subset * subset;
{
  cmp_func_t cmps1[] = {cmp_hosts, cmp_vulns};
  cmp_func_t cmps2[] = {cmp_vulns};
  return subset_sort(
      subset_uniq(subset_sort(subset, 0, 1, cmps1), 0), 1, 1, cmps2);
}

/*
 * Initializers
 */

static char **
select_severity_pixmap(severity)
  char * severity;
{
  if(severity)
  {
    if(!strcmp(severity, "Security Note"))return info_small_xpm;
    else if(!strcmp(severity, "Security Warning"))return warning_small_xpm;
    else if(!strcmp(severity, "Security Hole")) return error_small_xpm;
  }
  return nothing_xpm;
} /* select_severity_pixmap */


/*
 * Update the label at the bottom of the report frame with
 * information about when the scan happened.
 */
void
prefs_report_update_timestamp(ctrls)
  struct arglist *ctrls;
{
  GtkWidget *scan_timestamps = arg_get_value(ctrls, "SCAN_TIMESTAMPS");
  int be = (int)arg_get_value(ctrls, "BE");
  char *str;

  if(be < 0)
    str = g_strdup("");
  else
  {
    struct subset *start_subset = query_backend(be,
	"SELECT date FROM timestamps WHERE type = 'scan_start'");
    struct subset *end_subset = query_backend(be,
	"SELECT date FROM timestamps WHERE type = 'scan_end'");
    char *start = NULL, *end = NULL;

    if(subset_size(start_subset))
      start = subset_value(start_subset);
    if(subset_size(end_subset))
      end = subset_value(end_subset);

    if(start && end)
      str = g_strdup_printf(_("Scan took place from %s to %s"), start, end);
    else if(start)
      str = g_strdup_printf(_("Scan started on %s"), start);
    else if(end)
      str = g_strdup_printf(_("Scan finished on %s"), end);
    else
      str = g_strdup_printf(_("Time of scan not available."));

    subset_free(start_subset);
    subset_free(end_subset);
  }
  gtk_label_set_text(GTK_LABEL(scan_timestamps), str);
  gtk_misc_set_alignment((GtkMisc *)scan_timestamps, 0, 1);
  g_free(str);
}

GtkWidget *
create_label(list, obj)
  GtkWidget * list;
  struct subset * obj;
{
  char * name = subset_nth_value(obj, 0);
  char * severity = subset_nth_value(obj, 1);
  GtkWidget *widget = gtk_list_item_new();
  GtkWidget * box = gtk_hbox_new(FALSE, 3);
  GtkWidget * hostname;
  GtkWidget *pixmap;
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  char ** cat = NULL;
  char ** level;
 char * t;

  gtk_container_add(GTK_CONTAINER(widget), box);
  gtk_widget_show(box);

  if(!strcmp(sort_key, "host"))cat  = (char**)computer_xpm;
  else if(!strcmp(sort_key, "subnet"))cat = (char**)network_xpm;

  if(cat)
  {
    pixmap = make_pixmap(list, NULL, cat);
    gtk_box_pack_start(GTK_BOX(box), pixmap, FALSE, FALSE, 5);
    gtk_widget_show(pixmap);
  }

  if((level = select_severity_pixmap(severity)))
  {
    pixmap = make_pixmap(list, NULL, level);
    gtk_box_pack_start(GTK_BOX(box), pixmap, FALSE, FALSE, 5);
    gtk_widget_show(pixmap);
  }

  t = strchr(name, '\r');
  while(t != NULL)
  {
    t[0] = ' ';
    t = strchr(t + 1, '\r');
  }

  hostname = gtk_label_new(name);
  gtk_label_set_justify(GTK_LABEL(hostname), GTK_JUSTIFY_LEFT); 
  gtk_widget_show(hostname);
  gtk_box_pack_start(GTK_BOX(box), hostname, FALSE, FALSE, 5);
  gtk_widget_show(hostname);

  return widget;
}

static void
empty_list(list)
  GtkWidget * list;
{
  GList * items = GTK_LIST(list)->children;
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");

  if(items)
  {
    while(items)
    {
      char * ptr = gtk_object_get_data(GTK_OBJECT(items->data), sort_key);
      gtk_object_remove_data(GTK_OBJECT(items->data), sort_key);
      efree(&ptr);
      items = items->next;
    }
  gtk_list_remove_items(GTK_LIST(list), GTK_LIST(list)->children);
  }
}

void
fill_list(list, subset)
  GtkWidget * list;
  struct subset * subset;
{
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  struct subset * walk;
  GList * glist = NULL;

  walk = subset;
  while(walk)
  {
    GtkWidget * item = create_label(list, walk);
    glist = g_list_append(glist, item);
    gtk_widget_show(item);
    gtk_object_set_data(GTK_OBJECT(item), sort_key,
                        estrdup(subset_value(walk)));
    walk = subset_next(walk);
  }
  gtk_list_append_items(GTK_LIST(list), glist); 
  gtk_list_select_item(GTK_LIST(list), 0);
}

void
subnets_fill(ctrls, list)
  struct arglist * ctrls;
  GtkWidget * list;
{
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  struct subset * subset;
  int be = (int)arg_get_value(ctrls, "BE");

  if (be < 0) return;

  subset = x(query_backend(be, "SELECT %s,severity FROM results", sort_key ));

  fill_list(list, subset);
  subset_free(subset);
}

static void
hosts_fill(ctrls, list)
  struct arglist * ctrls;
  GtkWidget * list;
{
  char * restriction_1_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_1_key");
  char * restriction_1_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_1_value"); 
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  struct subset * subset;
  int be = (int)arg_get_value(ctrls, "BE");

  if (be < 0) return;

  subset = x(query_backend(be, "SELECT %s,severity FROM results WHERE %s = '%s'",
             sort_key, n(restriction_1_key), n(restriction_1_value)));

  fill_list(list, subset);
  subset_free(subset);
}

static void
ports_fill(ctrls, list)
  struct arglist * ctrls;
  GtkWidget * list;
{
  char * restriction_1_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_1_key");
  char * restriction_1_value = gtk_object_get_data(GTK_OBJECT(list),
                                                  "restriction_1_value"); 
  char * restriction_2_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_2_key");
  char * restriction_2_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_2_value"); 
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  struct subset * subset;
  int be = (int)arg_get_value(ctrls, "BE");

  if (be < 0) return;

  subset = x(query_backend(be,
    "SELECT %s,severity FROM results WHERE %s = '%s'  AND %s = '%s'",
    sort_key, n(restriction_1_key), n(restriction_1_value),
    n(restriction_2_key), n(restriction_2_value)));

  fill_list(list, subset);
  subset_free(subset);
}

static void
severity_fill(ctrls, list)
  struct arglist * ctrls;
  GtkWidget * list;
{
  char * restriction_1_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_1_key");
  char * restriction_1_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_1_value"); 
  char * restriction_2_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_2_key");
  char * restriction_2_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_2_value");
  char * restriction_3_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_3_key");
  char * restriction_3_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_3_value");

  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  struct subset * subset;
  int be = (int)arg_get_value(ctrls, "BE");

  if (be < 0) return;

  subset = x(query_backend(be,
    "SELECT %s,severity FROM results WHERE %s = '%s' AND %s = '%s' AND %s = '%s'",
    sort_key, n(restriction_1_key), n(restriction_1_value),
    n(restriction_2_key), n(restriction_2_value),
    n(restriction_3_key), n(restriction_3_value)));

  fill_list(list, subset);
  subset_free(subset);
}

static void
reports_clear(textview)
  GtkWidget *textview;
{
  GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));

  gtk_text_buffer_set_text(buffer, "", -1);
}

static void
reports_fill(ctrls, textview)
  struct arglist *ctrls;
  GtkWidget *textview;
{
  char *restriction_1_key = g_object_get_data(G_OBJECT(textview),
	"restriction_1_key");
  char *restriction_1_value = g_object_get_data(G_OBJECT(textview),
	"restriction_1_value");
  char *restriction_2_key = g_object_get_data(G_OBJECT(textview),
	"restriction_2_key");
  char *restriction_2_value = g_object_get_data(G_OBJECT(textview),
	"restriction_2_value");
  char *restriction_3_key = g_object_get_data(G_OBJECT(textview),
	"restriction_3_key");
  char *restriction_3_value = g_object_get_data(G_OBJECT(textview),
	"restriction_3_value");
  char *restriction_4_key = g_object_get_data(G_OBJECT(textview),
	"restriction_4_key");
  char *restriction_4_value = g_object_get_data(G_OBJECT(textview),
	"restriction_4_value");
  char *sort_key = g_object_get_data(G_OBJECT(textview),
	"sort_key");
  struct subset * subset;
  struct subset * walk;
  int be = (int)arg_get_value(ctrls, "BE");
  GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
  GtkTextIter iter;

  if (be < 0) return;

  subset = x(query_backend(be,
    "SELECT %s,severity FROM results"
    " WHERE %s = '%s' AND %s = '%s' AND %s = '%s' AND %s = '%s'",
    sort_key, n(restriction_1_key), n(restriction_1_value),
    n(restriction_2_key), n(restriction_2_value),
    n(restriction_3_key), n(restriction_3_value),
    n(restriction_4_key), n(restriction_4_value)));

  walk = subset;
  while(walk)
  {
    gtk_text_buffer_get_end_iter(buffer, &iter);
    gtk_text_buffer_insert(buffer, &iter, subset_value(walk), -1);
    walk = subset_next(walk);
    if(walk)
    {
      gtk_text_buffer_get_end_iter(buffer, &iter);
      gtk_text_buffer_insert(buffer, &iter, "\n"
	  "=================================="
	  "=================================="
	  "\n", -1);
    }
  }
  subset_free(subset);
}

/*
 * Callbacks
 */

static void
on_menu_item_subnet_selected(item, list)
  GtkMenuItem * item;
  GtkWidget  * list;
{
  char * old_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  char * new_key = gtk_object_get_data(GTK_OBJECT(item), "sort_key");
  char * k;

  int idx_list = -1, idx_this_list = -1;
  int i;

  if(!strcmp(old_key, new_key))
  {
    return;
  }

  for(i=0;i<4;i++)
  {
    if(Lists[i] == list) {
      idx_this_list = i;
      break;
    }
  }

  for(i=0;i<4;i++)
  {
    k = gtk_object_get_data(GTK_OBJECT(Lists[i]), "sort_key"); 
    if((new_key != NULL) && (k != NULL) && (strcmp(new_key, k) == 0))
    {
      idx_list = i;
      break;
    }
  }


  if(idx_list >= 0)
  {
    func_fill_t fill_a, fill_b;
    int min;
    struct arglist * ctrls;
    GtkWidget * optionmenu;
    GtkWidget * t;
    gtk_object_set_data(GTK_OBJECT(Lists[idx_this_list]), "sort_key", new_key);
    gtk_object_set_data(GTK_OBJECT(Lists[idx_list]), "sort_key", old_key);


    min = idx_this_list > idx_list ? idx_list:idx_this_list;
    fill_a  = (func_fill_t)
              gtk_object_get_data(GTK_OBJECT(Lists[idx_this_list]), "fill");
    fill_b  = (func_fill_t)
              gtk_object_get_data(GTK_OBJECT(Lists[idx_list]), "fill");
    ctrls = (struct arglist *)gtk_object_get_data(GTK_OBJECT(Lists[min]),
                                                  "ctrls");

    /* printf("Changing option for %d\n", idx_list); */
    optionmenu = gtk_object_get_data(GTK_OBJECT(Lists[idx_list]), "optionmenu");

    gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu), idx_this_list);

    empty_list(Lists[idx_list]);
    empty_list(Lists[idx_this_list]);
    if(fill_a)fill_a(ctrls, Lists[idx_this_list]);
    if(fill_b)fill_b(ctrls, Lists[idx_list]);

    t = Lists[idx_list];
    Lists[idx_list] = Lists[idx_this_list];
    Lists[idx_this_list] = t;
  }
}

static void
on_subnets_list_selection_changed(list, ctrls)
  GtkList *list;
  struct arglist * ctrls;
{
  char * sort_value;
  GtkWidget * hosts = gtk_object_get_data(GTK_OBJECT(list), "hosts_list");
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");

  empty_list(hosts);

  if(list->selection)
  {
    sort_value = gtk_object_get_data(GTK_OBJECT(list->selection->data),
                                     sort_key);
    replace_data(GTK_OBJECT(hosts), "restriction_1_key", estrdup(sort_key));
    replace_data(GTK_OBJECT(hosts), "restriction_1_value", estrdup(sort_value));
    if(sort_value)hosts_fill(ctrls, hosts);
  }
}


static void
on_hosts_list_selection_changed(list, ctrls)
  GtkList *list;
  struct arglist * ctrls;
{
  char * sort_value;
  char * sort_key     = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  GtkWidget * ports = gtk_object_get_data(GTK_OBJECT(list), "ports_list");
  char * restriction_1_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_1_key");
  char * restriction_1_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_1_value");

  empty_list(ports);
  if(list->selection)
  {
    sort_value = gtk_object_get_data(GTK_OBJECT(list->selection->data),
                                    sort_key);
    /* printf("host> set restriction1 = %s (%s)\n", restriction_1_key,restriction_1_value); */

    replace_data(GTK_OBJECT(ports), "restriction_1_key",
                 estrdup(restriction_1_key));
    replace_data(GTK_OBJECT(ports), "restriction_1_value",
                 estrdup(restriction_1_value));

    replace_data(GTK_OBJECT(ports), "restriction_2_key", estrdup(sort_key));
    replace_data(GTK_OBJECT(ports), "restriction_2_value", estrdup(sort_value));
    if(sort_value)ports_fill(ctrls, ports);
  }
}

static void
on_ports_list_selection_changed(list, ctrls)
  GtkList * list;
  struct arglist * ctrls;
{
  char * sort_value;
  char * sort_key = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  GtkWidget * severity = gtk_object_get_data(GTK_OBJECT(list), "severity_list");
  char * restriction_1_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_1_key");
  char * restriction_1_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_1_value");
  char * restriction_2_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_2_key");
  char * restriction_2_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_2_value");

  empty_list(severity);
  if(list->selection)
  {
    sort_value = gtk_object_get_data(GTK_OBJECT(list->selection->data),
                                     sort_key);
    replace_data(GTK_OBJECT(severity), "restriction_1_key",
                 estrdup(restriction_1_key));
    replace_data(GTK_OBJECT(severity), "restriction_1_value",
                 estrdup(restriction_1_value));

   replace_data(GTK_OBJECT(severity), "restriction_2_key",
                estrdup(restriction_2_key));
   replace_data(GTK_OBJECT(severity), "restriction_2_value",
                estrdup(restriction_2_value));

   replace_data(GTK_OBJECT(severity), "restriction_3_key", estrdup(sort_key));
   replace_data(GTK_OBJECT(severity), "restriction_3_value",
                estrdup(sort_value));
   if(sort_value)severity_fill(ctrls, severity);
  }

}

static void
on_severity_list_selection_changed(list, ctrls)
  GtkList * list;
  struct arglist * ctrls;
{
  char * sort_value;
  char * sort_key     = gtk_object_get_data(GTK_OBJECT(list), "sort_key");
  GtkWidget * reports = gtk_object_get_data(GTK_OBJECT(list), "reports_list");
  char * restriction_1_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_1_key");
  char * restriction_1_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_1_value");
  char * restriction_2_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_2_key");
  char * restriction_2_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_2_value");
  char * restriction_3_key = gtk_object_get_data(GTK_OBJECT(list),
                                                 "restriction_3_key");
  char * restriction_3_value = gtk_object_get_data(GTK_OBJECT(list),
                                                   "restriction_3_value");

  reports_clear(reports);
  if(list->selection)
  {
    sort_value = gtk_object_get_data(GTK_OBJECT(list->selection->data),
                                     sort_key);
   replace_data(GTK_OBJECT(reports), "restriction_1_key",
                estrdup(restriction_1_key));
   replace_data(GTK_OBJECT(reports), "restriction_1_value",
                estrdup(restriction_1_value));

   replace_data(GTK_OBJECT(reports), "restriction_2_key",
                estrdup(restriction_2_key));
   replace_data(GTK_OBJECT(reports), "restriction_2_value",
                estrdup(restriction_2_value));

   replace_data(GTK_OBJECT(reports), "restriction_3_key",
                estrdup(restriction_3_key));
   replace_data(GTK_OBJECT(reports), "restriction_3_value",
                estrdup(restriction_3_value));

   replace_data(GTK_OBJECT(reports), "restriction_4_key", estrdup(sort_key));
   replace_data(GTK_OBJECT(reports), "restriction_4_value",
                estrdup(sort_value));
   if(sort_value)reports_fill(ctrls, reports);
   }
}

/*
 * Build a vbox element with the report text widget.
 * be is a handle id of the backend. The backend functions
 * know what to do with it.
 */
struct arglist *
prefs_dialog_report(void)
{
  struct arglist * ctrls = emalloc(sizeof(struct arglist));
  GtkWidget * vbox;
  GtkTooltips * tooltips;
  GtkWidget *hpaned1;
  GtkWidget *vpaned1;
  GtkWidget *vbox2;
  GtkWidget *subnet;
  GtkWidget *subnet_menu;
  GtkWidget *glade_menuitem;
  GtkWidget *scrolled_window_subnet;
  GtkWidget *list_subnets;
  GtkWidget *vbox3;
  GtkWidget *optionmenu2;
  GtkWidget *optionmenu2_menu;
  GtkWidget *hosts_scrolled_window;
  GtkWidget *list_hosts;
  GtkWidget *vpaned2;
  GtkWidget *hpaned2;
  GtkWidget *vbox4;
  GtkWidget *optionmenu3;
  GtkWidget *optionmenu3_menu;
  GtkWidget *scrolledwindow3;
  GtkWidget *list_ports;
  GtkWidget *vbox5;
  GtkWidget *optionmenu4;
  GtkWidget *optionmenu4_menu;
  GtkWidget *scrolledwindow4;
  GtkWidget *list_severity;
  GtkWidget *vbox6;
  GtkWidget *scrolledwindow5;
  GtkWidget *list_reports;
  GtkWidget *hbox;
  GtkWidget *scan_timestamps;

  tooltips = gtk_tooltips_new();

  arg_add_value(ctrls, "BE", ARG_INT, sizeof(int), (void *)-1);

  vbox = gtk_vbox_new(FALSE, FALSE);
  arg_add_value(ctrls, "VBOX", ARG_PTR, -1, vbox);
  gtk_widget_show(vbox);

  Lists[0] = list_subnets = gtk_list_new ();
  Lists[1] = list_hosts   = gtk_list_new ();
  Lists[2] = list_ports   = gtk_list_new ();
  Lists[3] = list_severity= gtk_list_new ();

  list_reports = gtk_text_view_new();
  gtk_text_view_set_editable(GTK_TEXT_VIEW(list_reports), FALSE);

  scan_timestamps = gtk_label_new("Foo");
  gtk_widget_show(scan_timestamps);
  gtk_box_pack_end(GTK_BOX(vbox), scan_timestamps, FALSE, FALSE, 2);
  arg_add_value(ctrls, "SCAN_TIMESTAMPS", ARG_PTR, -1, scan_timestamps);

  hpaned1 = gtk_hpaned_new ();
  gtk_widget_ref(hpaned1);
  gtk_paned_set_position(GTK_PANED(hpaned1), 200);
  gtk_object_set_data_full(GTK_OBJECT (vbox), "hpaned1", hpaned1,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (hpaned1);
  gtk_box_pack_start(GTK_BOX(vbox), hpaned1, TRUE, TRUE, 0);

  hbox = gtk_hbox_new(TRUE, 10);
  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
  gtk_widget_show(hbox);

  vpaned1 = gtk_vpaned_new ();
  gtk_widget_ref(vpaned1);
  gtk_paned_set_position(GTK_PANED(vpaned1), 200);
  gtk_object_set_data_full(GTK_OBJECT (vbox), "vpaned1", vpaned1,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show(vpaned1);
  gtk_container_add(GTK_CONTAINER (hpaned1), vpaned1);

  vbox2 = gtk_vbox_new(FALSE, 0);
  gtk_widget_ref(vbox2);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "vbox2", vbox2,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show(vbox2);
  gtk_container_add(GTK_CONTAINER (vpaned1), vbox2);

  subnet = gtk_option_menu_new ();
  gtk_widget_ref(subnet);
  gtk_object_set_data_full(GTK_OBJECT (vbox), "subnet", subnet,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show(subnet);
  gtk_box_pack_start(GTK_BOX (vbox2), subnet, FALSE, FALSE, 0);
  subnet_menu = gtk_menu_new();
  glade_menuitem = gtk_menu_item_new_with_label(_("Subnet"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("subnet"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC(on_menu_item_subnet_selected),
                      list_subnets);
  arg_add_value(ctrls, "MENUITEM_SUBNET", ARG_PTR, -1, glade_menuitem);

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (subnet_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Host"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("host"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_subnets);

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (subnet_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Port"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("port"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_subnets);
  gtk_widget_show (glade_menuitem);

  gtk_menu_append (GTK_MENU (subnet_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Severity"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("severity"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_subnets);

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (subnet_menu), glade_menuitem);

  gtk_option_menu_set_menu (GTK_OPTION_MENU (subnet), subnet_menu);

  scrolled_window_subnet = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_ref (scrolled_window_subnet);
  gtk_object_set_data_full(GTK_OBJECT (vbox),
                           "scrolled_window_subnet", scrolled_window_subnet,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (scrolled_window_subnet);
  gtk_box_pack_start (GTK_BOX (vbox2), scrolled_window_subnet, TRUE, TRUE, 0);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_subnet),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_scrolled_window_add_with_viewport(
    GTK_SCROLLED_WINDOW(scrolled_window_subnet), list_subnets);


  gtk_object_set_data(GTK_OBJECT(list_subnets), "fill", (void*)subnets_fill);
  gtk_object_set_data(GTK_OBJECT(list_subnets), "optionmenu", (void*)subnet);
  gtk_object_set_data(GTK_OBJECT(list_subnets), "ctrls", (void*)ctrls);

  gtk_widget_ref (list_subnets);
  gtk_object_set_data_full(GTK_OBJECT (vbox), "list_subnets",
                           list_subnets, (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (list_subnets);

  vbox3 = gtk_vbox_new (FALSE, 0);
  gtk_widget_ref (vbox3);
  gtk_object_set_data_full (GTK_OBJECT (vbox), "vbox3", vbox3,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (vbox3);
  gtk_container_add (GTK_CONTAINER (vpaned1), vbox3);

  optionmenu2 = gtk_option_menu_new ();
  gtk_widget_ref (optionmenu2);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "optionmenu2",
                           optionmenu2,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (optionmenu2);
  gtk_box_pack_start (GTK_BOX (vbox3), optionmenu2, FALSE, FALSE, 0);
  optionmenu2_menu = gtk_menu_new ();
  glade_menuitem = gtk_menu_item_new_with_label (_("Subnet"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("subnet"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_hosts); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu2_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Host"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("host"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_hosts); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu2_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Port"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("port"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_hosts); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu2_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Severity"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("severity"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_hosts); 
  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu2_menu), glade_menuitem);

  gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu2), optionmenu2_menu);
  gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu2), 1);

  hosts_scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_ref (hosts_scrolled_window);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "hosts_scrolled_window",
                           hosts_scrolled_window,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (hosts_scrolled_window);
  gtk_box_pack_start (GTK_BOX (vbox3), hosts_scrolled_window, TRUE, TRUE, 0);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(hosts_scrolled_window),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_scrolled_window_add_with_viewport(
    GTK_SCROLLED_WINDOW(hosts_scrolled_window), list_hosts);

  gtk_object_set_data(GTK_OBJECT(list_hosts), "fill", (void*)hosts_fill);
  gtk_object_set_data(GTK_OBJECT(list_hosts), "optionmenu", (void*)optionmenu2);
  gtk_object_set_data(GTK_OBJECT(list_hosts), "ctrls", (void*)ctrls);
  gtk_widget_ref (list_hosts);
  gtk_object_set_data_full(GTK_OBJECT (vbox), "list_hosts",
                           list_hosts,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (list_hosts);

  vpaned2 = gtk_vpaned_new ();
  gtk_widget_ref (vpaned2);
  gtk_object_set_data_full (GTK_OBJECT (vbox), "vpaned2", vpaned2,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (vpaned2);
  gtk_container_add (GTK_CONTAINER (hpaned1), vpaned2);

  hpaned2 = gtk_hpaned_new ();
  gtk_widget_ref (hpaned2);
  gtk_paned_set_position(GTK_PANED(hpaned2), 200);
  gtk_object_set_data_full (GTK_OBJECT (vbox), "hpaned2", hpaned2,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (hpaned2);
  gtk_container_add (GTK_CONTAINER (vpaned2), hpaned2);

  vbox4 = gtk_vbox_new (FALSE, 0);
  gtk_widget_ref (vbox4);
  gtk_object_set_data_full (GTK_OBJECT (vbox), "vbox4", vbox4,
                            (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (vbox4);
  gtk_container_add (GTK_CONTAINER (hpaned2), vbox4);

  optionmenu3 = gtk_option_menu_new ();
  gtk_widget_ref (optionmenu3);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "optionmenu3",
                           optionmenu3,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (optionmenu3);
  gtk_box_pack_start (GTK_BOX (vbox4), optionmenu3, FALSE, FALSE, 0);
  optionmenu3_menu = gtk_menu_new ();
  glade_menuitem = gtk_menu_item_new_with_label (_("Subnet"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("subnet"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_ports); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu3_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Host"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("host"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_ports); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu3_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Port"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("port"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_ports); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu3_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Severity"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("severity"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_ports); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu3_menu), glade_menuitem);

  gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu3), optionmenu3_menu);
  gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu3), 2);

  scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_ref (scrolledwindow3);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "scrolledwindow3",
                           scrolledwindow3,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (scrolledwindow3);
  gtk_box_pack_start (GTK_BOX (vbox4), scrolledwindow3, TRUE, TRUE, 0);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow3),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_scrolled_window_add_with_viewport(
    GTK_SCROLLED_WINDOW(scrolledwindow3), list_ports);

  gtk_object_set_data(GTK_OBJECT(list_ports), "fill", (void*)ports_fill);
  gtk_object_set_data(GTK_OBJECT(list_ports), "optionmenu", (void*)optionmenu3);
  gtk_object_set_data(GTK_OBJECT(list_ports), "ctrls", (void*)ctrls);
  gtk_widget_ref (list_ports);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "list_ports", list_ports,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (list_ports);

  vbox5 = gtk_vbox_new (FALSE, 0);
  gtk_widget_ref (vbox5);
  gtk_object_set_data_full(GTK_OBJECT (vbox), "vbox5", vbox5,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (vbox5);
  gtk_container_add (GTK_CONTAINER (hpaned2), vbox5);

  optionmenu4 = gtk_option_menu_new ();
  gtk_widget_ref (optionmenu4);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "optionmenu4",
                           optionmenu4, (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (optionmenu4);
  gtk_box_pack_start (GTK_BOX (vbox5), optionmenu4, FALSE, FALSE, 0);
  optionmenu4_menu = gtk_menu_new ();
  glade_menuitem = gtk_menu_item_new_with_label (_("Subnet"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("subnet"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_severity); 
  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu4_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Host"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("host"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_severity); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu4_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Port"));
  gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("port"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_severity); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu4_menu), glade_menuitem);
  glade_menuitem = gtk_menu_item_new_with_label (_("Severity"));
   gtk_object_set_data(GTK_OBJECT(glade_menuitem), "sort_key", ("severity"));
  gtk_signal_connect (GTK_OBJECT (glade_menuitem), "activate",
                      GTK_SIGNAL_FUNC (on_menu_item_subnet_selected),
                      list_severity); 

  gtk_widget_show (glade_menuitem);
  gtk_menu_append (GTK_MENU (optionmenu4_menu), glade_menuitem);

  gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu4), optionmenu4_menu);
  gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu4), 3);

  scrolledwindow4 = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_ref (scrolledwindow4);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "scrolledwindow4",
                           scrolledwindow4,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (scrolledwindow4);
  gtk_box_pack_start (GTK_BOX (vbox5), scrolledwindow4, TRUE, TRUE, 0);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow4),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_scrolled_window_add_with_viewport(
    GTK_SCROLLED_WINDOW(scrolledwindow4), list_severity);

  gtk_object_set_data(GTK_OBJECT(list_severity), "fill", (void*)severity_fill);
  gtk_object_set_data(GTK_OBJECT(list_severity), "optionmenu",
                      (void*)optionmenu4);
  gtk_object_set_data(GTK_OBJECT(list_severity), "ctrls", (void*)ctrls);
  gtk_widget_ref (list_severity);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "list_severity",
                           list_severity,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (list_severity);

  vbox6 = gtk_vbox_new (FALSE, 0);
  gtk_widget_ref (vbox6);
  gtk_object_set_data_full(GTK_OBJECT (vbox), "vbox6", vbox6,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (vbox6);
  gtk_container_add (GTK_CONTAINER (vpaned2), vbox6);

  scrolledwindow5 = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_ref (scrolledwindow5);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "scrolledwindow5",
                           scrolledwindow5,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (scrolledwindow5);
  gtk_box_pack_start (GTK_BOX (vbox6), scrolledwindow5, TRUE, TRUE, 0);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow5),
                                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

  gtk_scrolled_window_add_with_viewport(
    GTK_SCROLLED_WINDOW(scrolledwindow5), list_reports);

  gtk_object_set_data(GTK_OBJECT(list_reports), "fill", (void*)reports_fill);
  gtk_object_set_data(GTK_OBJECT(list_reports), "ctrls", (void*)ctrls);

  gtk_widget_ref (list_reports);
  gtk_object_set_data_full(GTK_OBJECT(vbox), "list_reports",
                           list_reports,
                           (GtkDestroyNotify) gtk_widget_unref);
  gtk_widget_show (list_reports);


  gtk_object_set_data(GTK_OBJECT(list_subnets), "sort_key", estrdup("subnet"));
  gtk_object_set_data(GTK_OBJECT(list_subnets), "hosts_list", list_hosts);
  gtk_signal_connect (GTK_OBJECT (list_subnets), "selection_changed",
                      GTK_SIGNAL_FUNC (on_subnets_list_selection_changed),
                      (void*)ctrls);
  subnets_fill(ctrls, list_subnets);
  replace_data(GTK_OBJECT(list_subnets), "restriction_1_key",
               estrdup("subnet"));
  replace_data(GTK_OBJECT(list_subnets), "restriction_1_value",
               estrdup("not_selected"));

  gtk_object_set_data(GTK_OBJECT (list_hosts), "sort_key", estrdup("host"));
  gtk_object_set_data(GTK_OBJECT (list_hosts), "ports_list", list_ports);
  gtk_signal_connect (GTK_OBJECT (list_hosts), "selection_changed",
                      GTK_SIGNAL_FUNC (on_hosts_list_selection_changed),
                      (void*)ctrls);

  gtk_object_set_data(GTK_OBJECT (list_ports), "sort_key", estrdup("port"));
  gtk_object_set_data(GTK_OBJECT (list_ports), "severity_list", list_severity);
  gtk_signal_connect (GTK_OBJECT (list_ports), "selection_changed",
                      GTK_SIGNAL_FUNC (on_ports_list_selection_changed),
                      (void*)ctrls);

  gtk_object_set_data(GTK_OBJECT (list_severity), "sort_key",
                      estrdup("severity"));
  gtk_object_set_data(GTK_OBJECT (list_severity), "reports_list", list_reports);
  gtk_signal_connect (GTK_OBJECT (list_severity), "selection_changed",
                      GTK_SIGNAL_FUNC (on_severity_list_selection_changed),
                      (void*)ctrls);

  gtk_object_set_data(GTK_OBJECT (list_reports), "sort_key", estrdup("report"));

  gtk_tooltips_enable(tooltips);

  return ctrls;
}


void
prefs_report_update(ctrls)
  struct arglist *ctrls;
{
  empty_list(Lists[0]);
  subnets_fill(ctrls, Lists[0]);
  prefs_report_update_timestamp(ctrls);
}

