/* $Id: prefs_context.c,v 1.7.2.2 2006/11/04 23:22:37 renaud Exp $
 *
 * Copyright (C) 2004 by Intevation GmbH
 * Author(s):
 * Thomas Arendsen Hein <thomas@intevation.de>
 *
 * 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 "nessus_i18n.h"

#include <gtk/gtk.h>
#include "globals.h"
#include "nessus.h"
#include "context.h"
#include "preferences.h"
#include "error_dialog.h"
#include "comm.h"
#include "prefs_dialog.h"
#include "prefs_target.h"
#include "prefs_dialog_plugins_prefs.h"
#include "prefs_dialog_scan_opt.h"
#include "prefs_plugins.h"
#include "prefs_dialog_user.h"
#include "backend.h"
#include "prefs_context.h"
#include "report.h"
#include "prefs_report.h"
#include "prefs_scope_tree.h"
#include "prefs_comment.h"

#include "../xpm/encrypted.xpm"
#include "../xpm/unencrypted.xpm"

void
prefs_context_enable_widget(name, enabled)
  const gchar *name;
  gboolean enabled;
{
  GtkWidget *widget = GTK_WIDGET(arg_get_value(MainDialog, name));

  gtk_widget_set_sensitive(widget, enabled);
}

void
prefs_context_update_widgets(context)
  struct context *context;
{
  static context_type last_type = CONTEXT_ENUM;
  static context_action last_action = CONTEXT_IDLE;
  context_type type = context->type;
  context_type action = context->action;
  int do_enable;
  
  if(type != last_type || action != last_action )
  {
    prefs_context_enable_widget("RENAMETASK_MENUITEM", type >= CONTEXT_TASK);
    prefs_context_enable_widget("DELETETASK_MENUITEM", type >= CONTEXT_TASK);

    prefs_context_enable_widget("EXECSCOPE_MENUITEM", type >= CONTEXT_SCOPE && action == CONTEXT_IDLE );
    prefs_context_enable_widget("NEWSCOPE_MENUITEM", type >= CONTEXT_TASK);
    prefs_context_enable_widget("RENAMESCOPE_MENUITEM", type >= CONTEXT_SCOPE);
    prefs_context_enable_widget("DELETESCOPE_MENUITEM", type >= CONTEXT_SCOPE);
    prefs_context_enable_widget("OPENSCOPE_MENUITEM", type >= CONTEXT_TASK);
    prefs_context_enable_widget("SAVESCOPE_MENUITEM", type >= CONTEXT_SCOPE);

    prefs_context_enable_widget("RENAMEREPORT_MENUITEM", type >= CONTEXT_REPORT);
    prefs_context_enable_widget("DELETEREPORT_MENUITEM", type >= CONTEXT_REPORT);
    prefs_context_enable_widget("IMPORTREPORT_MENUITEM", type >= CONTEXT_SCOPE);
    prefs_context_enable_widget("EXPORTREPORT_MENUITEM", type >= CONTEXT_REPORT);
    prefs_context_enable_widget("PRINTREPORT_MENUITEM", type >= CONTEXT_REPORT);

    prefs_context_enable_widget("DELETECONTEXT_BUTTON", type >= CONTEXT_TASK);
    prefs_context_enable_widget("EXECSCOPE_BUTTON", type == CONTEXT_SCOPE && action == CONTEXT_IDLE);
  }
  last_type = type;
  last_action = action;

  prefs_context_enable_widget("MOVESCOPE_MENUITEM",
      type >= CONTEXT_SCOPE && Global->children->next);

  do_enable = (type == CONTEXT_SCOPE || type == CONTEXT_GLOBAL)
    && context->socket < 0;
  prefs_context_enable_widget("CONNECT_MENUITEM", do_enable);
  prefs_context_enable_widget("CONNECT_BUTTON", do_enable);

  do_enable = (type == CONTEXT_SCOPE || type == CONTEXT_GLOBAL )
    && context->socket >= 0 
    && action == CONTEXT_IDLE;
  prefs_context_enable_widget("DISCONNECT_MENUITEM", do_enable);
  prefs_context_enable_widget("DISCONNECT_BUTTON", do_enable);
}

void
prefs_context_switch_notebookpage(notebook, page, page_num, user_data)
  GtkNotebook *notebook;
  GtkNotebookPage *page;
  guint page_num;
  gpointer user_data;
{
  GtkWidget *newpage = gtk_notebook_get_nth_page(notebook, page_num);

  if(!GTK_WIDGET_IS_SENSITIVE(newpage))
  {
    show_info(_("This page is not available in the current context."));
    prefs_context_update(Context);
  }
}

void
prefs_context_enable_notebookpage(notebook, pagenr, enable)
  int pagenr;
  GtkWidget *notebook;
  gboolean enable;
{
  GtkWidget *page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), pagenr);
  GtkWidget *label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(notebook), page);

  gtk_widget_set_sensitive(label, enable);
  gtk_widget_set_sensitive(page, enable);
}

void
prefs_context_update_notebook(comment, options, report)
  gboolean comment;
  gboolean options;
  gboolean report;
{
  GtkWidget *notebook = arg_get_value(MainDialog, "CONTEXTNOTEBOOK");

  prefs_context_enable_notebookpage(notebook, 0, comment);
  prefs_context_enable_notebookpage(notebook, 1, options);
  prefs_context_enable_notebookpage(notebook, 2, report);

  if(report)
    gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 2);
  else if(options)
    gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 1);
  else if(comment)
    gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0);
}

void
prefs_context_update_comment(context)
  struct context *context;
{
  fill_comment(context, arg_get_value(MainDialog, "COMMENT"));
}

void
prefs_context_enable_options_frame(name, enabled)
  const gchar *name;
  gboolean enabled;
{
  struct arglist *options = arg_get_value(MainDialog, "OPTIONS");
  struct arglist *suboptions = arg_get_value(options, name);
  GtkWidget *widget = GTK_WIDGET(arg_get_value(suboptions, "FRAME"));

  gtk_widget_set_sensitive(widget, enabled);
}

void
prefs_context_update_options_enable(enable)
  gboolean enable;
{
  prefs_context_enable_options_frame("SCAN_OPTIONS", enable);
  prefs_context_enable_options_frame("PLUGINS", enable);
  prefs_context_enable_options_frame("PLUGINS_PREFS", enable);
  prefs_context_enable_options_frame("TARGET", enable);
  prefs_context_enable_options_frame("USER", enable);
  prefs_context_enable_options_frame("SAVE_KB", enable);
}

void
prefs_context_update_options(context)
  struct context *context;
{
  if(prefs_has_options(context))
  {
    prefs_dialog_set_defaults(context, MainDialog);
    fill_scanner_list(context, arg_get_value(MainDialog, "SCAN_OPTIONS"));
    fill_plugins_family(context, arg_get_value(MainDialog, "PLUGINS"));
    fill_rules_list(context, arg_get_value(MainDialog, "USER"));
    prefs_plugins_prefs_redraw(context, arg_get_value(MainDialog, "PLUGINS_PREFS"));
    prefs_context_update_options_enable(context->type < CONTEXT_REPORT);
  }
}

void
prefs_context_update_report(context)
  struct context *context;
{
  int be;
  struct arglist *ctrls_report;
  char *fname;

  /*
   * load the corresponding report and update the report page
   */
  fname = report_get_filename(context);
  ctrls_report = arg_get_value(MainDialog, "REPORT");
  /* but first discard the current one */
  be = (int)arg_get_value(ctrls_report, "BE");
  if (be >= 0) {
    backend_dispose(be);
    arg_set_value(ctrls_report, "BE", sizeof(int), (void *)-1);
  }
  if (fname && check_is_file(fname)) {
    be = backend_import_report(fname);
    efree(&fname);
    arg_set_value(ctrls_report, "BE", sizeof(int), (void *)be);
    scopetreeview_counters_update(context, be, fname);
  }
  prefs_report_update(ctrls_report);
}

