/* PureAdmin
 * Copyright (C) 2003 Isak Savo
 *
 *  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.
 *
 *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
 * Preferences management - the GUI-part.
 *
 * Copyright (C) 2003 - Isak Savo
 */
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <gtk/gtk.h>

#include "cfg.h"
#include "prefwin.h"
#include "helper.h"
#include "gui_helper.h"
#include "logfile.h"
#include "globals.h"
#include "system_accounts.h"
#include "dirbrowser.h"

static void prefwin_menu_gid_changed (GtkOptionMenu *optionmenu, gpointer user_data);
static void prefwin_menu_uid_changed (GtkOptionMenu *optionmenu, gpointer user_data);
static void prefwin_rdo_toggled (GtkToggleButton *togglebutton, gpointer user_data);
static void prefwin_entry_changed (GtkEditable *editable, gpointer user_data);
static void prefwin_btn_search_clicked (GtkButton *button, gpointer user_data);
static void prefwin_chkbtn_toggled (GtkToggleButton *togglebutton, gpointer user_data);
static void prefwin_chkencoding_toggled (GtkToggleButton *togglebutton, gpointer user_data);
static void prefwin_btn_browse_clicked (GtkButton *button, GtkWidget *entry);
static void prefwin_btn_browse_home_clicked (GtkButton *button, gpointer user_data);
static void prefwin_btn_encoding_sel_clicked (GtkButton *button, gpointer user_data);

GladeXML *pref_xml = NULL;

prefwin_widgets *prefwin_get_widgets (void)
{
	static prefwin_widgets *w = NULL;

	if (G_UNLIKELY (!w))
	{
		w = g_new0 (prefwin_widgets, 1);
       
		w->menu_uid = PW("opt_menu_uid");
		w->menu_gid = PW("opt_menu_gid");
		w->home = PW("entry_home");
		w->cmd_purepw = PW("entry_purepw_cmd");
		w->pwfile = PW("entry_passwd_file");
		w->pdbfile = PW("entry_pdb_file");
		w->encoding = PW("entry_encoding");
		w->btn_search = PW("btn_search_set_defaults");
		w->rdo_syslog = PW("rdo_syslog");
		w->rdo_custom = PW("rdo_custom");
		w->logfile = PW("entry_logfile");
		w->chk_resolve = PW("chk_resolve_hostnames");
		w->btn_home_browse = PW("btn_home_dir_browse");
		w->btn_encoding_sel = PW("btn_encoding_sel");
		w->chk_save_window_geo = PW("chk_save_window_geo");
		w->chk_use_system_encoding = PW("chk_use_system_encoding");
		w->chk_use_tray_icon = PW("chk_use_tray_icon");
		w->chk_always_notify = PW("chk_always_notify");
		w->btn_browse_purepw = PW("btn_browse_purepw");
		w->btn_browse_pw = PW("btn_browse_pw");
		w->btn_browse_pdb = PW("btn_browse_pdb");
	}
	return w;
}

void prefwin_close (GtkWidget *w, gpointer data)
{
	cfg_write_settings ();
}


static GtkWidget *create_prefwin (void)
{
	gchar *our_path;
	
	our_path = g_build_filename (datadir, PACKAGE, "prefwin.glade", NULL);
	pref_xml = glade_xml_new (our_path, NULL, NULL);
	g_free (our_path);

	/* FIXME: autoconnect? */
	return PW("preferences");
}

