/*---[ preferences.c ]------------------------------------------------
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The preferences notebook window
 *
 * Note that esd wont play sounds if the esd daemon wasn't started by
 * root. esdctl unlock?
 *
 * Based on firestarter code by Tomas Junnonen (majix@sci.fi)
 *--------------------------------------------------------------------*/

#include "preferences.h"
#include "razorback.h"
#include "parse.h"

#include "xpm/play.xpm"

#define LOG 0
#define HIT 1
#define STOP 2
#define RESTART 3


static GtkWidget *sections_clist;

GtkWidget *scriptentry;
GtkWidget *logentry;

GtkWidget *exitonclose;
GtkWidget *starthidden;
GtkWidget *removedups;

GtkWidget *enablesounds;
GtkWidget *hitsoundentry;

GtkWidget *showmasqpage;
GtkWidget *locatesbins;
GtkWidget *selectdeny;
GtkWidget *selectreject;

GtkWidget *filesel;

gboolean ifo = FALSE;

static GtkWidget *create_browse_button (GtkWidget *button, gint which);
static void 	 create_filesel	       (GtkWidget *widget, gpointer data);
static void	 set_file_log	       (GtkWidget *widget, gpointer data);
static void	 set_file_hit	       (GtkWidget *widget, gpointer data);
static void 	 give_false_ifo	       (GtkWidget *widget, gpointer data);
static void 	 destroy_filesel       (GtkWidget *pbox,   gpointer data);

/* [ starthidden_sensitive ]
 * The sensitivity of the starthidden widget is determined from exitonclose
 */
static void
starthidden_sensitive (GtkWidget *widget)
{
	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (exitonclose)))
		gtk_widget_set_sensitive (starthidden, FALSE);
	else
		gtk_widget_set_sensitive (starthidden, TRUE);
}


/* [ save_preferences ]
 * Save the preferences to the gnome registry
 */
static void
save_preferences (GnomePropertyBox *property_box, gint page_num, gint num)
{
/* TODO: This function is called 2 times when apply is pressed, why? */

/* General */
	gnome_config_set_string ("/razorback/Files/logfile",
		gtk_entry_get_text (GTK_ENTRY (logentry)));

	gnome_config_set_bool ("/razorback/Program/exitonclose",
		gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (exitonclose)));

	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (exitonclose)))
		gnome_config_set_bool ("/razorback/Program/starthidden",
			gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (starthidden)));
	else
		gnome_config_set_bool ("/razorback/Program/starthidden", FALSE);

	gnome_config_set_bool ("/razorback/Program/removedups",
		gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (removedups)));

/* Sounds */
	gnome_config_set_bool ("/razorback/Sounds/enablesounds",
		gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (enablesounds)));

 	gnome_config_set_string ("/razorback/Sounds/hitsoundfile",
		gtk_entry_get_text (GTK_ENTRY (hitsoundentry)));

	gnome_config_sync ();
}

/* [ create_general_page ]
 * Create the general property page
 */
