/* 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.
 */

/**
 * @file
 * Module to create large parts of the GUI.\n
 * Most visible GTK Widgets are hooked into arglist(s) like MainDialog (defined
 * in nessus.c).
 * 
 */

#include <includes.h>

#include "nessus_i18n.h"
#include "nessus_plugin.h"
#include "nvt_pref_sshlogin.h"

#ifdef USE_GTK
#include "comm.h"
#include <gtk/gtk.h>
#include "context.h"
#include "preferences.h"
#include "sighand.h"
#include "prefs_dialog_auth.h"
#include "prefs_dialog_prefs.h"
#include "prefs_help.h"
#include "prefs_dialog.h"
#include "prefs_context.h"
#include "prefs_scope_tree.h"
#include "about_dlg.h"
#include "slad_install.h"
#include "prefs_comment.h"
#include "prefs_options.h"
#include "prefs_report.h"
#include "prefs_scan_assistant.h"
/* We act on the tree-view showing contexts, needed for prefs_scope_tree_update_report  */
#include "prefs_scope_tree.h"
#include "prefs_comment.h"
#include "prefs_dialog_user.h"


#ifdef ENABLE_SAVE_KB
# include "prefs_kb.h"
#endif

/* We do non-capsulated things on the tree-view showing contexts */
#include "backend.h"
#include "error_dlg.h"
#include "severityfiltermngr_dlg.h"
#include "severity_filter.h"
#include "ssh_keys_dialog.h"
#include "monitor_dialog.h"
#include "report.h"
#include "report_save.h"
#include "read_target_file.h"
#include "globals.h"

#include "../xpm/connect_16.xpm"
#include "../xpm/connect_24.xpm"
#include "../xpm/disconnect_16.xpm"
#include "../xpm/disconnect_24.xpm"
#include "../xpm/general_prefs.xpm"
#include "../xpm/credentials.xpm"
#include "../xpm/plugins.xpm"
#include "../xpm/knowledgebase.xpm"
#include "../xpm/access_rules.xpm"
#include "../xpm/properties.xpm"
#include "../xpm/target_selection.xpm"
#include "../xpm/warning.xpm"
#include "../xpm/warning_small.xpm"
#include "../xpm/error.xpm"
#include "../xpm/error_small.xpm"
#include "../xpm/info.xpm"
#include "../xpm/info_small.xpm"

/* temporary, should be part of the global context, comes from severity_filter.c */
extern severity_filter_t* global_filter;

static void prefs_dialog_set_tooltips(struct arglist *);

/**
 * @brief Launch the users manual pdf document with the configured pdf viewer.
 */
void
show_users_manual (GtkWidget *menuitem, gpointer ctrls)
{
#ifndef CYGWIN
#ifdef NESSUS_DOCDIR
  char * dir = NESSUS_DOCDIR;
#else
  char * dir = "";
#endif
#else
  char * dir = g_win32_get_package_installation_subdirectory(NULL, NULL,
                 "share\\doc\\openvas-manual");
#endif /* CYGWIN */

  /* PDF file path. String is covered by gettext to allow speficication of 
   * translation in the respective po files rather than in the source code. */
  char * fname = _("users-manual.pdf");
  char * path = g_build_filename(dir, fname, NULL);

  show_pdf(path);
  g_free(path);
}

/**
 * @brief Save the current global settings to ~/.openvasrc .
 */
void
save_global_settings (GtkWidget *menuitem, gpointer ctrls)
{
  prefs_dialog_apply(Global, ctrls);
  prefs_dialog_apply_plugin_prefs(Global->plugins);
  prefs_dialog_apply_plugin_prefs(Global->scanners);
  context_sync_plugin_prefs(Global);
  preferences_save(Global);
  show_info(_("The global settings have been saved."));
}

/**
 * @brief Toggle Toolbar on/off.
 * 
 * @param menuitem Check box menu item for toggling visibility of the toolbar.
 * @param ctrls    Arglist where the TOOLBAR is hooked into.
 */
void
toggle_toolbar (GtkWidget *menuitem, struct arglist *ctrls)
{
  GtkWidget *toolbar = arg_get_value(ctrls, "TOOLBAR");

  if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)))
  {
    prefs_set_int(Global, "hide_toolbar", 0);
    gtk_widget_show(toolbar);
  }
  else
  {
    prefs_set_int(Global, "hide_toolbar", 1);
    gtk_widget_hide(toolbar);
  }
}


/**
 * @brief Toggle Message-Log on/off.
 * 
 * @param menuitem Check box menu item for toggling the message frame display.
 * @param ctrls    Arglist where the MSGLOGFRAME is hooked into.
 */
void
toggle_msglog (GtkWidget *menuitem, struct arglist *ctrls)
{
  GtkWidget *msglogframe = arg_get_value(ctrls, "MSGLOGFRAME");

  if(gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)))
  {
    prefs_set_int(Global, "hide_msglog", 0);
    gtk_widget_show(msglogframe);
  }
  else
  {
    prefs_set_int(Global, "hide_msglog", 1);
    gtk_widget_hide(msglogframe);
  }
}


/**
 * @brief Add a menu item with optional icon and signal-connect it to a function.
 * 
 * @param menutitem Menu-Item to add.
 * @param menu      Menu to add menu-item to.
 * @param stockicon Name for icon from stock (can be NULL).
 * @param name      Visible name of the menu item.
 * @param func      Function to connect to activate-signal.
 */
void
menuitem_add (GtkWidget *menuitem, GtkWidget *menu, const gchar *name,
              const gchar *stockicon, GtkSignalFunc func)
{
  GtkWidget *icon;

  gtk_widget_show(menuitem);
  gtk_container_add(GTK_CONTAINER(menu), menuitem);
  if(name)
    arg_add_value(MainDialog, name, ARG_PTR, -1, menuitem);
  if(stockicon)
  {
    icon = gtk_image_new_from_stock(stockicon, GTK_ICON_SIZE_MENU);
    gtk_widget_show(icon);
    gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), icon);
  }
  if(func)
    g_signal_connect(GTK_OBJECT(menuitem), "activate", func, MainDialog);
}

/**
 * @brief Adds a separator to a menu.
 * 
 * @param menu Menu to add a separator to.
 */
void
menuitem_separator (GtkWidget *menu)
{
  GtkWidget *menuitem;

  menuitem = gtk_menu_item_new();
  menuitem_add(menuitem, menu, NULL, NULL, NULL);
  gtk_widget_set_sensitive(menuitem, FALSE);
}


/**
 * @brief Add a pair of new "stock" icons to the factory.
 *
 * The parameters small and large are the arrays of char* that make up
 * an xpm.  The icons are added to the factory as an icon set for the
 * given stock id.  The small icon is used as the default icon for the
 * size GTK_ICON_SIZE_MENU and the large one is the default icon for the
 * whole set and the default icon for the size
 * GTK_ICON_SIZE_LARGE_TOOLBAR.
 *
 * The parameter small may be NULL to indicate that no special small
 * variant exists.
 * 
 * @param large Char array that makes the large size icon (xpm).
 * @param small Char array that makes the small size icon (xpm).
 */