/* Update the encryption state image.
 *
 * If is_encrypted is true, the picture shown in the image is set to
 * encrypted_xpm otherwise it's unencrypted_xpm.
 */
static void
update_encryption_image(image, is_encrypted)
  GtkWidget *image;
  int is_encrypted;
{
  static GdkPixbuf *encrypted = NULL;
  static GdkPixbuf *unencrypted = NULL;

  if (encrypted == NULL)
  {
    encrypted = gdk_pixbuf_new_from_xpm_data(encrypted_xpm);
  }
  if (unencrypted == NULL)
  {
    unencrypted = gdk_pixbuf_new_from_xpm_data(unencrypted_xpm);
  }

  gtk_image_set_from_pixbuf(GTK_IMAGE(image),
      is_encrypted ? encrypted : unencrypted);
}


void
prefs_context_update_statusbar(context)
  struct context *context;
{
  GtkStatusbar * statusbar = GTK_STATUSBAR(arg_get_value(MainDialog,
	"CONNECT_STATUSBAR"));
  gchar * connect_status;
  int port = prefs_get_int(context, "nessusd_port");
  const gchar * username = prefs_get_string(context, "nessusd_user");
  const gchar * hostname = prefs_get_string(context, "nessusd_host");
  gboolean use_ssl = prefs_get_int(context, "use_ssl");
  GtkWidget *icon = arg_get_value(MainDialog, "CONNECT_ENCRYPTED_IMAGE");

