/* OpenVAS-Client
 * $Id$
 * Description: The OpenVAS SSH Key Manager dialog.
 *
 * Authors:
 * 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.
 */

#include <includes.h>
#include "nessus_i18n.h"

#ifdef USE_GTK
#include <gtk/gtk.h>
#include "error_dlg.h"
#include "listnotebook.h"
#include "openvas_ssh_login.h"
#include "preferences.h"
#include "nvt_pref_sshlogin.h"
#include "ssh_keys_dialog.h"
#include "openvas_lsc_target_prep.h"
#include "openvas_lsc_user_deb.h"
#include "openvas_lsc_user_makensis.h"
#include "openvas_lsc_user_rpm.h"
#include "openvas_ssh_key_create.h"
#include "ssh_key_info_form.h"

#define STR_NO_LOGINS_YET _("[No logins yet]")

/**
 * @file
 * Displays the OpenVAS SSH Key Manager to list, create and delete registered
 * ssh logins.
 */

/**
 * @brief Callback function to open the OpenVAS SSH Key Manager.
 * 
 * Only calls ssh_keys_dialog_show.
 * 
 * @see ssh_keys_dialog_show
 */
void
ssh_manager_button_cb (GtkWidget* super, void* ignored)
{
  // So far no pre- or post conditions, show dialog directly.
  ssh_keys_dialog_show();
}

/**
 * @brief Does not _empty_ the notebook but displays a placeholder (~"No logins yet").
 * 
 * @param listnotebook Listnotebook to add the 'empty' to.
 */
static void
ssh_keys_dialog_empty (GtkWidget* listnotebook)
{
  ssh_key_info_form* form = ssh_key_info_form_create ();
  ssh_key_info_form_fill (form, NULL);
  listnotebook_add_page (listnotebook, form->box, STR_NO_LOGINS_YET, NULL);
  gtk_widget_show_all (listnotebook);
}


/**
 * Creates a ssh_key_info_form from an openvas_ssh_login and adds it as a page to
 * a Listnotebook.
 * @param _ignored --ignored-- (might be non-NULL if used as callback).
 * @param login Login to create a form from.
 * @param listnotebook Listnotebook to add the page to.
 */
static void
ssh_keys_dialog_add_key (char* _ignored, openvas_ssh_login* login,
                         GtkWidget* listnotebook)
{
  if (login == NULL)
    return;

  // Remove "no logins yet"- entry if it exists.
  listnotebook_remove_page (listnotebook, STR_NO_LOGINS_YET);

  // Add the new one
  ssh_key_info_form* form = ssh_key_info_form_create();
  ssh_key_info_form_fill(form, login);
  listnotebook_add_page(listnotebook, form->box, login->name, NULL);
  gtk_widget_show_all(listnotebook);

  // Select the just created item.
  listnotebook_select_page_named (listnotebook, login->name);
}

/**
 * @brief Callback for click on 'delete'.
 * 
 * Asks the user if he is sure that the selected login should be deleted.
 * 
 * @param parent   ignored (callback).
 * @param notebook Callback user-data: the listnotebook in which a login is
 *                 selected.
 */