static void
add_nessus_icon_set (GtkIconFactory *factory, const char *stock_id,
                     const char **large, const char **small_icon)
{
  GtkIconSet *iconset;
  GtkIconSource *source;
  GdkPixbuf *pixbuf;

  /* The "large" icon is used as the default icon and the icon for the
   * GTK_ICON_SIZE_LARGE_TOOLBAR size */
  pixbuf = gdk_pixbuf_new_from_xpm_data(large);
  iconset = gtk_icon_set_new_from_pixbuf(pixbuf);

  source = gtk_icon_source_new();
  gtk_icon_source_set_pixbuf(source, pixbuf);
  gtk_icon_source_set_size_wildcarded(source, FALSE);
  gtk_icon_source_set_size(source, GTK_ICON_SIZE_LARGE_TOOLBAR);
  gtk_icon_set_add_source(iconset, source);
  gtk_icon_source_free(source);
  g_object_unref(G_OBJECT(pixbuf));

  /* The "small" icon is used for the GTK_ICON_SIZE_MENU size */
  if (small_icon != NULL)
  {
    pixbuf = gdk_pixbuf_new_from_xpm_data(small_icon);
    source = gtk_icon_source_new();
    gtk_icon_source_set_pixbuf(source, pixbuf);
    gtk_icon_source_set_size_wildcarded(source, FALSE);
    gtk_icon_source_set_size(source, GTK_ICON_SIZE_MENU);
    gtk_icon_set_add_source(iconset, source);
    gtk_icon_source_free(source);
    g_object_unref(G_OBJECT(pixbuf));
  }

  gtk_icon_factory_add(factory, stock_id, iconset);
}

/**
 * @brief Create some openvas specific stock icons.
 *
 * This function adds several openvas specific icon sets for use in e.g.
 * menus and buttons.
 */
static void
create_nessus_icon_factory()
{
  GtkIconFactory* factory = gtk_icon_factory_new();

  add_nessus_icon_set(factory, "openvas-connect", connect_24, connect_16);
  add_nessus_icon_set(factory, "openvas-disconnect", disconnect_24,
                      disconnect_16);
  add_nessus_icon_set(factory, "nessus-general-prefs", 
                      (const char**) general_prefs_xpm, NULL);
  add_nessus_icon_set(factory, "nessus-plugins",
                      (const char**) plugins_xpm, NULL);
  add_nessus_icon_set(factory, "nessus-credentials",
                      (const char**) credentials_xpm, NULL);
  add_nessus_icon_set(factory, "nessus-target-selection",
                      (const char**) target_selection_xpm, NULL);
  add_nessus_icon_set(factory, "nessus-access-rules",
                      (const char**) access_rules_xpm, NULL);
  add_nessus_icon_set(factory, "nessus-prefs", (const char**) properties_xpm,
                      NULL);
  add_nessus_icon_set(factory, "nessus-knowledge-base",
                      (const char**) knowledgebase_xpm, NULL);
  add_nessus_icon_set(factory, "nessus-error",
                      (const char**) error_xpm, (const char**) error_small_xpm);
  add_nessus_icon_set(factory, "nessus-warning", (const char**) warning_xpm,
                      (const char**) warning_small_xpm);
  add_nessus_icon_set(factory, "nessus-info", (const char**) info_xpm,
                      (const char**) info_small_xpm);

  gtk_icon_factory_add_default(factory);
  g_object_unref(G_OBJECT(factory));
}

/**
 * @brief Applies/Undos the global severity_filter to current selected report.
 * 
 * Swaps the current contexts is_severity_mapped flag and the menu items
 * label.
 * 
 * @param source The GtkMenuImageItem. The text will be altered to indicate
 *               the new possibility after applying/ undoing the overrides.
 */
static void
apply_severity_filter (GtkWidget* source, gpointer ignored)
{
  GtkWidget *menu_label = gtk_bin_get_child(GTK_BIN(source));

  if (Context->type != CONTEXT_REPORT)
    return;

  // Swap the flag and set the text of the menu- item according to state of
  // context (a handier way of doing this (item_set_label) in Gtk 2.16 )
  if (Context->is_severity_mapped == TRUE)
    {
      gtk_label_set_text(GTK_LABEL(menu_label), _("Override severities"));
      Context->is_severity_mapped = FALSE;
    }
  else
    {
      gtk_label_set_text(GTK_LABEL(menu_label), _("Undo severity override"));
      Context->is_severity_mapped = TRUE;
    }

  // Refresh scopeview
  prefs_scope_tree_update_report ();
}

/**
 * @brief Draws the preferences dialog of the OpenVAS client (and other things).
 * 
 * Also init and draw the OpenVAS client.
 * Inits the MainDialog from where GUI elements are referenced.
 */