static GtkWidget*
create_general_page (GtkWidget *pbox)
{
	GtkWidget *table;
	GtkWidget *label;
	GtkWidget *button;
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *hbox;

	table = gtk_table_new (1, 1, FALSE);
	gtk_table_set_row_spacings (GTK_TABLE (table), 0);
	gtk_table_set_col_spacings (GTK_TABLE (table), GNOME_PAD_SMALL);

	frame = gtk_frame_new (_("General options"));
	gtk_widget_set_usize (frame, 380, 170);
	gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
			  GTK_FILL, GTK_FILL, GNOME_PAD, GNOME_PAD_SMALL);

	vbox = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (frame), vbox);

	exitonclose = gtk_check_button_new_with_label (_(
		"Exit program when window is closed (otherwise hide)"));
	gtk_tooltips_set_tip (ttips, exitonclose, _(
		"By default when you close the program window the program is "
		"merely hidden, you can then make it visible again by clicking "
		"on the status button."), "");
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (exitonclose),
		 gnome_config_get_bool ("/razorback/Program/exitonclose=FALSE"));
	gtk_box_pack_start (GTK_BOX (vbox), exitonclose, FALSE, FALSE, 0);

	starthidden = gtk_check_button_new_with_label (_("Start hidden"));
	gtk_tooltips_set_tip (ttips, starthidden, _(
		"Check this and Razorback will start hidden. Click on the "
		"status button to unhide. Disabled by default."), "");
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (starthidden),
		gnome_config_get_bool ("/razorback/Program/starthidden=FALSE"));
	gtk_box_pack_start (GTK_BOX (vbox), starthidden, FALSE, FALSE, 0);

	removedups = gtk_check_button_new_with_label (_(
		"Remove identical snort hit lines"));
	gtk_tooltips_set_tip (ttips, removedups, _(
		"Check this and the snort hit log will filter out identical "
		"lines. Enabled by deault."), "");
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (removedups),
		gnome_config_get_bool ("/razorback/Program/removedups=TRUE"));
	gtk_box_pack_start (GTK_BOX (vbox), removedups, FALSE, FALSE, 0);

	if (gnome_config_get_bool ("/razorback/Program/exitonclose=FALSE"))
		gtk_widget_set_sensitive (starthidden, FALSE);

	hbox = gtk_hbox_new (FALSE, 2);
	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

	label = gtk_label_new (_("Snort syslog file:"));
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 18);

	logentry = gtk_entry_new ();
	gtk_tooltips_set_tip (ttips, logentry, _(
		"Enter the path to the file the syslog daemon logs to. "
		"This is almost always /var/log/secure."), "");
	gtk_entry_set_text (GTK_ENTRY (logentry),
		gnome_config_get_string (
			"/razorback/Files/logfile=/var/log/secure"));
	gtk_box_pack_start (GTK_BOX (hbox), logentry, FALSE, FALSE, 0);

	button = create_browse_button (button, LOG);
	gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);

	gtk_signal_connect_object (GTK_OBJECT (logentry), "changed",
		GTK_SIGNAL_FUNC (gnome_property_box_changed), GTK_OBJECT (pbox));
	gtk_signal_connect_object (GTK_OBJECT (exitonclose), "toggled",
		GTK_SIGNAL_FUNC (gnome_property_box_changed), GTK_OBJECT (pbox));
	gtk_signal_connect_object (GTK_OBJECT (removedups), "toggled",
		GTK_SIGNAL_FUNC (gnome_property_box_changed), GTK_OBJECT (pbox));

	gtk_signal_connect (GTK_OBJECT (exitonclose), "toggled",
			    GTK_SIGNAL_FUNC (starthidden_sensitive), NULL);

	gtk_signal_connect_object (GTK_OBJECT (starthidden), "toggled",
		GTK_SIGNAL_FUNC (gnome_property_box_changed), GTK_OBJECT (pbox));

	return (table);
}

static void
play_sound (GtkWidget *widget, GtkWidget *entry)
{
	gnome_sound_play (gtk_entry_get_text (GTK_ENTRY (entry)));
}


/* [ create_play_button ]
 * Convenience function to create a sound play button
 */
static GtkWidget*
create_play_button (GtkWidget *button, GtkWidget *entry)
{
	GtkWidget *picture;

	button = gtk_button_new ();
	gtk_tooltips_set_tip (ttips, button, _(
		"Play current sound file"), "");
	picture = gnome_pixmap_new_from_xpm_d (play_xpm);
	gtk_container_add (GTK_CONTAINER (button), picture);

	gtk_signal_connect (GTK_OBJECT (button), "clicked",
		GTK_SIGNAL_FUNC (play_sound), entry);

	return (button);
}


/* [ create_sounds_page ]
 * Create the sound property page
 */