GtkWidget *pref_init_prefwindow (GtkWidget *parent)
{
	prefwin_widgets *w;
	GList *id;
	GtkWidget *menu;
	static GtkWidget *prefwin = NULL;
	gint i;

	if (!prefwin)
		prefwin = create_prefwin ();
	else
		return prefwin;
	
	w = prefwin_get_widgets ();
   
	/* GID/UID Option menus */
	id = sys_get_user_ids ();
	menu = gui_create_system_account_menu(id);
	gtk_option_menu_remove_menu (GTK_OPTION_MENU (w->menu_uid));
	gtk_option_menu_set_menu (GTK_OPTION_MENU (w->menu_uid), menu);
	/* Keep the list attached to the menu so that it's available in the callbacks.. */
	g_object_set_data (G_OBJECT (w->menu_uid), "items", id);
	i = 0;
	while (id)
	{
		if (cfg.default_uid == ((SystemAccount*) id->data)->id)
			break;
		i++;
		id = g_list_next (id);
	}
	gtk_option_menu_set_history (GTK_OPTION_MENU (w->menu_uid), i);

	id = sys_get_group_ids ();
	menu = gui_create_system_account_menu(id);
	gtk_option_menu_remove_menu (GTK_OPTION_MENU (w->menu_gid));
	gtk_option_menu_set_menu (GTK_OPTION_MENU (w->menu_gid), menu);
	g_object_set_data_full (G_OBJECT (w->menu_gid), "items", id, (GDestroyNotify) system_account_list_free);
	i = 0;
	while (id)
	{
		if (cfg.default_gid == ((SystemAccount*) id->data)->id)
			break;
		i++;
		id = g_list_next (id);
	}
	gtk_option_menu_set_history (GTK_OPTION_MENU (w->menu_gid), i);

	if (cfg.logmethod == LOG_SYSLOG)
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->rdo_syslog), TRUE);
	else
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->rdo_custom), TRUE);
   
	gtk_entry_set_text (GTK_ENTRY (w->home), cfg.default_home);
	gtk_entry_set_text (GTK_ENTRY (w->encoding), cfg.uname_encoding);
	gtk_entry_set_text (GTK_ENTRY (w->cmd_purepw), cfg.cmd_purepw);
	gtk_entry_set_text (GTK_ENTRY (w->pwfile), cfg.pwfile);
	gtk_entry_set_text (GTK_ENTRY (w->pdbfile), cfg.pdbfile);
	gtk_entry_set_text (GTK_ENTRY (w->logfile), cfg.logfile);

	/* Use these paths as a fallback for the fileselector */
	g_object_set_data (G_OBJECT(w->cmd_purepw), "default_path", "/usr/bin/");
	g_object_set_data (G_OBJECT(w->pwfile), "default_path", "/etc/");
	g_object_set_data (G_OBJECT(w->pdbfile), "default_path", "/etc/");

	/* Used to hint the file selector on the type of file we're selecting */
	g_object_set_data (G_OBJECT(w->cmd_purepw), "whatfile", _("pure-pw executable"));
	g_object_set_data (G_OBJECT(w->pwfile), "whatfile", _("password file"));
	g_object_set_data (G_OBJECT(w->pdbfile), "whatfile", _("database file"));
	
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_resolve), cfg.resolve_hostnames);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_save_window_geo), cfg.save_window_geometry);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_use_tray_icon), cfg.use_tray_icon);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_always_notify), cfg.always_notify_activities);
	g_signal_connect ((gpointer) w->chk_use_system_encoding, "toggled",
			  G_CALLBACK (prefwin_chkencoding_toggled),
			  NULL);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w->chk_use_system_encoding), cfg.use_system_encoding);
	/* Hookup signals for the widgets to allow 'instant-apply' */
	g_signal_connect ((gpointer) w->menu_uid, "changed",
			  G_CALLBACK (prefwin_menu_uid_changed),
			  NULL);
	g_signal_connect ((gpointer) w->menu_gid, "changed",
			  G_CALLBACK (prefwin_menu_gid_changed),
			  NULL);
	g_signal_connect ((gpointer) w->home, "changed",
			  G_CALLBACK (prefwin_entry_changed),
			  "home");
	g_signal_connect ((gpointer) w->encoding, "changed",
			  G_CALLBACK (prefwin_entry_changed),
			  "encoding");
	g_signal_connect ((gpointer) w->cmd_purepw, "changed",
			  G_CALLBACK (prefwin_entry_changed),
			  "cmd_purepw");
	g_signal_connect ((gpointer) w->pwfile, "changed",
			  G_CALLBACK (prefwin_entry_changed),
			  "pwfile");
	g_signal_connect ((gpointer) w->pdbfile, "changed",
			  G_CALLBACK (prefwin_entry_changed),
			  "pdbfile");
	g_signal_connect ((gpointer) w->rdo_syslog, "toggled",
			  G_CALLBACK (prefwin_rdo_toggled),
			  GINT_TO_POINTER (LOG_SYSLOG));
	g_signal_connect ((gpointer) w->rdo_custom, "toggled",
			  G_CALLBACK (prefwin_rdo_toggled),
			  GINT_TO_POINTER (LOG_CUSTOM));
	g_signal_connect ((gpointer) w->logfile, "changed",
			  G_CALLBACK (prefwin_entry_changed),
			  "logfile");
	g_signal_connect ((gpointer) w->chk_resolve, "toggled",
			  G_CALLBACK (prefwin_chkbtn_toggled),
			  "resolve");
	g_signal_connect ((gpointer) w->chk_use_tray_icon, "toggled",
			  G_CALLBACK (prefwin_chkbtn_toggled),
			  "use_tray_icon");
	g_signal_connect ((gpointer) w->chk_always_notify, "toggled",
			  G_CALLBACK (prefwin_chkbtn_toggled),
			  "always_notify_activities");
	
	g_signal_connect ((gpointer) w->chk_save_window_geo, "toggled",
			  G_CALLBACK (prefwin_chkbtn_toggled),
			  "save_window");
   
	/* Button Callbacks */
	g_signal_connect ((gpointer) w->btn_search, "clicked",
			  G_CALLBACK (prefwin_btn_search_clicked),
			  NULL);
	g_signal_connect ((gpointer) w->btn_encoding_sel, "clicked",
			  G_CALLBACK (prefwin_btn_encoding_sel_clicked),
			  NULL);
	g_signal_connect ((gpointer) w->btn_home_browse, "clicked",
			  G_CALLBACK (prefwin_btn_browse_home_clicked),
			  NULL);
	g_signal_connect ((gpointer) w->btn_browse_purepw, "clicked",
			  G_CALLBACK (prefwin_btn_browse_clicked),
			  (gpointer) w->cmd_purepw);
	g_signal_connect ((gpointer) w->btn_browse_pw, "clicked",
			  G_CALLBACK (prefwin_btn_browse_clicked),
			  (gpointer) w->pwfile);
	g_signal_connect ((gpointer) w->btn_browse_pdb, "clicked",
			  G_CALLBACK (prefwin_btn_browse_clicked),
			  (gpointer) w->pdbfile);

	/* Signals for the prefwindow actual prefwindow */
	g_signal_connect_swapped (G_OBJECT (PW("btn_prefwin_close")),
				  "clicked",
				  G_CALLBACK (gtk_widget_hide),
				  (gpointer) prefwin);
	g_signal_connect (G_OBJECT (prefwin),
			  "delete-event",
			  G_CALLBACK (gtk_widget_hide),
			  NULL);
	g_signal_connect (G_OBJECT (prefwin),
			  "hide",
			  G_CALLBACK (prefwin_close),
			  NULL);

	gtk_window_set_transient_for (GTK_WINDOW (prefwin), GTK_WINDOW (parent));

	return prefwin;
}