void
prefs_dialog_setup (struct context* context)
{
  GtkWidget *window;
  GtkWidget *mainmenu;
  GtkWidget *menuitem;
  GtkWidget *submenu;
  GtkWidget *subsubmenu;
  GtkWidget *notebook;
  GtkWidget *label;
  GtkWidget *frame;
  GtkWidget *box;
  GtkWidget *hbox;
  GtkWidget *vbox;
  GtkWidget *msglogframe;
  GtkWidget *icon;
  GtkTooltips * toolbar_tips = gtk_tooltips_new();
  GtkToolItem * tool_button;
  GtkWidget *toolbar;
  GtkWidget *scrolledwindow;
  GtkWidget *textview;
  GtkWidget *hpaned;
  GtkWidget *statusbar;
  GtkAccelGroup *accel_group;
  struct arglist *prefs_scope_tree;
  struct arglist *prefs_comment;
  struct arglist *prefs_options;
  struct arglist *prefs_report;
  struct arglist *ctrls = emalloc(sizeof(struct arglist));

  MainDialog = ctrls;

  create_nessus_icon_factory();

  /* We draw the window .... */
  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_default_size(GTK_WINDOW(window), 1000, 630);
  g_signal_connect(G_OBJECT(window), "delete_event",
      G_CALLBACK(gtk_main_quit), NULL);
  g_signal_connect(G_OBJECT(window), "delete_event",
      G_CALLBACK(gtk_widget_hide_on_delete), NULL);

  gtk_window_set_title(GTK_WINDOW(window), _("OpenVAS-Client"));
  arg_add_value(ctrls, "WINDOW", ARG_PTR, -1, window);
  arg_add_value(ctrls, "CONTEXT", ARG_PTR, -1, window);

  /* We put a vbox in it... */
  box = gtk_vbox_new(FALSE, 0);
  gtk_container_add(GTK_CONTAINER(window), box);
  gtk_widget_show(box);


  /* Main menu */
  accel_group = gtk_accel_group_new();
  gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);

  mainmenu = gtk_menu_bar_new();
  gtk_widget_show(mainmenu);
  gtk_box_pack_start(GTK_BOX(box), mainmenu, FALSE, FALSE, 0);


  /* File menu */
  menuitem = gtk_menu_item_new_with_mnemonic(_("_File"));
  menuitem_add(menuitem, mainmenu, NULL, NULL, NULL);
  submenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);

  menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Connect"));
  menuitem_add(menuitem, submenu, "CONNECT_MENUITEM", "openvas-connect",
      GTK_SIGNAL_FUNC(prefs_dialog_auth_connect));

  menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Disconnect"));
  menuitem_add(menuitem, submenu, "DISCONNECT_MENUITEM", "openvas-disconnect",
      GTK_SIGNAL_FUNC(prefs_dialog_auth_disconnect));
  gtk_widget_set_sensitive(menuitem, FALSE);

  menuitem_separator(submenu);

  menuitem = gtk_image_menu_item_new_with_mnemonic(_("_Scan Assistant"));
  menuitem_add(menuitem, submenu, NULL, "gtk-help",
      GTK_SIGNAL_FUNC(prefs_scan_assistant));

  menuitem = gtk_image_menu_item_new_from_stock("gtk-preferences", accel_group);
  menuitem_add(menuitem, submenu, "PREFERENCES_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(prefs_dialog_prefs));

  menuitem = gtk_image_menu_item_new_with_mnemonic(_("Save _Global Settings"));
  menuitem_add(menuitem, submenu, NULL, "gtk-save",
      GTK_SIGNAL_FUNC(save_global_settings));

  menuitem_separator(submenu);

  menuitem = gtk_image_menu_item_new_from_stock("gtk-quit", accel_group);
  menuitem_add(menuitem, submenu, NULL, NULL,
      GTK_SIGNAL_FUNC(gtk_main_quit));


  /* View menu */
  menuitem = gtk_menu_item_new_with_mnemonic(_("_View"));
  menuitem_add(menuitem, mainmenu, NULL, NULL, NULL);
  submenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);

  menuitem = gtk_check_menu_item_new_with_mnemonic(_("_Toolbar"));
  menuitem_add(menuitem, submenu, "TOGGLETOOLBAR_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(toggle_toolbar));

  menuitem = gtk_check_menu_item_new_with_mnemonic(_("_Message log"));
  menuitem_add(menuitem, submenu, "TOGGLEMSGLOG_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(toggle_msglog));


  /* Task menu */
  menuitem = gtk_menu_item_new_with_mnemonic(_("_Task"));
  menuitem_add(menuitem, mainmenu, NULL, NULL, NULL);
  submenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);

  menuitem = gtk_image_menu_item_new_with_mnemonic(_("_New"));
  menuitem_add(menuitem, submenu, NULL, "gtk-new",
      GTK_SIGNAL_FUNC(task_menu_new));

  menuitem = gtk_menu_item_new_with_mnemonic(_("_Rename"));
  menuitem_add(menuitem, submenu, "RENAMETASK_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(task_menu_rename));

  menuitem = gtk_image_menu_item_new_from_stock("gtk-delete", accel_group);
  menuitem_add(menuitem, submenu, "DELETETASK_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(task_menu_delete));


  /* Scope menu */
  menuitem = gtk_menu_item_new_with_mnemonic(_("_Scope"));
  menuitem_add(menuitem, mainmenu, NULL, NULL, NULL);
  submenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);

  menuitem = gtk_image_menu_item_new_from_stock("gtk-execute", accel_group);
  menuitem_add(menuitem, submenu, "EXECSCOPE_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(prefs_dialog_execute));

  menuitem_separator(submenu);

  menuitem = gtk_image_menu_item_new_with_mnemonic(_("_New"));
  menuitem_add(menuitem, submenu, "NEWSCOPE_MENUITEM", "gtk-new",
      GTK_SIGNAL_FUNC(scope_menu_new));

  menuitem = gtk_menu_item_new_with_mnemonic(_("_Rename"));
  menuitem_add(menuitem, submenu, "RENAMESCOPE_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(scope_menu_rename));

  menuitem = gtk_image_menu_item_new_from_stock("gtk-delete", accel_group);
  menuitem_add(menuitem, submenu, "DELETESCOPE_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(scope_menu_delete));

  /* Scope -> Move to task */
  menuitem = gtk_menu_item_new_with_mnemonic(_("_Move to task"));
  menuitem_add(menuitem, submenu, "MOVESCOPE_MENUITEM", NULL, NULL);
  subsubmenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), subsubmenu);
  arg_add_value(ctrls, "MOVESCOPE_SUBMENU", ARG_PTR, -1, subsubmenu);

  menuitem_separator(submenu);

  menuitem = gtk_image_menu_item_new_from_stock("gtk-open", NULL);
  menuitem_add(menuitem, submenu, "OPENSCOPE_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(scope_menu_open));

  menuitem = gtk_image_menu_item_new_from_stock("gtk-save-as", NULL);
  menuitem_add(menuitem, submenu, "SAVESCOPE_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(scope_menu_save));


  /* Report menu */
  menuitem = gtk_menu_item_new_with_mnemonic(_("_Report"));
  menuitem_add(menuitem, mainmenu, NULL, NULL, NULL);
  submenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);

  menuitem = gtk_menu_item_new_with_mnemonic(_("_Rename"));
  menuitem_add(menuitem, submenu, "RENAMEREPORT_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(report_menu_rename));

  menuitem = gtk_image_menu_item_new_from_stock("gtk-delete", accel_group);
  menuitem_add(menuitem, submenu, "DELETEREPORT_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(report_menu_delete));

  menuitem_separator(submenu);

  //menuitem = gtk_check_menu_item_new_with_mnemonic (_("_Apply Severity Filter"));
  menuitem = gtk_image_menu_item_new_with_label (_("Override severities"));
  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menuitem),
                                 gtk_image_new_from_stock (GTK_STOCK_CONVERT, GTK_ICON_SIZE_MENU));
  menuitem_add (menuitem, submenu, "APPLYOVERRIDESTOREPORT_MENUITEM", NULL,
                                      GTK_SIGNAL_FUNC(apply_severity_filter));

  menuitem_separator(submenu);

  menuitem = gtk_menu_item_new_with_mnemonic(_("_Import"));
  menuitem_add(menuitem, submenu, "IMPORTREPORT_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(open_report_selectfile));

  menuitem = gtk_menu_item_new_with_mnemonic(_("E_xport"));
  menuitem_add(menuitem, submenu, "EXPORTREPORT_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(report_save_cb));

  menuitem = gtk_image_menu_item_new_from_stock("gtk-print", accel_group);
  menuitem_add(menuitem, submenu, "PRINTREPORT_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(report_open_pdf));

  /* Extras menu */
  menuitem = gtk_menu_item_new_with_mnemonic(_("E_xtras"));
  menuitem_add(menuitem, mainmenu, NULL, NULL, NULL);
  submenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);

  menuitem = gtk_image_menu_item_new_with_mnemonic(_("SLAD _Install Manager"));
  menuitem_add(menuitem, submenu, NULL, "slad-install",
      GTK_SIGNAL_FUNC(slad_install));

  menuitem = gtk_menu_item_new_with_mnemonic(_("LSC _Credentials Manager"));
  menuitem_add(menuitem, submenu, "LSCCREDENTIALSMANAGER_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(ssh_manager_button_cb));

  menuitem = gtk_menu_item_new_with_mnemonic(_("Severity _Overrides Manager"));
  menuitem_add(menuitem, submenu, "PRIRORITYFILTERMANAGER_MENUITEM", NULL,
      GTK_SIGNAL_FUNC(severityfiltermanager_dialog));

  /* Help menu */
  menuitem = gtk_menu_item_new_with_mnemonic(_("_Help"));
  menuitem_add(menuitem, mainmenu, NULL, NULL, NULL);
  submenu = gtk_menu_new();
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);

  menuitem = gtk_menu_item_new_with_mnemonic(_("_Users Manual"));
  menuitem_add(menuitem, submenu, NULL, NULL,
      GTK_SIGNAL_FUNC(show_users_manual));

  menuitem = gtk_menu_item_new_with_mnemonic(_("_About"));
  menuitem_add(menuitem, submenu, NULL, NULL,
      GTK_SIGNAL_FUNC(about_dialog));



/* hbox with toolbar+scopetree-vbox and notebook */
  hbox = gtk_hbox_new(FALSE, 4);
  gtk_widget_show(hbox);
  gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0);

  hpaned = gtk_hpaned_new();
  gtk_widget_ref(hpaned);
  gtk_paned_set_position(GTK_PANED(hpaned), 350);
  gtk_widget_show(hpaned);
  gtk_box_pack_start(GTK_BOX(hbox), hpaned, TRUE, TRUE, 0);

  gtk_container_set_border_width(GTK_CONTAINER(hbox), 4);

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_widget_show(vbox);
  gtk_container_add(GTK_CONTAINER(hpaned), vbox);

  /* The Toolbar */
  toolbar = gtk_toolbar_new();
  gtk_widget_show(toolbar);
  gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
  gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
  arg_add_value(ctrls, "TOOLBAR", ARG_PTR, -1, toolbar);

  tool_button = gtk_tool_button_new_from_stock("gtk-help");
  gtk_tool_button_set_label(GTK_TOOL_BUTTON(tool_button), _("Scan Assistant"));
  gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(tool_button),
                            toolbar_tips, _("Scan Assistant"), NULL);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_button, -1);
  g_signal_connect(G_OBJECT(tool_button), "clicked",
      G_CALLBACK(prefs_scan_assistant), MainDialog);
  gtk_widget_show(GTK_WIDGET(tool_button));

  tool_button = gtk_tool_button_new_from_stock("gtk-new");
  gtk_tool_button_set_label(GTK_TOOL_BUTTON(tool_button), _("New"));
  gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(tool_button),
                            toolbar_tips, _("New"), NULL);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_button, -1);
  g_signal_connect(G_OBJECT(tool_button), "clicked",
      G_CALLBACK(scopetree_context_new), NULL);
  gtk_widget_show(GTK_WIDGET(tool_button));

  tool_button = gtk_tool_button_new_from_stock("gtk-delete");
  gtk_tool_button_set_label(GTK_TOOL_BUTTON(tool_button), _("Delete"));
  gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(tool_button),
                            toolbar_tips, _("Delete"), NULL);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_button, -1);
  g_signal_connect(G_OBJECT(tool_button), "clicked",
      G_CALLBACK(scopetree_context_delete), NULL);
  gtk_widget_show(GTK_WIDGET(tool_button));
  arg_add_value(ctrls, "DELETECONTEXT_BUTTON", ARG_PTR, -1, tool_button);

  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), gtk_separator_tool_item_new(), -1);

  tool_button = gtk_tool_button_new_from_stock("openvas-connect");
  gtk_tool_button_set_label(GTK_TOOL_BUTTON(tool_button), _("Connect"));
  gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(tool_button),
                            toolbar_tips, _("Connect"), NULL);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_button, -1);
  g_signal_connect(G_OBJECT(tool_button), "clicked",
      G_CALLBACK(prefs_dialog_auth_connect), MainDialog);
  gtk_widget_show(GTK_WIDGET(tool_button));
  arg_add_value(ctrls, "CONNECT_BUTTON", ARG_PTR, -1, tool_button);

  tool_button = gtk_tool_button_new_from_stock("openvas-disconnect");
  gtk_tool_button_set_label(GTK_TOOL_BUTTON(tool_button), _("Disconnect"));
  gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(tool_button),
                            toolbar_tips, _("Disconnect"), NULL);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_button, -1);
  g_signal_connect(G_OBJECT(tool_button), "clicked",
      G_CALLBACK(prefs_dialog_auth_disconnect), MainDialog);
  gtk_widget_show(GTK_WIDGET(tool_button));
  arg_add_value(ctrls, "DISCONNECT_BUTTON", ARG_PTR, -1, tool_button);

  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), gtk_separator_tool_item_new(), -1);

  tool_button = gtk_tool_button_new_from_stock("gtk-execute");
  gtk_tool_button_set_label(GTK_TOOL_BUTTON(tool_button), _("Execute"));
  gtk_tool_item_set_tooltip(GTK_TOOL_ITEM(tool_button),
                            toolbar_tips, _("Execute"), NULL);
  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_button, -1);
  g_signal_connect(G_OBJECT(tool_button), "clicked",
      G_CALLBACK(prefs_dialog_execute), ctrls);
  gtk_widget_show(GTK_WIDGET(tool_button));
  arg_add_value(ctrls, "EXECSCOPE_BUTTON", ARG_PTR, -1, tool_button);

  /* The Scope Tree */
  prefs_scope_tree = prefs_dialog_scope_tree(context);
  frame = arg_get_value(prefs_scope_tree, "FRAME");
  gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
  arg_add_value(ctrls, "SCOPETREE", ARG_PTR, -1, prefs_scope_tree);

  /* The Context Frame */
  frame = gtk_frame_new(NULL);
  gtk_frame_set_label(GTK_FRAME(frame), _("Context"));
  gtk_widget_show(frame);
  gtk_container_add(GTK_CONTAINER(hpaned), frame);
  arg_add_value(ctrls, "CONTEXTFRAME", ARG_PTR, -1, frame);

  /* The Context Notebook */
  notebook = gtk_notebook_new();
  gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);
  gtk_container_add(GTK_CONTAINER(frame), notebook);
  gtk_widget_show(notebook);
  arg_add_value(ctrls, "CONTEXTNOTEBOOK", ARG_PTR, -1, notebook);

  /* We set up the pages of our notebook */
  prefs_comment = prefs_dialog_comment();
  prefs_options = prefs_dialog_options(context, ctrls);
  prefs_report = prefs_dialog_report();

  arg_add_value(ctrls, "COMMENT", ARG_ARGLIST, -1, prefs_comment);
  arg_add_value(ctrls, "OPTIONS", ARG_ARGLIST, -1, prefs_options);
  arg_add_value(ctrls, "REPORT", ARG_ARGLIST, -1, prefs_report);

  /* and we append them to it  */

  /* Tab "Comments" */
  label = gtk_label_new(_("Comments"));
  vbox = arg_get_value(prefs_comment, "VBOX");
  gtk_widget_show(vbox);
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);

  /* Tab "Options" */
  label = gtk_label_new(_("Options"));
  vbox = arg_get_value(prefs_options, "VBOX");
  gtk_widget_show(vbox);
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);

  /* Tab "Report" */
  label = gtk_label_new(_("Report"));
  vbox = arg_get_value(prefs_report, "VBOX");
  gtk_widget_show(vbox);
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label);

  g_signal_connect_after(G_OBJECT(notebook), "switch-page",
      G_CALLBACK(prefs_context_switch_notebookpage), NULL);


  /* Message Log */

  /* The frame */
  msglogframe = gtk_frame_new(NULL);
  gtk_widget_show(msglogframe);
  gtk_box_pack_start(GTK_BOX(box), msglogframe, TRUE, TRUE, 0);
  gtk_container_set_border_width(GTK_CONTAINER(msglogframe), 4);
  arg_add_value(ctrls, "MSGLOGFRAME", ARG_PTR, -1, msglogframe);

  /* The label for the frame */
  label = gtk_label_new(_("Message log"));
  gtk_widget_show(label);
  gtk_frame_set_label_widget(GTK_FRAME(msglogframe), label);

  /* The scrolled window */
  scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
  gtk_widget_show(scrolledwindow);
  gtk_container_add(GTK_CONTAINER(msglogframe), scrolledwindow);
  gtk_container_set_border_width(GTK_CONTAINER(scrolledwindow), 4);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
      GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
  gtk_scrolled_window_set_placement(GTK_SCROLLED_WINDOW(scrolledwindow),
      GTK_CORNER_TOP_RIGHT);
  arg_add_value(ctrls, "MSGLOGSCROLL", ARG_PTR, -1, scrolledwindow);

  /* The text view */
  textview = gtk_text_view_new();
  gtk_widget_show(textview);
  gtk_container_add(GTK_CONTAINER(scrolledwindow), textview);
  gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE);
  gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)),
    _("Welcome to OpenVAS-Client, http://www.openvas.org/"
      "\nNessusClient origin: Copyright 1998-2007 by Renaud Deraison"
      "\nNew code since OpenVAS-Client: Copyright 2007, 2008, 2009 Intevation GmbH"
      "\nAuthors: Renaud Deraison, Thomas Arendsen Hein, Jan-Oliver Wagner"
      ", Bernhard Herzog, Michel Arboi (SSL-Support), Bruce Verderaime (Pie/Charts)"
      ", Michael Wiegand, Felix Wolfsteller"
      "\n"),
      -1);
  arg_add_value(ctrls, "MSGLOGTEXT", ARG_PTR, -1, textview);

  /* The whole Message Log frame is invisible by default */
  gtk_widget_hide(msglogframe);


  /* Status bar */
  hbox = gtk_hbox_new(FALSE, 0);
  gtk_widget_show(hbox);
  gtk_box_pack_end(GTK_BOX(box), hbox, FALSE, TRUE, 0);

  hpaned = gtk_hpaned_new();
  gtk_widget_show(hpaned);
  gtk_box_pack_start(GTK_BOX(hbox), hpaned, TRUE, TRUE, 1);

  statusbar = gtk_statusbar_new();
  gtk_widget_show(statusbar);
  gtk_paned_pack1(GTK_PANED(hpaned), statusbar, TRUE, FALSE);
  gtk_widget_set_size_request(statusbar, 200, -1);
  gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE);

  statusbar = gtk_statusbar_new();
  gtk_widget_show(statusbar);
  gtk_paned_pack2(GTK_PANED(hpaned), statusbar, TRUE, FALSE);
  gtk_widget_set_size_request(statusbar, 200, -1);
  gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE);
  arg_add_value(ctrls, "CONNECT_STATUSBAR", ARG_PTR, -1, statusbar);
  gtk_statusbar_push(GTK_STATUSBAR(statusbar),
      gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "connection"),
      _("not connected"));

  icon = gtk_image_new();
  gtk_widget_show(icon);
  gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, TRUE, 0);
  arg_add_value(ctrls, "CONNECT_IMAGE", ARG_PTR, -1, icon);

  /* Final */
  menuitem = arg_get_value(ctrls, "TOGGLETOOLBAR_MENUITEM");
  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
      !prefs_get_int(Global, "hide_toolbar"));
  toggle_toolbar(menuitem, ctrls);
  menuitem = arg_get_value(ctrls, "TOGGLEMSGLOG_MENUITEM");
  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem),
      prefs_get_int(Global, "hide_msglog"));
  toggle_msglog(menuitem, ctrls);

  prefs_dialog_set_defaults(context, ctrls);
  prefs_dialog_set_tooltips(ctrls);
  gtk_widget_show(window);
}

