/* OpenVAS-Client
 * $Id$
 * Description: GUI handling for NVT preference "sshlogins".
 *
 * Author(s):
 * Felix Wolfsteller <felix.wolfsteller@intevation.de>
 *
 * Copyright:
 * Copyright (C) 2008 Intevation GmbH
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2,
 * or, at your option, any later version 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * In addition, as a special exception, you have
 * 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.
 */

/**
 * @file
 * Functions for adding / updating GTK Widgets that deal with user interaction
 * for a NVTS "sshlogins" preference.
 */

#ifdef USE_GTK

#include <gtk/gtk.h>
#include "glib.h"

#include "nvt_pref_sshlogin.h"

#include "arglists.c"
#include "context.h"
#include "comm.h" // for PREF_SSH_CREDENTIALS only
#include "error_dlg.h"
#include "hash_table_file.h"
#include "nessus_i18n.h"
#include "nessus_plugin.h"
#include "read_target_file.h"
#include "ssh_key_info_form.h"
#include "ssh_keys_dialog.h"

/**
 * Key in arglists to access the GtkTable widget that allows the user to modify
 * a PREF_SSH_CREDENTIALS preference of a plugin.
 * Note that the same widget is in contrast to other preference guis also
 * hardlinked" in Context->gui_sshlogins_per_target.
 */
#define GUI_KEY_NVT_PREF_SSHLOGIN_GTKTABLE "SSHLOGINSTABLE"

/**
 * Access to the currently active Scope- GUI- arglist.
 */
extern struct arglist* MainDialog;


/**
 * @brief Returns true if str contains at least one '*' or '?'.
 * 
 * @param str String that is understood to be a hostname or pattern.
 * 
 * @return TRUE if str is understood to be a pattern (contains at least one '?'
 *         or '*').
 */
static gboolean
is_pattern (const char* str)
{
  return ( str != NULL
           &&  (strchr (str, '*') != NULL || strchr (str, '?') != NULL)
         );
}

/**
 * Helper function to set the active text of a combobox that has been 
 * initialized with gtk_combobox_new_text().
 * If value is not in the list of combobox entries, the first entry will be
 * set to be the active one.
 * 
 * @param combobox GtkComboBox to manipulate.
 * @param value    String of the active-item-to-be. If NULL, the first item will
 *                 be selected.
 */
void
text_combobox_set_active_text (GtkWidget* combobox, char* value)
{
  GtkTreeIter iter;
  gboolean valid;
  int idx = -1;
  
  GtkTreeModel* treemdl = gtk_combo_box_get_model (GTK_COMBO_BOX(combobox));
  valid = gtk_tree_model_get_iter_first (treemdl, &iter);
  if (value == NULL)
    {
      valid = FALSE;
      idx = 0;
    }
  
  // Find the right item.
  while (valid)
  {
    char* entry;
    idx++;
    gtk_tree_model_get (treemdl, &iter, 0, &entry, -1);
    valid = gtk_tree_model_iter_next (treemdl, &iter);
    // If text is the text we want to be active, make it active and return.
    if (strcmp(entry, value) == 0)
      {
        break;
      }
    // If that was the last item, we apparently havent found any match
    if (valid == FALSE)
      idx = 0;
  }
  
  gtk_combo_box_set_active (GTK_COMBO_BOX(combobox), idx);
}

/**
 * @brief Callback when the selection of a combobox showing ssh logins changed.
 * 
 * Updates the Contexts map target->sshlogins.
 * 
 * @param combobox Combobox whose selection changed.
 * @param target   Target name (key in Context->map_target_sshlogin).
 */
static void
sshlogin_selected_cb (GtkWidget* combobox, char* target)
{
  // TODO Find a solution for the Global Setting scenario: (location of .host_logins, copy mapping when new task is created etc.)
  // Do nothing but warn user when Global settings are affected
  if (Context->type == CONTEXT_GLOBAL)
    {
      show_warning (_("Changes in the per-target sshlogin selection done in the Global Settings have no effect.\nPlease update your scopes individually."));
      return;
    }

  if (combobox == NULL || target == NULL)
    return;

  char* login_name = gtk_combo_box_get_active_text (GTK_COMBO_BOX (combobox));
  g_hash_table_insert (Context->map_target_sshlogin, g_strdup(target), login_name);

  // FIXME: Following (saving the map) only needs to be done when client is quit/killed.
  // Should be moved to quit() function or signal handler, once that part got repaired.
  char* fileloc = g_build_filename (Context->dir, ".host_sshlogins", NULL);
  gboolean success = hash_table_file_write (Context->map_target_sshlogin, fileloc);
  if (success == FALSE)
    show_warning (_("Could not update Login selection per target - file.\n"));
  efree (&fileloc);
}