static void prefwin_menu_gid_changed (GtkOptionMenu *optionmenu, gpointer user_data)
{
	GList *id;
	gint node_no;
   
	id = (GList *) g_object_get_data (G_OBJECT (optionmenu), "items");
	node_no = gtk_option_menu_get_history (optionmenu);
	id = g_list_nth (id, node_no);
	if (!id)
		g_print ("Gid change: Wrong history: %d\n", node_no);
}

static void prefwin_menu_uid_changed (GtkOptionMenu *optionmenu, gpointer user_data)
{
	GList *id;
	gint node_no;
   
	id = (GList *) g_object_get_data (G_OBJECT (optionmenu), "items");
	node_no = gtk_option_menu_get_history (optionmenu);
	id = g_list_nth (id, node_no);
	if (!id)
		g_print ("Uid change: Wrong history: %d\n", node_no);
}

static void prefwin_rdo_toggled (GtkToggleButton *togglebutton, gpointer user_data)
{
	GtkWidget *entry;
   
	if (!gtk_toggle_button_get_active (togglebutton))
		return;
	entry = PW("entry_logfile");
   
	cfg.logmethod = GPOINTER_TO_INT (user_data);
	switch (GPOINTER_TO_INT (user_data))
	{
	case LOG_SYSLOG: /* Syslog selected */
		gtk_entry_set_text (GTK_ENTRY (entry), "/var/log/messages");
		break;
	case LOG_CUSTOM: /* Custom selected */
		gtk_entry_set_text (GTK_ENTRY (entry), "/var/log/pureftpd.log");
		break;
	}
}