/**
 * @brief Sets a ARG_STRING value "yes" or "no" in a preference arglist, if the same
 * @brief key existed as ARG_INT before.
 *
 * @param preferences    Preferences arglist.
 *
 * @param prefrence_name Key to look for and eventually set to "yes" or no.
 *
 * @return The value of the preference as string (do not free it).
 */
static char*
arg_int_to_yesno (struct arglist* preferences, const char* preference_name)
{
  char* value = arg_get_value (preferences, preference_name);

  if (arg_get_type (preferences, preference_name) == ARG_INT)
  {
    char *yesno = (value) ? estrdup("yes") : estrdup("no");

    /* RATS: ignore yesno is nul-terminated because of strdup of string literal*/
    arg_set_value (preferences, preference_name, strlen(yesno), yesno);
    arg_set_type  (preferences, preference_name, ARG_STRING);
    return yesno;
  }

  return value;
}

/**
 * @brief Sets the state of a togglebutton according to a preference value and
 * @brief possibly changes the pref value (to represent "yes"/"no" as strings).
 *
 * @param ctrls Arglist where the toggle-button is hooked into.
 *
 * @param togglebuttonkey Key for toggle button in arglist (param) ctrls.
 *
 * @param prefs Arglist holding the preferences.
 *
 * @param prefkey Key (preference name) of preference value in arlist (param)
 *                prefs.
 *
 * @return TRUE if togglebutton was set according to a preferences value, FALSE
 *         otherwise.
 */