/**
 * @brief Callback to add a key from a GHashTable to a Combobox.
 * 
 * @param key Will be added to combobox.
 * @param value --ignored-- (callback)
 */
static void
add_key_to_combobox_cb (char* key, gpointer value, GtkWidget* combobox)
{
  gtk_combo_box_append_text (GTK_COMBO_BOX(combobox), key);
}


/**
 * @brief Asks the user to confirm deletion of a pattern and does so if confirmed.
 */
static void
remove_pattern (GtkWidget* signal_emitter, char* pattern)
{
  GtkWidget* dialog = NULL;
  gint response;
  
  dialog = gtk_message_dialog_new (NULL,
                                   GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
                                   GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
                                   _("Delete pattern '%s'?"), pattern);
  response = gtk_dialog_run (GTK_DIALOG(dialog));
  if ( response == GTK_RESPONSE_YES)
    {
      g_hash_table_remove (Context->map_target_sshlogin, pattern);
      nvt_pref_sshlogin_rebuild_gui (NULL, NULL);
    }
  // else user does not want to delete the pattern, nothing to do.
  gtk_widget_destroy (dialog);
}

/**
 * @brief Displays dialog that allows user to enter a pattern and select a login
 * @brief for it.
 * 
 * Callback for 'Add pattern' button.
 * 
 * @param signal_emitter Usually the button (callback).
 * @param ignored        ignored (callback).
 */
static void
prompt_new_pattern (GtkWidget* signal_emitter, gpointer ignored)
{
  GtkWidget* dialog           = NULL;
  GtkWidget* patterntextfield = NULL;
  GtkWidget* content_box      = NULL;
  GtkWidget* content_area     = NULL;
  GtkWidget* content_vbox     = NULL;
  GtkWidget* combobox         = NULL;
  GtkWidget* text             = NULL;
  gboolean sane               = FALSE;
  gint response               = GTK_RESPONSE_NONE;
  GtkWidget *context_window   = arg_get_value(MainDialog, "CONTEXT");

  // Create dialog
  dialog = gtk_dialog_new_with_buttons ("Enter pattern for hostname",
                                        GTK_WINDOW(context_window),
                                        GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                        GTK_STOCK_OK, GTK_RESPONSE_OK, NULL
                                        );

  // Label // text
  text = gtk_label_new (_("Please enter a pattern (it has to contain * or ?)\n"
                          "for hostnames and assign a login to it.\nYou can "
                          "still change the assignment later.\nThe "
                          "pattern will be matched against hostnames or\n"
                          "target IPs as specified in the 'Target selection'"
                          " section.\n\nFor example:\n'192.168.15.*' matches "
                          "'192.168.15.7' but not 'myserver',\n'*' "
                          "matches everything."
                         ));

  patterntextfield = gtk_entry_new ();
  content_box  = gtk_hbox_new (FALSE, 10);
  content_vbox = gtk_vbox_new (FALSE, 10);
  content_area = GTK_DIALOG(dialog)->vbox;

  // Create Combobox with SSH-Logins
  combobox = gtk_combo_box_new_text ();
  gtk_combo_box_append_text (GTK_COMBO_BOX(combobox), NO_SSH_LOGIN_SELECTED);
  gtk_combo_box_set_active  (GTK_COMBO_BOX(combobox), 0);
  if(Global->sshkeys != NULL)
    {
      // TODO: If entries should be added sorted, we can generate a list of keys
      // (either update gtk or generate by hand) or consistently use a treemodel
      g_hash_table_foreach(Global->sshkeys, (GHFunc) add_key_to_combobox_cb, combobox);
    }

  // Assemble and show
  gtk_container_add (GTK_CONTAINER (content_vbox), content_box);
  gtk_container_add (GTK_CONTAINER (content_vbox), text);
  gtk_container_add (GTK_CONTAINER (content_box),  patterntextfield);
  gtk_container_add (GTK_CONTAINER (content_box),  combobox);
  gtk_container_add (GTK_CONTAINER (content_area), content_vbox);
  gtk_widget_show_all (dialog);

  // Run the dialog (until user cancels, closes or enters a valid pattern)
  while (sane == FALSE && response != GTK_RESPONSE_CANCEL)
    {
      response = gtk_dialog_run (GTK_DIALOG(dialog));

      if (response == GTK_RESPONSE_OK)
        {
          // Sanity check
          sane =  is_pattern (gtk_entry_get_text (GTK_ENTRY(patterntextfield)));

          // Check if pattern is just '*' (bad) or insane
          // NOTE: Some window managers seem to be confusable by two with the
          // same parent (a second modal dialog does not block the first one)
          // Solution: change show_warning to accept a parent as argument.
          if (sane == TRUE && 
              !strcmp(gtk_entry_get_text (GTK_ENTRY(patterntextfield)), "*"))
            {
              show_warning (_("Pattern matches everything. Use the 'Default' target instead."));
              sane = TRUE;
              continue;
            }
          else if (sane == FALSE)
            {
              show_warning (_("Pattern does not contain '*' or '?'"));
              continue;
            }

          // Add new mapping to hashtable
          g_hash_table_insert (Context->map_target_sshlogin, g_strdup(gtk_entry_get_text (GTK_ENTRY(patterntextfield))),
                              g_strdup(gtk_combo_box_get_active_text (GTK_COMBO_BOX (combobox))));
          nvt_pref_sshlogin_rebuild_gui (NULL, NULL);
        }
      else // just throw it away
        {
          break;
        }
    }

  gtk_widget_destroy (dialog);
}