static void prefwin_chkbtn_toggled (GtkToggleButton *togglebutton, gpointer user_data)
{
	gchar *arg = (gchar *) user_data;
	gboolean toggled = gtk_toggle_button_get_active (togglebutton);
	if (g_str_equal (arg, "resolve"))
		cfg.resolve_hostnames = toggled;
	else if (g_str_equal (arg, "save_window"))
		cfg.save_window_geometry = toggled;
	else if (g_str_equal (arg, "use_tray_icon")) {
		if (!toggled)
			/* Remove it if it's shown */
			hide_status_icon ();
		cfg.use_tray_icon = toggled;
	}
	else if (g_str_equal (arg, "always_notify_activities"))
		cfg.always_notify_activities = toggled;
}

static void prefwin_chkencoding_toggled (GtkToggleButton *togglebutton, gpointer user_data)
{
	prefwin_widgets *w;
	gboolean active;
	
	w = prefwin_get_widgets ();
	active = gtk_toggle_button_get_active (togglebutton);
	cfg.use_system_encoding = active;
	gtk_widget_set_sensitive (w->encoding, !active);
	gtk_widget_set_sensitive (w->btn_encoding_sel, !active);
}


static void prefwin_entry_changed (GtkEditable *editable, gpointer user_data)
{
	gchar *tmp;
	gchar *ename;
	ename = (gchar *) user_data;
	tmp = gtk_editable_get_chars (GTK_EDITABLE (editable), 0, -1);
   
	/* g_print ("Entry [%s] changed into: %s\n", ename, tmp); */
	if (g_str_equal (ename, "home"))
	{
		g_free (cfg.default_home);
		cfg.default_home = tmp;
	}
	else if (g_str_equal (ename, "cmd_purepw"))
	{
		g_free (cfg.cmd_purepw);
		cfg.cmd_purepw = tmp;
	}
	else if (g_str_equal (ename, "pwfile"))
	{
		g_free (cfg.pwfile);
		cfg.pwfile = tmp;
	} 
	else if (g_str_equal (ename, "pdbfile"))
	{
		g_free (cfg.pdbfile);
		cfg.pdbfile = tmp;
	}
	else if (g_str_equal(ename, "logfile"))
	{
		if (g_path_is_absolute (tmp) && g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
		{
			close_logfile ();
			g_free (cfg.logfile);
			cfg.logfile = tmp;
			init_logfile ();
		}
		else
			g_free (tmp);
	}
	else if (g_str_equal (ename, "encoding"))
	{
		g_free (cfg.uname_encoding);
		cfg.uname_encoding = tmp;
	}
	else
		g_free (tmp);
}

static void prefwin_btn_search_clicked (GtkButton *button, gpointer user_data)
{
	gchar *tmp;
	prefwin_widgets *w;

	w = prefwin_get_widgets ();

	tmp = g_find_program_in_path ("pure-pw");
	gtk_entry_set_text (GTK_ENTRY (w->cmd_purepw), tmp ? tmp : _("Not Found"));
	g_free (tmp);

	tmp = cfg_find_pwfile ();
	gtk_entry_set_text (GTK_ENTRY (w->pwfile), tmp ? tmp : _("Not Found"));
	g_free (tmp);
	
	tmp = cfg_find_pdbfile ();
	gtk_entry_set_text (GTK_ENTRY (w->pdbfile), tmp ? tmp : _("Not Found"));
	g_free (tmp);
}

static void store_filename (GtkWidget *widget, GtkWidget *fs)
{
	GtkWidget *entry;
	const gchar *selected_filename;

	entry = (GtkWidget *) g_object_get_data (G_OBJECT (fs), "affected_entry");
	selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs));
	
	gtk_entry_set_text (GTK_ENTRY (entry), selected_filename);
}