static gboolean
set_toggle_from_pref (struct arglist* ctrls,
                      const char* togglebuttonkey,
                      struct arglist* prefs,
                      const char* prefkey
                      )
{
  GtkWidget* togglebutton = arg_get_value (ctrls, togglebuttonkey);
  char* value;

  if (!togglebutton)
    return FALSE;

  // If we see yes/no represented as int, change it into "yes" or "no" and
  // set the type of this key/value-pair to type_string.
  value = arg_int_to_yesno (prefs, prefkey);

  if (value && !strcmp(value, "yes"))
    GTK_TOGGLE_BUTTON(togglebutton)->active = TRUE;
  else
    GTK_TOGGLE_BUTTON(togglebutton)->active = FALSE;

  return TRUE;
}

/**
 * @brief Sets default values to the GTK Widgets hooked in ctrls.
 */
void
prefs_dialog_set_defaults (struct context *context, struct arglist *ctrls)
{
#define EX_NONE 1
#define EX_DNS 2
#define EX_IP 4
#define EX_NFS 8

  struct arglist *t, *serv;
  char *v;
  int flag = 0;
  GtkWidget *gtkw;

  serv = arg_get_value(context->prefs, "SERVER_PREFS");
  if(!serv)
    return;

  t = arg_get_value(ctrls, "PLUGINS");

  set_toggle_from_pref (t, "ENABLE_DEPS_AT_RUNTIME", serv, "auto_enable_dependencies");
  set_toggle_from_pref (t, "SILENT_DEPS", serv, "silent_dependencies");

  gtkw = arg_get_value (t, "GLOBAL_NVT_TIMEOUT");
  if(gtkw)
    {
      v = arg_get_value(serv, "plugins_timeout");
      if(v)
        gtk_spin_button_set_value (GTK_SPIN_BUTTON(gtkw), atof(v));
    }

  // Not using set_toggle_from_pref because the preferences type (int) shall not
  // be changed
  gtkw = arg_get_value(t, "AUTO_ENABLE_NEW_PLUGINS");
  if(gtkw)
  {
    int iv = prefs_get_int(context, "auto_enable_new_plugins");
    if(iv)
      GTK_TOGGLE_BUTTON(gtkw)->active = TRUE;
    else
      GTK_TOGGLE_BUTTON(gtkw)->active = FALSE;
  }

  /* Host expansion options */
  t = arg_get_value(ctrls, "TARGET");
  gtk_entry_set_text(GTK_ENTRY(arg_get_value(t, "TARGET")),
      prefs_get_string(context, "targets"));
  v = arg_get_value(serv, "host_expansion");
  if(!v)
    flag |= EX_NONE;
  else
  {
    if(strstr(v, "dns"))
      flag = EX_DNS;
    if(strstr(v, "nfs"))
      flag |= EX_NFS;
    if(strstr(v, "none"))
      flag |= EX_NONE;
    if(strstr(v, "ip"))
      flag |= EX_IP;
  }

  if(!(flag & EX_NONE))
  {
    GtkWidget *w;

    w = arg_get_value(t, "DNS_EXPAND");
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), (flag & EX_DNS));
  }

  /* Scan options */
  t = arg_get_value(ctrls, "SCAN_OPTIONS");

  set_toggle_from_pref (t, "PING_HOSTS", serv, "ping_hosts");
  set_toggle_from_pref (t, "REVERSE_LOOKUP", serv, "reverse_lookup");
  set_toggle_from_pref (t, "OPTIMIZE_TEST", serv, "optimize_test");
  set_toggle_from_pref (t, "SAFE_CHECKS", serv, "safe_checks");
  set_toggle_from_pref (t, "USE_MAC_ADDR", serv, "use_mac_addr");

  v = arg_get_value(serv, "port_range");
  if(v)
  {
    gtkw = arg_get_value(t, "PORT_RANGE");
    if(gtkw)
      gtk_entry_set_text(GTK_ENTRY(gtkw), v);
  }

  set_toggle_from_pref (t, "UNSCANNED_CLOSED", serv, "unscanned_closed");

  gtkw = arg_get_value(t, "MAX_HOSTS");
  if(gtkw)
  {
    v = arg_get_value(serv, "max_hosts");
    if(v)
      gtk_spin_button_set_value (GTK_SPIN_BUTTON(gtkw), atof(v));
  }

  gtkw = arg_get_value(t, "MAX_CHECKS");
  if(gtkw)
  {
    v = arg_get_value(serv, "max_checks");
    if(v)
      gtk_spin_button_set_value (GTK_SPIN_BUTTON(gtkw), atof(v));
  }

  gtkw = arg_get_value(t, "CGI_PATH");
  if(gtkw)
  {
    v = arg_get_value(serv, "cgi_path");
    if(v)
      gtk_entry_set_text(GTK_ENTRY(gtkw), v);
  }

  /* User */
  fill_rules_list(context, arg_get_value(MainDialog, "USER"));