static GtkWidget*
create_sounds_page (GtkWidget *pbox)
{
	GtkWidget *table;
	GtkWidget *label;
	GtkWidget *button = NULL;
	GtkWidget *frame;
	GtkWidget *vbox;
	GtkWidget *hbox;

	table = gtk_table_new (1, 1, FALSE);
	gtk_table_set_row_spacings (GTK_TABLE (table), 0);
	gtk_table_set_col_spacings (GTK_TABLE (table), GNOME_PAD_SMALL);

	frame = gtk_frame_new (_("Sound options"));
	gtk_widget_set_usize (frame, 380, 115);
	gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
			  GTK_FILL, GTK_FILL, GNOME_PAD, GNOME_PAD_SMALL);

	vbox = gtk_vbox_new (FALSE, 0);
	gtk_container_add (GTK_CONTAINER (frame), vbox);

	enablesounds = gtk_check_button_new_with_label (_("Enable sounds"));
	gtk_tooltips_set_tip (ttips, enablesounds, _(
		"Check this if you want to hear sounds on certain events"), "");
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (enablesounds),
		gnome_config_get_bool ("/razorback/Sounds/enablesounds=TRUE"));
	gtk_box_pack_start (GTK_BOX (vbox), enablesounds, FALSE, FALSE, 0);

	hbox = gtk_hbox_new (FALSE, 2);
	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

	label = gtk_label_new (_("File to play on snort hit:"));
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);

	hitsoundentry = gtk_entry_new ();
	gtk_tooltips_set_tip (ttips, hitsoundentry, _(
		"Enter the path to the sound file that should be played when a snort hit occurs."), "");
	gtk_entry_set_text (GTK_ENTRY (hitsoundentry),
		gnome_config_get_string ("/razorback/Sounds/hitsoundfile="));

	button = create_browse_button (button, HIT);
	gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 2);

	button = create_play_button (button, hitsoundentry);
	gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);

	gtk_box_pack_end (GTK_BOX (hbox), hitsoundentry, FALSE, FALSE, 2);

	hbox = gtk_hbox_new (FALSE, 2);
	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

	hbox = gtk_hbox_new (FALSE, 2);
	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);

	gtk_signal_connect_object (GTK_OBJECT (enablesounds), "toggled",
				   GTK_SIGNAL_FUNC (gnome_property_box_changed), GTK_OBJECT (pbox));
	gtk_signal_connect_object (GTK_OBJECT (hitsoundentry), "changed",
				   GTK_SIGNAL_FUNC (gnome_property_box_changed), GTK_OBJECT (pbox));
	return (table);
}

static void
prefs_select_row_cb (GtkCList *clist,
                     gint row,
                     gint column,
                     GdkEventButton *event,
                     GtkWidget *pbox)
{
        gtk_notebook_set_page (GTK_NOTEBOOK (
		GNOME_PROPERTY_BOX (pbox)->notebook), row);
}

static int
prefs_add_section_page (gchar     *name,
                        GtkWidget *widget,
			GtkWidget *pbox)
{
	gchar *text[2] = {name, NULL};
	gtk_notebook_append_page (GTK_NOTEBOOK (GNOME_PROPERTY_BOX (pbox)->notebook),
				  widget, gtk_label_new (name));
	return gtk_clist_append (GTK_CLIST (sections_clist), text);
}

/* [ preferences_cb ]
 * Create the preferences property_box
 */