/**
 * @brief In a g_hash_table_foreach inserts copies of patterns from one hash
 *        table into another.
 * 
 * @param key   Key string (if pattern, key-value pair will be copied).
 * @param value Value.
 * @param dest  Destination hash table (to copy in).
 */
void
copy_pattern (char* key, char* value, GHashTable* dest)
{
  if (is_pattern (key) == TRUE)
    g_hash_table_insert (dest, g_strdup (key), g_strdup (value));
}


/**
 * @brief Adds label (target) and combobox (sshlogin name) to a row of a
 *        GtkTable.
 * 
 * The GtkTable will usually be a contexts ssh-per-target GUI.
 * If the target label contains a pattern, a button will be added, which will
 * remove the pattern from gui and memory if clicked.
 * 
 * @param target Target name.
 * @param login  User-defined name of login.
 * @param rowid_guitable GPointerArray containing the index(int) of the row to
 *                       add content to (will be increased) and the table itself.
 */
static void
add_host_login_row (char* target, char* login, GPtrArray* rowidx_guitable)
{
  GtkWidget* targetbox = NULL;
  GtkWidget* label     = gtk_label_new (target);
  GtkWidget* combobox  = gtk_combo_box_new_text ();
  gtk_combo_box_append_text (GTK_COMBO_BOX(combobox), NO_SSH_LOGIN_SELECTED);
  gtk_combo_box_set_active  (GTK_COMBO_BOX(combobox), 0);
  int* rowidx          = g_ptr_array_index (rowidx_guitable, 0);
  GtkWidget* guitable  = g_ptr_array_index (rowidx_guitable, 1);
  
  // Build combobox
  if(Global->sshkeys != NULL)
    {
      // TODO: If entries should be added sorted, we can generate a list of keys
      // (either update gtk or generate by hand) or consistently use a treemodel
      g_hash_table_foreach(Global->sshkeys, (GHFunc) add_key_to_combobox_cb, combobox);
      //text_combobox_set_active_text(lcombobox, value);
    }
  
  // Patterns need a delete button, so pack them in a box
  if (is_pattern (target) == TRUE)
    {
      targetbox = gtk_hbox_new (FALSE, 5);
      GtkWidget* del_icon =  gtk_image_new_from_stock(GTK_STOCK_DELETE, GTK_ICON_SIZE_BUTTON);
      GtkWidget* delpatternbutton = gtk_button_new ();
      gtk_button_set_image (GTK_BUTTON(delpatternbutton), del_icon);
      gtk_box_pack_start_defaults (GTK_BOX(targetbox), delpatternbutton);
      gtk_box_pack_end_defaults (GTK_BOX(targetbox), label);
      g_signal_connect (GTK_OBJECT(delpatternbutton), "clicked",
                    (GtkSignalFunc) remove_pattern, g_strdup(target));
    }

  // Add the label if target is hostname, targetbox if target is pattern
  if (targetbox == NULL)
    gtk_table_attach (GTK_TABLE (guitable), label, 0, 1,
                      (*rowidx), (*rowidx)+1, GTK_EXPAND, GTK_SHRINK, 5, 5);
  else
    gtk_table_attach (GTK_TABLE (guitable), targetbox, 0, 1,
                      (*rowidx), (*rowidx)+1, GTK_EXPAND, GTK_SHRINK, 5, 5);

  gtk_widget_show (combobox);
  gtk_table_attach (GTK_TABLE (guitable), combobox, 1, 2,
                      (*rowidx), (*rowidx)+1, GTK_EXPAND, GTK_SHRINK, 5, 5);
  
  text_combobox_set_active_text (combobox, login);

  g_signal_connect (GTK_OBJECT(combobox), "changed",
                    (GtkSignalFunc) sshlogin_selected_cb, g_strdup(target));

  (*rowidx)++;
}