#ifdef ENABLE_SAVE_KB
  prefs_dialog_kb_set_prefs(arg_get_value(ctrls, "SAVE_KB"), context->prefs);
#endif
}

/**
 * @brief Sets tooltips for various GTK widgets hooked up in ctrls.
 *
 * @param ctrls Arglist with GTK widget hooked into.
 */
static void
prefs_dialog_set_tooltips (struct arglist *ctrls)
{
  struct arglist *t;
  GtkTooltips *tooltips;
  GtkWidget *w;

  tooltips = gtk_tooltips_new();
  arg_add_value(ctrls, "TOOLTIPS", ARG_PTR, -1, tooltips);

  t = arg_get_value(ctrls, "PLUGINS");
  w = arg_get_value(t, "ENABLE_DEPS_AT_RUNTIME");
  gtk_tooltips_set_tip(tooltips, w, HLP_ENABLE_DEPS_AT_RUNTIME, "");

  w = arg_get_value(t, "SILENT_DEPS");
  gtk_tooltips_set_tip(tooltips, w, HLP_SILENT_DEPS, "");

  w = arg_get_value(t, "AUTO_ENABLE_NEW_PLUGINS");
  gtk_tooltips_set_tip(tooltips, w, HLP_AUTO_ENABLE_NEW_PLUGINS, "");

  w = arg_get_value(t, "GLOBAL_NVT_TIMEOUT");
  gtk_tooltips_set_tip(tooltips, w, HLP_AUTO_GLOBAL_NVT_TIMEOUT, "");

  t = arg_get_value(ctrls, "TARGET");
  w = arg_get_value(t, "DNS_EXPAND");
  gtk_tooltips_set_tip(tooltips, w, HLP_HOST_EXPANSION_DNS, "");

  w = arg_get_value(t, "TARGET");
  gtk_tooltips_set_tip(tooltips, w, HLP_TARGET_PRIMARY_TARGET, "");

  w = arg_get_value(t, "READ_FROM_FILE");
  gtk_tooltips_set_tip(tooltips, w, HLP_TARGET_READ_FROM_FILE, "");


  t = arg_get_value(ctrls, "SCAN_OPTIONS");
  w = arg_get_value(t, "PING_HOSTS");
  gtk_tooltips_set_tip(tooltips, w, HLP_SCAN_OPT_PING, "");
  w = arg_get_value(t, "OPTIMIZE_TEST");
  gtk_tooltips_set_tip(tooltips, w, HLP_SCAN_OPT_OPTIMIZE, "");

  w = arg_get_value(t, "SAFE_CHECKS");
  gtk_tooltips_set_tip(tooltips, w, HLP_SCAN_OPT_SAFE_CHECKS, "");

  w = arg_get_value(t, "USE_MAC_ADDR");
  gtk_tooltips_set_tip(tooltips, w, HLP_SCAN_OPT_USE_MAC_ADDR, "");

  w = arg_get_value(t, "REVERSE_LOOKUP");
  gtk_tooltips_set_tip(tooltips, w, HLP_SCAN_OPT_REVERSE_LOOKUP, "");
  w = arg_get_value(t, "PORT_RANGE");
  gtk_tooltips_set_tip(tooltips, w, HLP_SCAN_OPT_PORT_RANGE, "");
  w = arg_get_value(t, "UNSCANNED_CLOSED");
  gtk_tooltips_set_tip(tooltips, w, HLP_UNSCANNED_CLOSED, "");

  w = arg_get_value(t, "MAX_HOSTS");
  gtk_tooltips_set_tip(tooltips, w, HLP_MISC_MAX_HOSTS, "");
  w = arg_get_value(t, "MAX_CHECKS");
  gtk_tooltips_set_tip(tooltips, w, HLP_MISC_MAX_CHECKS, "");
  w = arg_get_value(t, "CGI_PATH");

  gtk_tooltips_set_tip(tooltips, w, HLP_CGI_PATH, "");
  // FIXME suspect tooltip for following item is missing:
  t = arg_get_value(ctrls, "USER");
  gtk_tooltips_enable(tooltips);
}