void
preferences_cb (GtkWidget *widget, gpointer data)
{
	static GtkWidget *pbox;
	GtkWidget *hbox;
	GtkWidget *label;

	if (pbox != NULL) {
		g_assert (GTK_WIDGET_REALIZED (pbox));
		gdk_window_show (pbox->window);
		gdk_window_raise (pbox->window);

		return;
	}

	pbox = gnome_property_box_new ();
	gtk_window_set_title (GTK_WINDOW (pbox), _("Razorback: Preferences"));

	hbox = gtk_hbox_new (FALSE, GNOME_PAD);
	gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);

	sections_clist = gtk_clist_new (1);
	gtk_widget_set_usize (GTK_WIDGET (sections_clist), 100, 0);
	gtk_clist_set_selection_mode (GTK_CLIST (sections_clist),
				      GTK_SELECTION_BROWSE);

	gtk_signal_connect (GTK_OBJECT (sections_clist), "select_row",
			    GTK_SIGNAL_FUNC (prefs_select_row_cb), pbox);

	label = gtk_label_new ("Test");
	prefs_add_section_page (_("General"), create_general_page (pbox), pbox);
	prefs_add_section_page (_("Sounds"), create_sounds_page (pbox), pbox);

	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (GNOME_PROPERTY_BOX (pbox)->notebook), FALSE);
	gtk_notebook_set_show_border (GTK_NOTEBOOK (GNOME_PROPERTY_BOX (pbox)->notebook), FALSE);

	gtk_widget_ref (GNOME_PROPERTY_BOX (pbox)->notebook);

	gtk_container_remove (GTK_CONTAINER (GNOME_DIALOG (pbox)->vbox),
			      GNOME_PROPERTY_BOX (pbox)->notebook);

	gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(pbox)->vbox),
			    hbox, TRUE, TRUE, 0);

	gtk_box_pack_start (GTK_BOX (hbox),
			    sections_clist,
			    TRUE, TRUE, 0);

	gtk_box_pack_start (GTK_BOX (hbox),
			    GNOME_PROPERTY_BOX (pbox)->notebook,
			    TRUE, TRUE, 0);

	gtk_widget_unref (GNOME_PROPERTY_BOX (pbox)->notebook);

	gtk_signal_connect (GTK_OBJECT (pbox), "apply",
		   GTK_SIGNAL_FUNC (destroy_filesel), NULL);

	gtk_signal_connect (GTK_OBJECT (pbox), "apply",
			    GTK_SIGNAL_FUNC (save_preferences), NULL);
			    
	gtk_signal_connect (GTK_OBJECT (pbox), "destroy",
		   GTK_SIGNAL_FUNC (destroy_filesel), NULL);

	gtk_signal_connect (GTK_OBJECT (pbox), "destroy",
			    GTK_SIGNAL_FUNC (gtk_widget_destroyed), &pbox);

	gtk_widget_show_all (pbox);
}

static void
set_file_log (GtkWidget *widget, gpointer data)
{
	gtk_entry_set_text (GTK_ENTRY (logentry),
			gtk_file_selection_get_filename (GTK_FILE_SELECTION (data)));
}

static void
set_file_hit (GtkWidget *widget, gpointer data)
{
	gtk_entry_set_text (GTK_ENTRY (hitsoundentry),
			gtk_file_selection_get_filename (GTK_FILE_SELECTION (data)));
}


static void
give_false_ifo (GtkWidget *widget, gpointer data)
{
	ifo = FALSE;
}

static void
create_filesel (GtkWidget *widget, gpointer data)
{
	gint which = (gint) data;

	ifo = TRUE;
	filesel = (which == LOG) ?
		gtk_file_selection_new (_("Select the syslog log file")):
		gtk_file_selection_new (_("Select the file to play a sound"));

	gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (
		filesel)->ok_button), "clicked",
		GTK_SIGNAL_FUNC ((which == LOG ? set_file_log : set_file_hit)),
			GTK_OBJECT (GTK_FILE_SELECTION (filesel)));

	gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
		"clicked", GTK_SIGNAL_FUNC (give_false_ifo), NULL);

	gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->ok_button),
		"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
		GTK_OBJECT (GTK_FILE_SELECTION (filesel)));

	gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
		"clicked", GTK_SIGNAL_FUNC (give_false_ifo), NULL);

	gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (filesel)->cancel_button),
		"clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
		GTK_OBJECT (GTK_FILE_SELECTION (filesel)));

	gtk_widget_show (filesel);
}

/* [ create_browse_button ]
 * Convenience function to create a browse button
 */
static GtkWidget*
create_browse_button (GtkWidget *button, gint which)
{
	button = gtk_button_new_with_label ("...");
	gtk_tooltips_set_tip (ttips, button, _("Browse"), "");

	gtk_signal_connect (GTK_OBJECT (button), "clicked",
		GTK_SIGNAL_FUNC (create_filesel), (gpointer) which);

	return (button);
}

/* [ destroy_filesel ]
 * Destroy the file selector window if open when the preference
 * window receive the any signal
 */

static void
destroy_filesel (GtkWidget *pbox, gpointer data)
{
	if (ifo) {
		gtk_widget_destroy (GTK_WIDGET (filesel));
		ifo = FALSE;
	}
}