  gtk_statusbar_pop(statusbar,
    gtk_statusbar_get_context_id(statusbar, "connection"));

  if(context->socket >= 0)
  {
    if (port == (int)prefs_get_default(context, "nessusd_port"))
      connect_status = g_strdup_printf(_("Connection: %s@%s %s"),
	username, hostname, use_ssl ? _("encrypted") : _("unencrypted") );
    else if (port >= 0)
      connect_status = g_strdup_printf(_("Connection: %s@%s:%d %s"),
	username, hostname, port, use_ssl ? _("encrypted") : _("unencrypted") );
    else
      connect_status = g_strdup_printf(_("Connection: user %s %s"),
	username, use_ssl ? _("encrypted") : _("unencrypted") );
    update_encryption_image(icon, use_ssl);
  }
  else
  {
    connect_status = g_strdup_printf(_("not connected"));
    /* if not connected we show the unencrypted icon.  This is not
     * ideal.  Maybe there should be a third image for that case. */
    update_encryption_image(icon, 0);
  }

  gtk_statusbar_push(statusbar,
      gtk_statusbar_get_context_id(statusbar, "connection"), connect_status);
  g_free(connect_status);
}

void
prefs_context_update(context)
  struct context *context;
{
  GtkWidget *scopetree = GTK_WIDGET(
      arg_get_value(arg_get_value(MainDialog, "SCOPETREE"), "TREEVIEW"));
  GtkTreePath *path = gtk_tree_row_reference_get_path(context->treerowref);
  GtkTreePath *curpath;
  GtkWidget *contextframe = arg_get_value(MainDialog, "CONTEXTFRAME");
  gchar *text = NULL;
  GtkTreeViewColumn *column;

  /* Make sure to synchronise other data structures with the GUI elements */
  prefs_dialog_apply(Context, MainDialog);
  prefs_dialog_apply_plugin_prefs(Context->plugins);
  prefs_dialog_apply_plugin_prefs(Context->scanners);
  context_sync_plugin_prefs(Context);

  scope_move_menuitem_enable(Context, TRUE);
  scope_move_menuitem_enable(context, FALSE);

  Context = context;	/* change current context */

  column = gtk_tree_view_get_column(GTK_TREE_VIEW(scopetree), 0);
  gtk_tree_view_get_cursor(GTK_TREE_VIEW(scopetree), &curpath, NULL);
  if(!curpath || !path || gtk_tree_path_compare(curpath, path))
    gtk_tree_view_set_cursor(GTK_TREE_VIEW(scopetree), path, column, FALSE);

  if(curpath)
    gtk_tree_path_free(curpath);
  if(path)
    gtk_tree_path_free(path);

  switch(context->type)
  {
    case CONTEXT_GLOBAL:
      prefs_context_update_notebook(FALSE, TRUE, FALSE);
      text = g_strdup_printf(prefs_get_string(context, "name"));
      break;
    case CONTEXT_TASK:
      prefs_context_update_notebook(TRUE, FALSE, FALSE);
      text = g_strdup_printf(_("Task: %s"),
	  prefs_get_string(context, "name"));
      break;
    case CONTEXT_SCOPE:
      /* disable options and comments while scanning */
      prefs_context_update_notebook(context->action != CONTEXT_SCANNING,
	  context->action != CONTEXT_SCANNING, FALSE);
      text = g_strdup_printf(_("Scope: %s (Task: %s)"),
	  prefs_get_string(context, "name"),
	  prefs_get_string(context->parent, "name"));
      break;
    case CONTEXT_REPORT:
      prefs_context_update_notebook(TRUE, prefs_has_options(context), TRUE);
      text = g_strdup_printf(_("Report for scope: %s (Task: %s)"),
	  prefs_get_string(context->parent, "name"),
	  prefs_get_string(context->parent->parent, "name"));
      break;
    default:
      show_error(_("prefs_context_update called with illegal context."));
  }
  gtk_frame_set_label(GTK_FRAME(contextframe), text);
  g_free(text);

  prefs_context_update_widgets(context);
  prefs_context_update_comment(context);
  prefs_context_update_options(context);
  prefs_context_update_report(context);
  prefs_context_update_statusbar(context);
}