/**
 * @brief Sets a string in a preference arglist as either "yes" or "no",
 * @brief depending on the state (active -> "yes") of a togglebutton.
 * 
 * @param preferences  Servers preference arglist.
 * @param togglebutton A gtk_toggle_button, of which the state will decide the
 *                     preference value (active -> "yes").
 * @param preference_name Key for the value in the preference arglist.
 */
static void
set_yesno_pref_from_toggle (struct arglist* preferences, GtkWidget* togglebutton,
                            char* preference_name)
{
 if(togglebutton)
  {
    char *value;

    if(GTK_TOGGLE_BUTTON(togglebutton)->active)
      value = estrdup("yes");
    else
      value = estrdup("no");

    if(arg_get_value(preferences, preference_name))
      arg_set_value(preferences, preference_name, strlen(value), value); /* RATS: ignore */
    else
      arg_add_value(preferences, preference_name, ARG_STRING, 
                    strlen(value), value); /* RATS: ignore */
  }
}


/**
 * @brief Applies user choices to a context (and its preferences etc.).
 * 
 * @param context The context to manipulate
 * @param ctrls   Arglist with all the GTK widgets hooked in.
 */
void
prefs_dialog_apply (struct context *context, struct arglist *ctrls)
{
  struct arglist *prefs;
  struct arglist *serv;
  struct arglist *t;
  char expansion[30];
  char *s;
  GtkWidget *gtkw;

  /* Save comment to preferences */
  store_comment(context, arg_get_value(ctrls, "COMMENT"));

  if(context->type == CONTEXT_TASK || context->type == CONTEXT_REPORT)
    return;

  /*
   * FIXME:
   * Only try to save values if GTK widgets were changed.
   * Otherwise prefs_dialog_set_defaults can't set default
   * values from server. */

  bzero (expansion, 30);
  prefs = context->prefs;
  serv = arg_get_value(prefs, "SERVER_PREFS");
  if(!serv)
  {
    serv = emalloc(sizeof(struct arglist));
    arg_add_value(prefs, "SERVER_PREFS", ARG_ARGLIST, -1, serv);
  }

  t = arg_get_value(ctrls, "PLUGINS");

  gtkw = arg_get_value(t, "ENABLE_DEPS_AT_RUNTIME");
  set_yesno_pref_from_toggle(serv, gtkw, "auto_enable_dependencies");

  gtkw = arg_get_value(t, "SILENT_DEPS");
  set_yesno_pref_from_toggle(serv, gtkw, "silent_dependencies");

  gtkw = arg_get_value(t, "GLOBAL_NVT_TIMEOUT");
  s = g_strdup (gtk_entry_get_text(GTK_ENTRY(gtkw)));

  if(arg_get_value(serv, "plugins_timeout"))
    arg_set_value(serv, "plugins_timeout", strlen(s), s);
  else
    arg_add_value(serv, "plugins_timeout", ARG_STRING, strlen(s), s);

  gtkw = arg_get_value(t, "AUTO_ENABLE_NEW_PLUGINS");
  if(gtkw)
  {
    if(GTK_TOGGLE_BUTTON(gtkw)->active)
      prefs_set_int(context,"auto_enable_new_plugins", 1);
    else
      prefs_set_int(context,"auto_enable_new_plugins", 0);
  }

  /* Host expansion */
  t = arg_get_value(ctrls, "TARGET");
  gtkw = arg_get_value(t, "DNS_EXPAND");
  if(GTK_TOGGLE_BUTTON(gtkw)->active)
    strcat (expansion, "dns;");

  strcat(expansion, "ip;");

  if (!strlen(expansion))
    strncpy (expansion, "none;", 5);
  expansion[strlen(expansion) - 1] = 0;

  s = (char *)gtk_entry_get_text(GTK_ENTRY(arg_get_value(t, "TARGET")));
  prefs_set_string(context, "targets", s);

  s = emalloc(strlen(expansion) + 1);
  strncpy(s, expansion, strlen(expansion));

  if(arg_get_value(serv, "host_expansion"))
    arg_set_value(serv, "host_expansion", strlen(s), s);
  else
    arg_add_value(serv, "host_expansion", ARG_STRING, strlen(s), s);


  /*
   * Scan options
   */
  t = arg_get_value(ctrls, "SCAN_OPTIONS");
  gtkw = arg_get_value(t, "PING_HOSTS");
  set_yesno_pref_from_toggle(serv, gtkw, "ping_hosts");


  gtkw = arg_get_value(t, "REVERSE_LOOKUP");
  set_yesno_pref_from_toggle(serv, gtkw, "reverse_lookup");

  gtkw = arg_get_value(t, "OPTIMIZE_TEST");
  set_yesno_pref_from_toggle(serv, gtkw, "optimize_test");

  gtkw = arg_get_value(t, "SAFE_CHECKS");
  set_yesno_pref_from_toggle(serv, gtkw, "safe_checks");

  gtkw = arg_get_value(t, "USE_MAC_ADDR");
  set_yesno_pref_from_toggle(serv, gtkw, "use_mac_addr");

  t = arg_get_value(ctrls, "SCAN_OPTIONS");
  gtkw = arg_get_value(t, "PORT_RANGE");
  s = estrdup (gtk_entry_get_text(GTK_ENTRY(gtkw)));

  if(arg_get_value(serv, "port_range"))
    arg_set_value(serv, "port_range", strlen(s), s);
  else
    arg_add_value(serv, "port_range", ARG_STRING, strlen(s), s);

  gtkw = arg_get_value(t, "UNSCANNED_CLOSED");
  set_yesno_pref_from_toggle(serv, gtkw, "unscanned_closed");

  gtkw = arg_get_value(t, "MAX_HOSTS");

  s = estrdup (gtk_entry_get_text(GTK_ENTRY(gtkw)));

  if(arg_get_value(serv, "max_hosts"))
    arg_set_value(serv, "max_hosts", strlen(s), s);
  else
    arg_add_value(serv, "max_hosts", ARG_STRING, strlen(s), s);


  gtkw = arg_get_value(t, "MAX_CHECKS");
  s = g_strdup (gtk_entry_get_text(GTK_ENTRY(gtkw)));

  if(arg_get_value(serv, "max_checks"))
    arg_set_value(serv, "max_checks", strlen(s), s);
  else
    arg_add_value(serv, "max_checks", ARG_STRING, strlen(s), s);

  gtkw = arg_get_value(t, "CGI_PATH");
  s = estrdup((char *)gtk_entry_get_text(GTK_ENTRY(gtkw)));


  if(arg_get_value(serv, "cgi_path"))
    arg_set_value(serv, "cgi_path", strlen(s), s);
  else
    arg_add_value(serv, "cgi_path", ARG_STRING, strlen(s), s);

#ifdef ENABLE_SAVE_KB
  t = arg_get_value(ctrls, "SAVE_KB");
  prefs_dialog_kb_get_prefs(context, t);
#endif


  /* Client-side User Access Rules
   * Get them out of the USRER->RULES_TREE and push them into
   * context->prefs->CLIENTSIDE_USERRULES */
  t = arg_get_value(ctrls, "USER");
  gtkw = arg_get_value(t, "RULES_TREE");
  if (gtkw)
  {
    GtkTreeModel * store;
    GtkTreePath * path;
    GtkTreeIter iter;
    int n = 0;
    char * rule, * name = NULL;
    struct arglist * clientside_userrules;

    /* First of all, remove the old stuff */
    clientside_userrules = emalloc(sizeof(struct arglist));
    if (arg_get_value(prefs, "CLIENTSIDE_USERRULES"))
    {
      arg_free_all(arg_get_value(prefs, "CLIENTSIDE_USERRULES"));
      arg_set_value(prefs, "CLIENTSIDE_USERRULES", -1, clientside_userrules);
    } else
      arg_add_value(prefs, "CLIENTSIDE_USERRULES", ARG_ARGLIST, -1,
                    clientside_userrules);

    store = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkw));

    /* Go to the third entry */
    path = gtk_tree_path_new_from_string("2:0");
    if (gtk_tree_model_get_iter(store, &iter, path))
    {
      do {
        gtk_tree_model_get(store, &iter, 0, &rule, -1);

        name = emalloc(20);
        sprintf(name, "%d", n);
        arg_add_value(clientside_userrules, name, ARG_STRING,
                      strlen(rule), rule);
        n ++;
      } while (gtk_tree_model_iter_next(store, &iter));
    }
  }
}