static GtkWidget *create_fileselector (const gchar *title, const gchar *preselected)
{
	GtkWidget *file_selector;
	
	file_selector = gtk_file_selection_new (title);

	g_signal_connect (GTK_FILE_SELECTION (file_selector)->ok_button,
			  "clicked",
			  G_CALLBACK (store_filename),
			  file_selector);
	
	/* Ensure that the dialog box is destroyed when the user clicks a button. */
	g_signal_connect_swapped (GTK_FILE_SELECTION (file_selector)->ok_button,
				  "clicked",
				  G_CALLBACK (gtk_widget_destroy), 
				  file_selector);
	
	g_signal_connect_swapped (GTK_FILE_SELECTION (file_selector)->cancel_button,
				  "clicked",
				  G_CALLBACK (gtk_widget_destroy),
				  file_selector);
	
	gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_selector),
					 preselected);
	gtk_window_set_transient_for (GTK_WINDOW (file_selector),
				      GTK_WINDOW (PW("preferences")));
	return file_selector;
}

static void prefwin_btn_browse_clicked (GtkButton *button, GtkWidget *entry)
{
	prefwin_widgets *w;
	GtkWidget *fs;
	gchar *title;
	
	w = prefwin_get_widgets ();

	/* Translators: %s will expand to the type of file. For instance, 'password file' or 'database file'.
	 * This is used as title for the file selector. */
	title = g_strdup_printf (_("Please select %s"), (gchar *) g_object_get_data (G_OBJECT (entry), "whatfile"));
	if (strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0)
		fs = create_fileselector (title, gtk_entry_get_text (GTK_ENTRY (entry)));
	else
		fs = create_fileselector (title, g_object_get_data (G_OBJECT(entry), "default_path"));

	g_object_set_data (G_OBJECT (fs), "affected_entry", (gpointer) entry);
	
	gtk_widget_show (fs);
}

static void prefwin_btn_browse_home_clicked (GtkButton *button, gpointer user_data)
{
	prefwin_widgets *w;
	GtkWidget *dbr;
	const gchar *dir;
	gint response;
   
	w = prefwin_get_widgets ();
	dbr = dirbrowser_new (_("Select Default Home Directory"));
	if (g_file_test (cfg.default_home, G_FILE_TEST_IS_DIR))
		dirbrowser_set_directory (DIRBROWSER (dbr), cfg.default_home);

	response = gtk_dialog_run (GTK_DIALOG (dbr));
	if (response == GTK_RESPONSE_OK)
	{
		dir = dirbrowser_get_directory (DIRBROWSER (dbr));
		gtk_entry_set_text (GTK_ENTRY (w->home), dir);
	}
	gtk_widget_destroy (dbr);
}

static void
encoding_changed_cb (GtkTreeView *tree, gpointer user_data)
{
	GtkEntry *entry = GTK_ENTRY (user_data);
	GtkTreeModel *model;
	GtkTreeSelection *sel;
	GtkTreeIter iter;
	gchar *encoding;
	g_print ("encoding changed\n");
	sel = gtk_tree_view_get_selection (tree);
	model = gtk_tree_view_get_model (tree);
	if (gtk_tree_selection_get_selected (sel, &model, &iter))
	{
		gtk_tree_model_get (model, &iter, 
				    0, &encoding,
				    -1);
		gtk_entry_set_text (entry, encoding);
	}
	return;
}

static GList *
get_available_encodings (void)
{
	GList *retval = NULL;
#define BUFSIZE 256
	gchar buf[BUFSIZE], *tmp;
	gchar *prgm, *full_prgm;
	FILE *p;

	if (!(prgm = g_find_program_in_path ("iconv"))) {
		pur_log_wrn ("Couldn't find the program \"iconv\". Unable to fetch list of encodings");
		return NULL;
	}
	
	full_prgm = g_strdup_printf ("%s --list", prgm);
	g_free (prgm);
	if ((p = popen (full_prgm, "r")) == NULL)
	{
		pur_log_wrn ("popen %s: %s", full_prgm, strerror(errno));
		return NULL;
	}
	g_free (full_prgm);
	while (fgets (buf, BUFSIZE, p))
	{
		if (!strstr (buf, "//"))
			continue;
		tmp = buf;
		while (tmp){
			if (*tmp == '/' && *(tmp +1) == '/') {
				*tmp = '\0';
				break;
			}
			tmp++;
		}
		g_strstrip (buf);
		retval = g_list_append (retval, g_strdup (buf));
	}
	pclose (p);

	return retval;
}
static void
free_encoding_list (GtkWidget *w, gpointer list)
{
	g_list_free ((GList *) list);
}