/**
 * @brief Rebuilds all sshlogin GUIS in scopes under context ctx.
 * 
 * Calls nvt_pref_sshlogin_rebuild_gui for all context under (children) or
 * nexto to (next) the parameter ctx (recursively).
 * 
 * @param ctx   Context to inspect (including children and nexts).
 */
void
nvt_pref_sshlogin_rebuild_all (struct context* ctx)
{
  if (ctx == NULL)
    return;

  // Look in all Scopes + Global
  while (ctx && ctx->type < CONTEXT_REPORT)
    {
      nvt_pref_sshlogin_rebuild_all (ctx->children);

      if (ctx->type == CONTEXT_SCOPE || ctx->type == CONTEXT_GLOBAL)
        {
          nvt_pref_sshlogin_rebuild_gui (NULL, ctx);
        }
      ctx = ctx->next;
    }
}

/**
 * @brief Rebuilds the GUI of the context ctx or sets it up of if it does
 * @brief not exist yet.
 * 
 * Rebuilds the table with hostnames and sshlogin- comboboxes and selects the
 * entries to match those in context->map_targets_sshlogins.
 * The latter will be updated according to the target string (if not NULL).
 * 
 * Eventual content will be removed first, so that this function might be 
 * called to rebuilt the gui when the target definition might have changed.
 * 
 * When the targets parameter is NULL, the GUI will be rebuilt to match the
 * entries in the contexts map_target_sshlogin.
 * 
 * @param targets String of comma-separated targets or NULL to rebuild from
 *                content of Context->map_target_sshlogin.
 * 
 * @param ctx     Context which's GUI to rebuild/ create. If NULL, Current 
 *                context will be selected.
 */