static void
ssh_keys_dialog_delete_login (GtkWidget* parent, GtkWidget* notebook)
{
  char* selected_account = NULL;
  GtkWidget* dialog      = NULL;
  gint response = 0;

  selected_account = listnotebook_get_selected (notebook);

  // User can not remove the placeholder item  (~"No logins yet")
  if (!strcmp (selected_account, STR_NO_LOGINS_YET))
    return;

  // Initialize dialog with a harder warning if the account is in use somewhere
  if (nvt_pref_sshlogin_is_in_use (Global, selected_account) )
    {
      dialog = gtk_message_dialog_new (NULL,
                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                    GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO,
                                    _("The selected login information '%s' is in use (selected for a target). "
                                        "Delete information and all corresponding key files anyway?"),
                                    selected_account);
    }
  else
    {
      dialog = gtk_message_dialog_new (NULL,
                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                                    GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
                                    _("Are you sure that you want to delete information about login '%s' and all corresponding key files?"),
                                    selected_account);
    }

  response = gtk_dialog_run (GTK_DIALOG (dialog));
  gtk_widget_destroy (dialog);

  if (response == GTK_RESPONSE_YES)
    {
      openvas_ssh_login* login = g_hash_table_lookup(Global->sshkeys,  selected_account);
      // Remove any installer / package.
      openvas_lsc_target_prep_remove (login);
      // Remove files and entry in Context->sshkeys hash map
      openvas_ssh_key_create_undo (login);

      // Save the file so that the removed login is not listed anymore and will
      // not appear next time.
      char* loginsfile = g_build_filename(prefs_get_nessushome(), ".openvas", ".ssh", ".logins", NULL);
      openvas_ssh_login_file_write(Global->sshkeys, loginsfile);
      efree(&loginsfile);
      listnotebook_remove_page (notebook, selected_account);

      // If no account remains, display the placeholder (~"no account yet") again
      if (g_hash_table_size (Global->sshkeys) == 0 )
        {
          ssh_keys_dialog_empty (notebook);
        }

      // Rebuild the GUIS in scopes
      nvt_pref_sshlogin_rebuild_all (Global);
    }
  // else: Do nothing, user does not want to delete that account.
}


/**
 * @brief Prompts the user for information about a new ssh login.
 * 
 * (Shows a dialog with an editable ssh_key_info_form).
 * The listnotebook parameter is passed on to the dialog.
 * If creation of a ssh keypair was successfull, information about the
 * openvas_ssh_login will be added to the notebook.
 * 
 * @param parent --ignored-- (might be non-NULL if used as callback).
 * @param notebook Listnotebook to add a page to if ssh keypair generation was
 *                 successfull.
 */
static void
ssh_keys_dialog_prompt_new (GtkWidget* parent, GtkWidget* notebook)
{
  GtkWidget* dialog;
  GtkWidget* content_area;
  ssh_key_info_form* form;
  form = ssh_key_info_form_create();

  dialog = gtk_dialog_new_with_buttons(_("OpenVAS LSC Credentials Manager - Create new Credentials"),
                                    NULL,
                                    GTK_DIALOG_MODAL
                                        | GTK_DIALOG_DESTROY_WITH_PARENT,
                                    GTK_STOCK_OK,
                                    GTK_RESPONSE_OK,
                                    GTK_STOCK_CANCEL,
                                    GTK_RESPONSE_CANCEL,
                                    NULL);

  content_area = GTK_DIALOG(dialog)->vbox;
  gtk_container_add (GTK_CONTAINER (content_area), form->box );

  gtk_window_set_default_size(GTK_WINDOW(dialog), 640, 240);
  gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  gtk_widget_show_all(dialog);

  gint result = gtk_dialog_run (GTK_DIALOG (dialog));
  while (result == GTK_RESPONSE_OK && ssh_key_info_form_validated(form) == FALSE )
    result = gtk_dialog_run(GTK_DIALOG(dialog));
  switch (result)
  {
    case GTK_RESPONSE_OK:
      {
      // Check entries
      openvas_ssh_login* loginfo = ssh_key_info_form_produce_login(form);
      if (openvas_ssh_key_create(loginfo) == FALSE)
        {
          show_error(_("Error creating key files."));
          break;
        }

      if (Global->sshkeys == NULL)
        Global->sshkeys = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
                                     (GDestroyNotify) openvas_ssh_login_free);
      g_hash_table_insert (Global->sshkeys, loginfo->name, loginfo); 

      gchar* loginsfile = g_build_filename (prefs_get_nessushome(), ".openvas", ".ssh", ".logins", NULL);
      openvas_ssh_login_file_write (Global->sshkeys, loginsfile);
      g_free (loginsfile);

      // Attempt to create rpm, deb and exe
      if (openvas_lsc_user_rpm_generator_found() == TRUE)
        {
          gchar* filename = openvas_lsc_user_rpm_filename (loginfo->name);
          // Check return value
          openvas_lsc_user_rpm_create (loginfo, filename);
          g_free (filename);
        }
      if (openvas_lsc_user_makensis_found() == TRUE)
        {
          gchar* filename = openvas_lsc_user_makensis_filename (loginfo->name);
          openvas_lsc_user_makensis (loginfo, filename);
          g_free (filename);
        }
      if (openvas_lsc_user_deb_alien_found() == TRUE)
        {
          gchar* filename = openvas_lsc_user_deb_filename (loginfo->name);
          openvas_lsc_user_deb (loginfo, filename);
          g_free (filename);
        }

      ssh_keys_dialog_add_key (NULL, loginfo, notebook);
      nvt_pref_sshlogin_update_all_comboboxes (Global, loginfo->name);
      break;
      }
    default:
      // do nothing since dialog was cancelled or closed
      break;
  }
   gtk_widget_destroy(dialog);
}