/**
 * @brief Creates a string from plugin preference radiobuttons.
 * 
 * @param list Value of arg_get_value(pref->value, "RADIOBUTTONS)
 * @param pref The plugin preference
 * 
 * @returns Plugin preference string for a radiobutton selection.
 */
static char*
get_plugin_radio_pref (GSList* list, struct arglist* pref)
{
  char* value = NULL;
  /* First pass: find the active entry */
  while (list)
  {
    GtkWidget *button = list->data;

    if (GTK_TOGGLE_BUTTON(button)->active)
    {
      value = estrdup(gtk_object_get_data(GTK_OBJECT(button), "name"));
      break;
    }
    list = list->next;
  }
  /* Second pass: find all other entries and append them separated with ";" */
  list = arg_get_value(pref->value, "RADIOBUTTONS");
  while (list)
  {
    GtkWidget *button = list->data;

    if (! GTK_TOGGLE_BUTTON(button)->active)
    {
      char * v = gtk_object_get_data(GTK_OBJECT(button), "name");
      value = (char *) erealloc((void *)value, (size_t) (strlen(value) + strlen(";") + strlen(v) + 1));
      strcat(value, ";");
      strcat(value, v);
    }
    list = list->next;
  }
  return value;
}


/**
 * @brief Applies the input from the plugins preferences widgets to the arglists.
 * 
 * Is currently called when an attack is started and when the user deselects
 * a scope (e.g. by selecting a different one).
 * XXX Warning:
 * saves to context->plugins and context->scanners,
 * NOT to context->prefs["PLUGINS_PREFS"]
 * 
 * @param plugins List of plugins whose preferences to modify.
 */
void
prefs_dialog_apply_plugin_prefs (struct nessus_plugin *plugins)
{
  while(plugins!= NULL )
  {
    struct arglist *pref;
    char *type  = NULL;
    char *value = NULL;

    if((pref = plugins->plugin_prefs) != NULL )
      while(pref && pref->next)
      {
	if((type = (char *)arg_get_value(pref->value, "type")))
	{
	  if(!strcmp(type, PREF_ENTRY) ||
	      !strcmp(type, PREF_FILE) || !strcmp(type, PREF_PASSWORD))
	  {
	    GtkWidget *entry = arg_get_value(pref->value, "ENTRY");

	    if(entry)
	    {
	      value = (char *)gtk_entry_get_text(GTK_ENTRY(entry));
	      arg_set_value(pref->value, "value", strlen(value),
		  estrdup(value));
	    }
	  }
	  else if(!strcmp(type, PREF_CHECKBOX))
	  {
	    GtkWidget *button = arg_get_value(pref->value, "CHECKBOX");

	    if(button)
	    {
	      char *value =
		  GTK_TOGGLE_BUTTON(button)->active ? "yes" : "no";
	      arg_set_value(pref->value, "value", strlen(value), estrdup(value)); /* RATS: ignore , value is yes or no and nul- terminated */
	    }
	  }
	  else if(!strcmp(type, PREF_RADIO))
	  {
            GSList *list = NULL;
            char * value = NULL;

            list = arg_get_value(pref->value, "RADIOBUTTONS");

            if (list)
            {
              value = get_plugin_radio_pref(list, pref);
            }
            if(value)
              arg_set_value(pref->value, "value", strlen(value), value);
	  }
          else if (!strcmp(type, PREF_SSH_CREDENTIALS))
          {
            // Workaround to trigger display of this NVT (otherwise invisible 
            // when not connected)
            arg_set_value(pref->value, "value", strlen("ignored"), "ignored"); /* RATS: ignore string literals are nul terminated */
          }
	}
	pref = pref->next;
      }
    plugins = plugins->next;
  }
}


/**
 * @brief To execute, first all preferences (user choices) are applied.
 * 
 * Function acts as a callback for menu items and button.
 * 
 * @return Always 0.
 */
int
prefs_dialog_execute (GtkWidget* w, struct arglist* ctrls)
{
  struct context *context = context_by_type(Context, CONTEXT_SCOPE);
  char *hostname;

  prefs_context_update(context);
  prefs_dialog_apply(context, ctrls);
  prefs_dialog_apply_plugin_prefs(context->plugins);
  prefs_dialog_apply_plugin_prefs(context->scanners);
  context_sync_plugin_prefs(context);

  /* Check for the errors */
  if(!prefs_dialog_auth_connection(context))
    return (0);

  /* If the target is a file, then translate it */
  hostname = target_translate(prefs_get_string(context, "targets"));

  if(hostname == NULL || hostname[0] == '\0')
  {
    show_error(_("You must enter the name or IP of the target(s)\n\
to attack in the 'Target' section."));
    return (0);
  }

  monitor_dialog_setup (hostname, context);

  return (0);
}
#endif