void
nvt_pref_sshlogin_rebuild_gui (const char* targets, struct context* context)
{
  if (context == NULL)
    context = Context;
  GtkTable*   gui_table = context->gui_sshlogins_per_target;
  GHashTable* old_map   = NULL;
  GHashTable* new_map   = NULL;
  GList* tablecontent   = NULL;
  gchar** targets_strv  = NULL;
  gchar** targets_list  = NULL;
  int n_entry           = 0;
  GPtrArray* rowidx_guitable;
  
  if (gui_table == NULL)
    return;
  
  // First, clear GUI, remove any element in table
  tablecontent = gtk_container_get_children (GTK_CONTAINER (gui_table));
  while (tablecontent != NULL)
    {
      gtk_container_remove (GTK_CONTAINER (gui_table), tablecontent->data);
      tablecontent = g_list_next (tablecontent);
    }

  // If the Contexts mapping has to be replaced, merge old and new mapping.
  if (targets != NULL)
    {
      // Sync the Contexts map with the new targets.
      old_map = context->map_target_sshlogin;
      if (old_map == NULL)
        old_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
    
      // Sync keys in contexts Hash Table with targets
      targets_strv = g_strsplit (targets, ",", 0);
      targets_list = targets_strv;
      new_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
      // Add all targets and set value, if it was set already
      while ( (*targets_list) && strcmp((*targets_list),"") != 0 )
        {
          char* selected_login = g_hash_table_lookup (old_map, (*targets_list));
          if (selected_login == NULL)
            selected_login = NO_SSH_LOGIN_SELECTED;
          g_hash_table_insert (new_map, estrdup(*targets_list), estrdup(selected_login));
          ++(targets_list);
        }
      // Add patterns if any
      g_hash_table_foreach (old_map, (GHFunc) copy_pattern, new_map);
      // Replace Contexts hashtable
      context->map_target_sshlogin = new_map;
      g_hash_table_destroy (old_map);
    }
  else /* No replacement of mapping needed */
    {
      new_map = context->map_target_sshlogin;
    }
  
  // Repopulate table with children and do the selection
  rowidx_guitable = g_ptr_array_new ();
  g_ptr_array_add (rowidx_guitable, (gpointer) &n_entry);
  g_ptr_array_add (rowidx_guitable, (gpointer) gui_table);
  g_hash_table_foreach (new_map, (GHFunc) add_host_login_row, rowidx_guitable);
  g_ptr_array_free (rowidx_guitable, TRUE);

  // Add "pattern button", give it an icon.
  GtkWidget* addpatternbutton = gtk_button_new_with_label(_("Add pattern"));
  GtkWidget* add_icon;
  add_icon = gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
  gtk_button_set_image (GTK_BUTTON(addpatternbutton), add_icon);
  gtk_table_attach (GTK_TABLE (context->gui_sshlogins_per_target), addpatternbutton, 1, 2,
                    (n_entry), (n_entry)+1, GTK_EXPAND, GTK_SHRINK, 5, 5);

  // Connect button signals
  g_signal_connect (addpatternbutton, "clicked", (GtkSignalFunc) prompt_new_pattern,
                    NULL);

  if(targets_strv!= NULL)
    g_strfreev(targets_strv);

  // Problem was: 'hiding' tables if the table to modify is not visible until
  // resize of the window.
  // Did not find another solution than queuing a resize of the pref area -- felix .
  gtk_widget_show_all (GTK_WIDGET(gui_table));
  gtk_widget_queue_resize (gtk_widget_get_parent (gtk_widget_get_parent (GTK_WIDGET(gui_table))));
}

/**
 * @brief To be used as a GHFunc to ask if a hashtable contains a certain value.
 * 
 * Becomes obsolete with GLib >= 2.12, which defines iterators over hash table
 * values.
 *
 * @return TRUE if value equals constvalue.
 */
static gboolean
str_hash_table_has_value (char* key, char* value, char* constvalue)
{
  return !strcmp (value, constvalue);
}

/**
 * @brief Checks whether a ssh account is selected as login for any target.
 * 
 * @param ctx   Context to inspect (including children and nexts).
 * @param login The login to search in any contexts map_target_sshlogins.
 * 
 * @return TRUE if any map_targets_sshlogins contains login_name as a value.
 */
gboolean
nvt_pref_sshlogin_is_in_use (struct context* ctx, char* login_name)
{
  if (ctx == NULL || login_name == NULL)
    return FALSE;

  // Look in all Scopes + Global
  while (ctx && ctx->type < CONTEXT_REPORT)
    {
      gboolean in_use = nvt_pref_sshlogin_is_in_use (ctx->children, login_name);

      // "Early" stop
      if (in_use == TRUE)
        return TRUE;

      if (ctx->type == CONTEXT_SCOPE || ctx->type == CONTEXT_GLOBAL)
        {
          // Get the ssh per-target gui of this context
          GHashTable* map = ctx->map_target_sshlogin;

          // Slowly search value (a g_hash_table_get_values exists in GLib >= 2.12)
          if ( map  != NULL 
               && g_hash_table_find (map, (GHRFunc) str_hash_table_has_value, login_name) != NULL)
            return TRUE;
        }
      ctx = ctx->next;
    }

  return FALSE;
}