static void
filter_encoding_list (GtkWidget *entry, gpointer data)
{
	GtkTreeView *tree = GTK_TREE_VIEW (data);
	GtkTreeIter iter, iter_sel;
	GtkListStore *model;
	GList *list;
	gint handler_id;
	const gchar *filter_str, *encoding;
	gboolean sel = FALSE;

	filter_str = gtk_entry_get_text (GTK_ENTRY(entry));
	handler_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tree), "callback_handler_id"));
	list = g_object_get_data (G_OBJECT (tree), "encoding_list");
	model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (tree)));
	
	g_signal_handler_block (G_OBJECT (tree), handler_id);
	gtk_list_store_clear (GTK_LIST_STORE (model));
	while (list)
	{
		encoding = (const gchar *) list->data;
		if (misc_str_isearch (encoding, filter_str))
		{
			gtk_list_store_append (GTK_LIST_STORE (model), &iter);
			gtk_list_store_set (GTK_LIST_STORE (model), &iter,
					    0, encoding,
					    -1);
			if (g_str_equal (encoding, cfg.uname_encoding)) {
				memcpy (&iter_sel, &iter, sizeof (GtkTreeIter));
				sel = TRUE;
			}
		}
		list = g_list_next (list);
		
	}
	if (sel)
		gui_select_treeview_row (&iter_sel, tree);
		
	g_signal_handler_unblock (G_OBJECT (tree), handler_id);

	return;
}

static void
prefwin_btn_encoding_sel_clicked (GtkButton *button, gpointer user_data)
{
	prefwin_widgets *w;
	static GtkWidget *dlg = NULL;
	GList *list, *head;
	GtkListStore *model;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *column;
	GtkTreeIter iter, iter_sel;
	GtkTreeView *tree;
	GtkWidget *entry;
	guint handler_id;
	gboolean sel = FALSE;
	
	if (dlg) {
		gtk_window_present (GTK_WINDOW (dlg));
		return;
	}
	w = prefwin_get_widgets ();
	dlg = PW("dlg_encoding");
	tree = GTK_TREE_VIEW (PW("tree_encoding"));
	model  = gtk_list_store_new (1, G_TYPE_STRING);
   
	gtk_tree_view_set_model (GTK_TREE_VIEW (tree), GTK_TREE_MODEL (model));
	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (tree)),
				     GTK_SELECTION_SINGLE);

	renderer = gtk_cell_renderer_text_new();
	column = gtk_tree_view_column_new_with_attributes (NULL, renderer,
							   "text", 0,
							   NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW(tree), column);

	head = list = get_available_encodings ();

	while (list)
	{
		gtk_list_store_append (GTK_LIST_STORE (model), &iter);
		gtk_list_store_set (GTK_LIST_STORE (model), &iter,
				    0, (gchar *) list->data,
				    -1);
		if (g_str_equal ((gchar*) list->data, cfg.uname_encoding)) {
			memcpy (&iter_sel, &iter, sizeof (GtkTreeIter));
			sel = TRUE;
		}
		
		list = g_list_next (list);
	}
	if (sel)
		gui_select_treeview_row (&iter_sel, tree);
	
	
	entry = PW("entry_filter");
	
	g_signal_connect (G_OBJECT (entry), "changed",
			  G_CALLBACK (filter_encoding_list), (gpointer) tree);
	
	handler_id = g_signal_connect (G_OBJECT (tree), "cursor-changed",
				       G_CALLBACK (encoding_changed_cb), w->encoding);
	g_object_set_data (G_OBJECT (tree), "callback_handler_id", GINT_TO_POINTER (handler_id));
	g_object_set_data (G_OBJECT (tree), "encoding_list", head);
	g_signal_connect (G_OBJECT (dlg), "destroy",
			  G_CALLBACK (free_encoding_list), (gpointer) head);
	
	gtk_dialog_run (GTK_DIALOG (dlg));
	
	gtk_widget_destroy (dlg);
	dlg = NULL;
}


syntax highlighted by Code2HTML, v. 0.9.1