/**
 * @brief Shows the OpenVAS LSC Credentials Management Dialog.
 */
void
ssh_keys_dialog_show()
{
  GtkWidget* win;
  GtkWidget* separator;
  GtkWidget* content_area;
  GtkWidget* key_notebook;
  GtkWidget* buttonbox;

  win = gtk_dialog_new_with_buttons(_("OpenVAS LSC Credentials Manager"),
                                    NULL,
                                    GTK_DIALOG_MODAL
                                        | GTK_DIALOG_DESTROY_WITH_PARENT,
                                    GTK_BUTTONS_NONE,
                                    NULL);

  content_area = GTK_DIALOG(win)->vbox;

  key_notebook = listnotebook_new(TRUE, TRUE);

  // For each key, add a notebookpage
  if(Global->sshkeys)
    g_hash_table_foreach(Global->sshkeys, (GHFunc) ssh_keys_dialog_add_key, 
                         key_notebook);

  if (Global->sshkeys == NULL || g_hash_table_size (Global->sshkeys) == 0)
    {
      // Show that there is none yet.
      ssh_keys_dialog_empty (key_notebook);
    }

  // Add listnotebook with keys
  gtk_box_pack_start (GTK_BOX(content_area), key_notebook, TRUE, TRUE, 5);
  gtk_widget_show(key_notebook);

  // Add a separator
  separator = gtk_hseparator_new();
  gtk_container_add (GTK_CONTAINER (content_area), separator);

  /* Add action buttons */
  buttonbox  = GTK_DIALOG(win)->action_area;
  // Keypair deletion
  GtkWidget* button_del = gtk_button_new_with_label(_("Delete keypair"));
  gtk_box_pack_start (GTK_BOX(buttonbox), button_del, TRUE, TRUE, 5);
  // Keypair creation
  GtkWidget* button_new = gtk_button_new_with_label(_("Create a new keypair"));
  gtk_box_pack_start (GTK_BOX(buttonbox), button_new, TRUE, TRUE, 5);

  // Close dialog button
  gtk_dialog_add_buttons (GTK_DIALOG(win), GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT, NULL);

  // Button- Signal connections
  g_signal_connect (button_new, "clicked", 
                    (GtkSignalFunc) ssh_keys_dialog_prompt_new, key_notebook);
  g_signal_connect (button_del, "clicked", 
                    (GtkSignalFunc) ssh_keys_dialog_delete_login, key_notebook);
  g_signal_connect_swapped (win, "response", G_CALLBACK (gtk_widget_destroy),
                            win);

  gtk_window_set_default_size(GTK_WINDOW(win), 640, 240);
  gtk_widget_show_all(win);
}

#endif /* USE_GTK */