/**
 * @brief Adds an entry to all the Comboboxes showing SSH keys.
 * 
 * To do this, all "next" and child contextes of ctx are recursively touched.
 * If a plugin had a ssh_credentials preferences, the contexts 
 * gui_sshlogins_per_target will be set, which can be searched for comboboxes
 * that show sshlogins.
 * 
 * @param ctx Context to start looking for plugins with ssh_credentials preference.
 * @param newentry Text to add (should be key of ctx's sshkeys hash table).
 * @see context.sshkeys
 * @see context.gui_sshlogins_per_target
 */
void
nvt_pref_sshlogin_update_all_comboboxes (struct context* ctx, char* newentry)
{
  if (ctx == NULL || newentry == NULL)
    return;

  // Look in all Scopes + Global
  while (ctx && ctx->type < CONTEXT_REPORT)
    {
      nvt_pref_sshlogin_update_all_comboboxes (ctx->children, newentry);

      if (ctx->type == CONTEXT_SCOPE || ctx->type == CONTEXT_GLOBAL)
        {
          // Get the ssh per-target gui of this context
          GtkTable* table = ctx->gui_sshlogins_per_target;
          GList* children = NULL;

          // If no interest in ssh logins in this context, search other contexts.
          if (table != NULL)
            children = g_list_last (table->children);

          // Retrieve every other children (combobox)
          // List starts with a label, skip it!
          if (children != NULL)
            children = children->prev;
          while (children != NULL)
            {
              GtkTableChild* child = (GtkTableChild*) children->data;
              GtkWidget* childwidget = child->widget;

              // Append the new item
              gtk_combo_box_append_text (GTK_COMBO_BOX(childwidget), newentry);

              // Ignore the next label (we just want comboboxes)
              children = children->prev;
              if (children != NULL)
                children = children->prev;
            } /* while (children) */

        }
      ctx = ctx->next;
    }
}

/**
 * @brief Function to add a "ssh-credentials" area that allows the user to 
 *        select a ssh key for each target.
 * 
 * Adds a table with a label and a combobox for each target (plus a "Default"
 * entry) in each row.
 * The combobox shows the options of ssh keys managed by the OpenVAS ssh key
 * manager, the label indicates the target.
 * The table will be added to the pref arglist under the key
 * GUI_KEY_NVT_PREF_SSHLOGIN_GTKTABLE.
 * Furthermore it will be set as the gui_sshlogins_per_target of the current
 * context.
 * 
 * @param vbox Box where to add the widgets to.
 * @param pref Arglist into which to hook the widgets.
 */
void
nvt_pref_sshlogin_add (GtkWidget* vbox, struct arglist* pref)
{
  GtkWidget* frame;
  GtkWidget* host_key_table;
  struct arglist* targets_gui;
  
  frame = gtk_frame_new (_("Per-host SSH Key Selection"));
  host_key_table = gtk_table_new (2, 2, FALSE);
  
  gtk_box_pack_start_defaults (GTK_BOX(vbox), frame);
  gtk_container_add (GTK_CONTAINER (frame), host_key_table);
  gtk_widget_show_all (frame);
  
  // Link the table in Context and in the preference arglist.
  arg_add_value (pref->value, GUI_KEY_NVT_PREF_SSHLOGIN_GTKTABLE, ARG_PTR, -1,
                 host_key_table);
  Context->gui_sshlogins_per_target = GTK_TABLE (host_key_table);
  
  // If showing the GUI for this time the first time ever, fetch target
  // definition from 'Targets' GUI, otherwise from memory
  if (Context->map_target_sshlogin == NULL ||
      g_hash_table_size (Context->map_target_sshlogin) == 0)
    {
      targets_gui = arg_get_value (MainDialog, "TARGET");
      const char* targets_text = gtk_entry_get_text (GTK_ENTRY(arg_get_value(targets_gui, "TARGET")));

      // Add a "Default" entry
      const char* targets = g_strconcat ("Default,", target_translate (targets_text), NULL);
      // Build the Hash- and GUI table for the first time
      nvt_pref_sshlogin_rebuild_gui (targets, NULL);
    }
  else
    // Create, populate the table and restore the selection from Hash Table
    nvt_pref_sshlogin_rebuild_gui (NULL, NULL);
}
#endif /* USE_GTK */
