/* capture_prefs.c
 * Dialog box for capture preferences
 *
 * $Id: prefs_capture.c 42176 2012-04-21 16:40:14Z etxrab $
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * 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.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef HAVE_LIBPCAP

#include <string.h>
#include <gtk/gtk.h>

#include <epan/prefs.h>

#include "ui/simple_dialog.h"
#include "../capture_ifinfo.h"
#include "../capture_ui_utils.h"

#include "ui/gtk/prefs_capture.h"
#include "ui/gtk/prefs_dlg.h"
#include "ui/gtk/gui_utils.h"
#include "ui/gtk/dlg_utils.h"
#include "ui/gtk/main.h"
#include "ui/gtk/main_welcome.h"
#include "ui/gtk/help_dlg.h"
#include "ui/gtk/stock_icons.h"
#include "ui/gtk/old-gtk-compat.h"
#include <epan/strutil.h>


#define DEVICE_KEY		"device"
#define PROM_MODE_KEY		"prom_mode"
#define PCAP_NG_KEY		"pcap_ng"
#define CAPTURE_REAL_TIME_KEY	"capture_real_time"
#define AUTO_SCROLL_KEY		"auto_scroll"
#define SHOW_INFO_KEY           "show_info"

#define CAPTURE_TABLE_ROWS 6

#define IFOPTS_CALLER_PTR_KEY	"ifopts_caller_ptr"
#define IFOPTS_DIALOG_PTR_KEY	"ifopts_dialog_ptr"
#define IFOPTS_TABLE_ROWS 2
#define IFOPTS_LIST_TEXT_COLS  4
#define IFOPTS_MAX_DESCR_LEN 128
#define IFOPTS_IF_NOSEL -1

/* interface options dialog */
static GtkWidget *cur_list, *if_dev_lb, *if_name_lb, *if_linktype_lb, *if_linktype_cb, *if_descr_te, *if_hide_cb;
#ifdef HAVE_PCAP_CREATE
static GtkWidget *if_monitor_lb, *if_monitor_cb;
#endif
static GtkTreeSelection *if_selection;	/* current interface row selected */
static int num_linktypes;
static gboolean interfaces_info_nochange;  /* TRUE to ignore Interface Options Properties */
                                           /*  widgets "changed" callbacks.               */

static void ifopts_edit_cb(GtkWidget *w, gpointer data);
static void ifopts_edit_ok_cb(GtkWidget *w, gpointer parent_w);
static void ifopts_edit_destroy_cb(GtkWidget *win, gpointer data);
static void ifopts_edit_ifsel_cb(GtkTreeSelection *selection, gpointer data);
#ifdef HAVE_PCAP_CREATE
static void ifopts_edit_monitor_changed_cb(GtkToggleButton *tbt, gpointer udata);
#endif
static void ifopts_edit_linktype_changed_cb(GtkComboBox *ed, gpointer udata);
static void ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata);
static void ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata);
static void ifopts_options_add(GtkListStore *list_store, if_info_t *if_info);
static void ifopts_options_free(gchar *text[]);
static void ifopts_if_liststore_add(void);
#ifdef HAVE_PCAP_CREATE
static void ifopts_write_new_monitor_mode(void);
#endif
static void ifopts_write_new_linklayer(void);
static void ifopts_write_new_descr(void);
static void ifopts_write_new_hide(void);

GtkWidget*
capture_prefs_show(void)
{
	GtkWidget	*main_tb, *main_vb;
	GtkWidget	*if_cbxe, *if_lb, *promisc_cb, *pcap_ng_cb, *sync_cb, *auto_scroll_cb, *show_info_cb;
	GtkWidget	*ifopts_lb, *ifopts_bt;
	GList		*if_list, *combo_list;
	int		err;
	int		row = 0;
	const gchar     *tooltips_text;

	/* Main vertical box */
	main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 7, FALSE);
	gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);

	/* Main table */
	main_tb = gtk_table_new(CAPTURE_TABLE_ROWS, 2, FALSE);
	gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
	gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
	gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
	gtk_widget_show(main_tb);

	/* Default device */
	if_lb = gtk_label_new("Default interface:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_lb), 1.0f, 0.5f);
	gtk_widget_show(if_lb);

	if_cbxe = gtk_combo_box_text_new_with_entry();
	/*
	 * XXX - what if we can't get the list?
	 */
	if_list = capture_interface_list(&err, NULL);
	combo_list = build_capture_combo_list(if_list, FALSE);
	free_interface_list(if_list);
	if (combo_list != NULL) {
		GList *combo_entry;
		for (combo_entry = combo_list; combo_entry != NULL; combo_entry = g_list_next(combo_entry)) {
				 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(if_cbxe), combo_entry->data);
		}
	}
	if (prefs.capture_device) {
		gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(if_cbxe))),
				   prefs.capture_device);
	}
	else if (combo_list != NULL) {
		gtk_combo_box_set_active(GTK_COMBO_BOX(if_cbxe), 0);
	}
	free_capture_combo_list(combo_list);

	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_cbxe, 1, 2, row, row+1);
	tooltips_text = "The default interface to be captured from.";
	gtk_widget_set_tooltip_text(if_lb, tooltips_text);
	gtk_widget_set_tooltip_text(gtk_bin_get_child(GTK_BIN(if_cbxe)), tooltips_text);
	gtk_widget_show(if_cbxe);
	g_object_set_data(G_OBJECT(main_vb), DEVICE_KEY, if_cbxe);
	row++;

	/* Interface properties */
	ifopts_lb = gtk_label_new("Interfaces:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(ifopts_lb), 1.0f, 0.5f);
	gtk_widget_show(ifopts_lb);

	ifopts_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_EDIT);
	tooltips_text = "Open a dialog box to set various interface options.";
	gtk_widget_set_tooltip_text(ifopts_lb, tooltips_text);
	gtk_widget_set_tooltip_text(ifopts_bt, tooltips_text);
	g_signal_connect(ifopts_bt, "clicked", G_CALLBACK(ifopts_edit_cb), NULL);
	gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_bt, 1, 2, row, row+1);
	row++;

	/* Promiscuous mode */
	promisc_cb = create_preference_check_button(main_tb, row++,
	    "Capture packets in promiscuous mode:",
	    "Usually a network card will only capture the traffic sent to its own network address. "
	    "If you want to capture all traffic that the network card can \"see\", mark this option. "
	    "See the FAQ for some more details of capturing packets from a switched network. ",
	    prefs.capture_prom_mode);
	g_object_set_data(G_OBJECT(main_vb), PROM_MODE_KEY, promisc_cb);

	/* Pcap-NG format */
	pcap_ng_cb = create_preference_check_button(main_tb, row++,
	    "Capture packets in pcap-ng format:",
	    "Capture packets in the next-generation capture file format.",
	    prefs.capture_pcap_ng);
	g_object_set_data(G_OBJECT(main_vb), PCAP_NG_KEY, pcap_ng_cb);

	/* Real-time capture */
	sync_cb = create_preference_check_button(main_tb, row++,
	    "Update list of packets in real time:",
	    "Update the list of packets while capture is in progress. "
	    "Don't use this option if you notice packet drops.",
	    prefs.capture_real_time);
	g_object_set_data(G_OBJECT(main_vb), CAPTURE_REAL_TIME_KEY, sync_cb);

	/* Auto-scroll real-time capture */
	auto_scroll_cb = create_preference_check_button(main_tb, row++,
	    "Automatic scrolling in live capture:",
	    "Automatic scrolling of the packet list while live capture is in progress. ",
	    prefs.capture_auto_scroll);
	g_object_set_data(G_OBJECT(main_vb), AUTO_SCROLL_KEY, auto_scroll_cb);

	/* Show capture info dialog */
	show_info_cb = create_preference_check_button(main_tb, row++,
	    "Hide capture info dialog:",
	    "Hide the capture info dialog while capturing. ",
	    !prefs.capture_show_info);
	g_object_set_data(G_OBJECT(main_vb), SHOW_INFO_KEY, show_info_cb);

	/* Show 'em what we got */
	gtk_widget_show_all(main_vb);

	return(main_vb);
}

void
capture_prefs_fetch(GtkWidget *w)
{
	GtkWidget *if_cbxe, *promisc_cb, *pcap_ng_cb, *sync_cb, *auto_scroll_cb, *show_info_cb;
	gchar	*if_text;

	if_cbxe    = (GtkWidget *)g_object_get_data(G_OBJECT(w), DEVICE_KEY);
	promisc_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), PROM_MODE_KEY);
	pcap_ng_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), PCAP_NG_KEY);
	sync_cb    = (GtkWidget *)g_object_get_data(G_OBJECT(w), CAPTURE_REAL_TIME_KEY);
	auto_scroll_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), AUTO_SCROLL_KEY);
        show_info_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), SHOW_INFO_KEY);

	if (prefs.capture_device != NULL) {
		g_free(prefs.capture_device);
		prefs.capture_device = NULL;
	}
	if_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(if_cbxe)))));
	/* Strip out white space */
	g_strstrip(if_text);
	/* If there was nothing but white space, treat that as an
	   indication that the user doesn't want to wire in a default
	   device, and just wants the first device in the list chosen. */
	if (*if_text == '\0') {
		g_free(if_text);
		if_text = NULL;
	}
	prefs.capture_device = if_text;

	prefs.capture_prom_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(promisc_cb));

	prefs.capture_pcap_ng = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pcap_ng_cb));

	prefs.capture_real_time = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sync_cb));

	prefs.capture_auto_scroll = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(auto_scroll_cb));

	prefs.capture_show_info = !(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(show_info_cb)));
}

void
capture_prefs_apply(GtkWidget *w _U_)
{
}

void
capture_prefs_destroy(GtkWidget *w)
{
	GtkWidget *caller = gtk_widget_get_toplevel(w);
	GtkWidget *dlg;

	/* Is there an interface descriptions dialog associated with this
	   Preferences dialog? */
	dlg = g_object_get_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY);

	if (dlg != NULL) {
		/* Yes.  Destroy it. */
		window_destroy(dlg);
	}
}

/*
 * Create an edit interface options dialog.
 */
enum
{
	DEVICE_COLUMN,
	DESC_COLUMN,
#ifdef HAVE_PCAP_CREATE
	DEF_MONITOR_MODE_COLUMN,
#endif
	DEF_LINK_LAYER_COLUMN,
	COMMENT_COLUMN,
	HIDE_COLUMN,
	DLT_COLUMN,
	N_COLUMN /* The number of columns */
};

static void
ifopts_edit_cb(GtkWidget *w, gpointer data _U_)
{
	GtkWidget	  *ifopts_edit_dlg, *cur_scr_win, *main_hb, *main_tb,
			  *cur_opts_fr, *ed_opts_fr, *main_vb,
			  *if_descr_lb,
			  *if_hide_lb,
			  *bbox, *ok_bt, *cancel_bt, *help_bt;

	GtkListStore	  *list_store;
	GtkWidget	  *list;
	GtkTreeViewColumn *column;
	GtkCellRenderer   *renderer;
 	GtkTreeView       *list_view;
	GtkTreeSelection  *selection;

	int row = 0;

	GtkWidget   *caller   = gtk_widget_get_toplevel(w);

	/* Has an edit dialog box already been opened for that top-level
	   widget? */
	ifopts_edit_dlg = g_object_get_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY);
	if (ifopts_edit_dlg != NULL) {
		/* Yes.  Just re-activate that dialog box. */
		reactivate_window(ifopts_edit_dlg);
		return;
	}

	/* create a new dialog */
	ifopts_edit_dlg = dlg_conf_window_new("Wireshark: Preferences: Interface Options");
	gtk_window_set_default_size(GTK_WINDOW(ifopts_edit_dlg), 1000, 440);

	main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 1, FALSE);
	gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
	gtk_container_add(GTK_CONTAINER(ifopts_edit_dlg), main_vb);
	gtk_widget_show(main_vb);

	/* create current options frame */
	cur_opts_fr = gtk_frame_new("Interfaces");
	gtk_container_add(GTK_CONTAINER(main_vb), cur_opts_fr);
	gtk_widget_show(cur_opts_fr);

	/* create a scrolled window to pack the current options TreeView widget into */
	cur_scr_win = scrolled_window_new(NULL, NULL);
	gtk_container_set_border_width(GTK_CONTAINER(cur_scr_win), 3);
	gtk_container_add(GTK_CONTAINER(cur_opts_fr), cur_scr_win);
	gtk_widget_show(cur_scr_win);

	/*
	 * Create current options TreeView.
	 */
	list_store = gtk_list_store_new(N_COLUMN,	/* Total number of columns XXX	*/
					G_TYPE_STRING,	/* Device			*/
					G_TYPE_STRING,	/* Description			*/
#ifdef HAVE_PCAP_CREATE
					G_TYPE_BOOLEAN,	/* Monitor mode		*/
#endif
					G_TYPE_STRING,	/* Default link-layer		*/
					G_TYPE_STRING,	/* Comment			*/
					G_TYPE_BOOLEAN,	/* Hide?			*/
					G_TYPE_INT);	/* Dlt 				*/

	list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));

	list_view = GTK_TREE_VIEW(list);

	/* The view now holds a reference.  We can get rid of our own reference */
	g_object_unref (G_OBJECT (list_store));

	/*
	 * Create the first column packet, associating the "text" attribute of the
	 * cell_renderer to the first column of the model
	 */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes ("Device", renderer,
							   "text", DEVICE_COLUMN,
							   NULL);

	gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
#ifdef _WIN32
	gtk_tree_view_column_set_min_width(column, 230);
#else
	gtk_tree_view_column_set_min_width(column, 70);
#endif
	/* Add the column to the view. */
	gtk_tree_view_append_column (list_view, column);

	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes ("Description", renderer,
							   "text", DESC_COLUMN,
							   NULL);

	gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
	gtk_tree_view_column_set_min_width(column, 260);
	/* Add the column to the view. */
	gtk_tree_view_append_column (list_view, column);

#ifdef HAVE_PCAP_CREATE
	/*
	 * XXX - for some reason, this doesn't show up.
	 */
	renderer = gtk_cell_renderer_toggle_new ();
	column = gtk_tree_view_column_new_with_attributes ("Default to monitor mode", renderer,
							   "active", DEF_MONITOR_MODE_COLUMN,
							   NULL);

	gtk_tree_view_column_set_resizable(column, FALSE);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
	/* Add the column to the view. */
	gtk_tree_view_append_column (list_view, column);
#endif

	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes ("Default link-layer", renderer,
							   "text", DEF_LINK_LAYER_COLUMN,
							   NULL);

	gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
	gtk_tree_view_column_set_min_width(column, 230);
	/* Add the column to the view. */
	gtk_tree_view_append_column (list_view, column);

	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes ("Comment", renderer,
							   "text", COMMENT_COLUMN,
							   NULL);

	gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
	gtk_tree_view_column_set_min_width(column, 100);
	/* Add the column to the view. */
	gtk_tree_view_append_column (list_view, column);

	renderer = gtk_cell_renderer_toggle_new ();
	column = gtk_tree_view_column_new_with_attributes ("Hide?", renderer,
							   "active", HIDE_COLUMN,
							   NULL);

	gtk_tree_view_column_set_resizable(column, FALSE);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
	/* Add the column to the view. */
	gtk_tree_view_append_column (list_view, column);

#if 0
	/* Don't show the DLT column */
	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes ("DLT", renderer,
							   "text", DLT_COLUMN,
							   NULL);

	gtk_tree_view_column_set_resizable(column, TRUE);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
	gtk_tree_view_column_set_min_width(column, 40);
	/* Add the column to the view. */
	gtk_tree_view_append_column (list_view, column);
#endif
	/* Setup the selection handler */
	selection = gtk_tree_view_get_selection(list_view);
	gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);

	cur_list = list;
	gtk_container_add(GTK_CONTAINER(cur_scr_win), cur_list);

	if_selection = selection;

	g_signal_connect (G_OBJECT (selection), "changed", /* select_row */
			  G_CALLBACK (ifopts_edit_ifsel_cb),
			  NULL);

	gtk_widget_show(cur_list);

	/* add interface names to cell */
	ifopts_if_liststore_add();

	/* create edit options frame */
	ed_opts_fr = gtk_frame_new("Properties");
	gtk_box_pack_start(GTK_BOX(main_vb), ed_opts_fr, FALSE, FALSE, 0);
	gtk_widget_show(ed_opts_fr);

	main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5, TRUE);
	gtk_container_set_border_width(GTK_CONTAINER(main_hb), 3);
	gtk_container_add(GTK_CONTAINER(ed_opts_fr), main_hb);
	gtk_widget_show(main_hb);

	/* table to hold description text entry and hide button */
	main_tb = gtk_table_new(IFOPTS_TABLE_ROWS, 4, FALSE);
	gtk_box_pack_start(GTK_BOX(main_hb), main_tb, TRUE, FALSE, 10);
	gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
	gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
	gtk_widget_show(main_tb);

	if_dev_lb = gtk_label_new("Device:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 1.0f, 0.5f);
	gtk_widget_show(if_dev_lb);

	if_dev_lb = gtk_label_new("");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 1, 2, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 0.0f, 0.5f);
	gtk_widget_show(if_dev_lb);
	row++;

	if_name_lb = gtk_label_new("Description:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_name_lb), 1.0f, 0.5f);
	gtk_widget_show(if_name_lb);

	if_name_lb = gtk_label_new("");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 1, 2, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_name_lb), 0.0f, 0.5f);
	gtk_widget_show(if_name_lb);
	row++;

#ifdef HAVE_PCAP_CREATE
	/* create "monitor mode" label and button */
	if_monitor_lb = gtk_label_new("Monitor mode:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_monitor_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_monitor_lb), 1.0f, 0.5f);
	gtk_widget_show(if_monitor_lb);

	if_monitor_cb = gtk_check_button_new();
	g_signal_connect(if_monitor_cb, "toggled", G_CALLBACK(ifopts_edit_monitor_changed_cb),
			cur_list);
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_monitor_cb, 1, 2, row, row+1);
	gtk_widget_show(if_monitor_cb);
        row++;
#endif

	if_linktype_lb = gtk_label_new("Default link-layer header type:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_linktype_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_linktype_lb), 1.0f, 0.5f);
	gtk_widget_show(if_linktype_lb);

	if_linktype_cb = gtk_combo_box_text_new();
	num_linktypes = 0;
	interfaces_info_nochange = FALSE;
	g_signal_connect(if_linktype_cb, "changed", G_CALLBACK(ifopts_edit_linktype_changed_cb),
			cur_list);
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_linktype_cb, 1, 2, row, row+1);
	gtk_widget_show(if_linktype_cb);
	row++;

	/* create interface description label and text entry */
	if_descr_lb = gtk_label_new("Comment:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_descr_lb), 1.0f, 0.5f);
	gtk_widget_show(if_descr_lb);

	if_descr_te = gtk_entry_new();
	g_signal_connect(if_descr_te, "changed", G_CALLBACK(ifopts_edit_descr_changed_cb),
			cur_list);
	gtk_entry_set_max_length(GTK_ENTRY(if_descr_te), IFOPTS_MAX_DESCR_LEN);
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_te, 1, 2, row, row+1);
	gtk_widget_show(if_descr_te);
	row++;

	/* create "hide interface" label and button */
	if_hide_lb = gtk_label_new("Hide interface?:");
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_lb, 0, 1, row, row+1);
	gtk_misc_set_alignment(GTK_MISC(if_hide_lb), 1.0f, 0.5f);
	gtk_widget_show(if_hide_lb);

	if_hide_cb = gtk_check_button_new();
	g_signal_connect(if_hide_cb, "toggled", G_CALLBACK(ifopts_edit_hide_changed_cb),
			cur_list);
	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_cb, 1, 2, row, row+1);
	gtk_widget_show(if_hide_cb);
        row++;

	/* button row: OK and Cancel buttons */
	bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
	gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
	gtk_widget_show(bbox);

	ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
	gtk_widget_set_tooltip_text(ok_bt, "Save changes and exit dialog");
	g_signal_connect(ok_bt, "clicked", G_CALLBACK(ifopts_edit_ok_cb), ifopts_edit_dlg);

	cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
	gtk_widget_set_tooltip_text(cancel_bt, "Cancel and exit dialog");
        window_set_cancel_button(ifopts_edit_dlg, cancel_bt, window_cancel_button_cb);

	help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
	g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb),
			 (gpointer)HELP_CAPTURE_INTERFACE_OPTIONS_DIALOG);
	gtk_widget_set_tooltip_text (help_bt, "Show topic specific help");

	gtk_widget_grab_default(ok_bt);

	g_signal_connect(ifopts_edit_dlg, "delete_event", G_CALLBACK(window_delete_event_cb),
                 NULL);
	/* Call a handler when we're destroyed, so we can inform
	   our caller, if any, that we've been destroyed. */
	g_signal_connect(ifopts_edit_dlg, "destroy", G_CALLBACK(ifopts_edit_destroy_cb), NULL);

	/* Set the key for the new dialog to point to our caller. */
	g_object_set_data(G_OBJECT(ifopts_edit_dlg), IFOPTS_CALLER_PTR_KEY, caller);
	/* Set the key for the caller to point to us */
	g_object_set_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY, ifopts_edit_dlg);

	gtk_widget_show(ifopts_edit_dlg); /* triggers ifopts_edit_ifsel_cb() with the  */
                                          /*  "interfaces" TreeView first row selected */
	window_present(ifopts_edit_dlg);
}

/*
 * User selected "OK". Create/write preferences strings.
 */
static void
ifopts_edit_ok_cb(GtkWidget *w _U_, gpointer parent_w)
{
	if (if_selection){ /* XXX: Cannot be NULL ?? */
#ifdef HAVE_PCAP_CREATE
		/* create/write new monitor-mode interfaces string */
		ifopts_write_new_monitor_mode();
#endif

		/* create/write new interfaces link-layer string */
		ifopts_write_new_linklayer();

		/* create/write new interfaces description string */
		ifopts_write_new_descr();

		/* create/write new "hidden" interfaces string */
		ifopts_write_new_hide();
	}

	/* Update welcome page */
	welcome_if_panel_reload ();

	/* Now nuke this window. */
	gtk_grab_remove(GTK_WIDGET(parent_w));
	window_destroy(GTK_WIDGET(parent_w));
}

static void
ifopts_edit_destroy_cb(GtkWidget *win, gpointer data _U_)
{
	GtkWidget *caller;

	/* Get the widget that requested that we be popped up, if any.
	   (It should arrange to destroy us if it's destroyed, so
	   that we don't get a pointer to a non-existent window here.) */
	caller = g_object_get_data(G_OBJECT(win), IFOPTS_CALLER_PTR_KEY);

	if (caller != NULL) {
		/* Tell it we no longer exist. */
                g_object_set_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY, NULL);
	}
}

static gint
ifopts_description_to_val (const char *if_name, gboolean monitor_mode,
    const char *descr)
{
	if_capabilities_t *caps;
	int dlt = -1;

	caps = capture_get_if_capabilities(if_name, monitor_mode, NULL);
	if (caps != NULL) {
		if (caps->data_link_types != NULL) {
			GList  *lt_entry;
			/* XXX: Code skips first entry because that's the default ??? */
			for (lt_entry = g_list_next(caps->data_link_types);
			    lt_entry != NULL;
			    lt_entry = g_list_next(lt_entry)) {
				data_link_info_t *dli_p = lt_entry->data;
				if (dli_p->description) {
					if (strcmp(dli_p->description, descr) == 0) {
						dlt = dli_p->dlt;
						break;
					}
				} else {
					if (strcmp(dli_p->name, descr) == 0) {
						dlt = dli_p->dlt;
						break;
					}
				}
			}
		}
		free_if_capabilities(caps);
	}
	return dlt;
}

/*
 * Interface selected callback; update displayed widgets.
 */
static void
ifopts_edit_ifsel_cb(GtkTreeSelection	*selection _U_,
		     gpointer		 data _U_)
{
	GtkTreeIter         iter;
	GtkTreeModel       *model;
	gchar              *desc, *comment, *text;
	gchar              *if_name, *linktype;
#ifdef HAVE_PCAP_CREATE
	gboolean            monitor_mode;
#endif
	gboolean            hide;
	if_capabilities_t  *caps;
	gint                selected = 0;

	/* Get list_store data for currently selected interface */
	if (!gtk_tree_selection_get_selected (if_selection, &model, &iter)){
		return;
	}
	gtk_tree_model_get(model, &iter,
			   DEVICE_COLUMN,             &if_name,
			   DESC_COLUMN,               &desc,
#ifdef HAVE_PCAP_CREATE
			   DEF_MONITOR_MODE_COLUMN,   &monitor_mode,
#endif
			   DEF_LINK_LAYER_COLUMN,     &linktype,
			   COMMENT_COLUMN,            &comment,
			   HIDE_COLUMN,               &hide,
			   -1);

	/* display  the interface device from current interfaces selection */
	gtk_label_set_text(GTK_LABEL(if_dev_lb), if_name);

	/* display the interface name from current interfaces selection */
	gtk_label_set_text(GTK_LABEL(if_name_lb), desc);

	/* Ignore "changed" callbacks while we update the Properties widgets */
	interfaces_info_nochange = TRUE;

	/* display the link-layer header type from current interfaces selection */
        /*  -- remove old linktype list (if any) from the ComboBox */
	while (num_linktypes > 0) {
		num_linktypes--;
		gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(if_linktype_cb), num_linktypes);
	}

        /*
	 * -- set the state and sensitivity of the monitor-mode checkbox,
	 * and build and add to the ComboBox a linktype list, corresponding
	 * to the interface capabilities of the selected interface
	 */
#ifdef HAVE_PCAP_CREATE
	caps = capture_get_if_capabilities(if_name, monitor_mode, NULL);
#else
	caps = capture_get_if_capabilities(if_name, FALSE, NULL);
#endif
	if (caps != NULL) {
#ifdef HAVE_PCAP_CREATE
		gtk_widget_set_sensitive(if_monitor_lb, caps->can_set_rfmon);
		gtk_widget_set_sensitive(if_monitor_cb, caps->can_set_rfmon);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_monitor_cb), monitor_mode);
#endif
		if (caps->data_link_types != NULL) {
			GList *lt_entry;
			for (lt_entry = caps->data_link_types; lt_entry != NULL;
			    lt_entry = g_list_next(lt_entry)) {
				data_link_info_t *dli_p = lt_entry->data;
				text = (dli_p->description != NULL) ? dli_p->description : dli_p->name;
				if (strcmp(linktype, text) == 0) {
					selected = num_linktypes;
				}
				 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(if_linktype_cb), text);
				num_linktypes++;
			}
			gtk_widget_set_sensitive(if_linktype_lb, num_linktypes >= 2);
			gtk_widget_set_sensitive(if_linktype_cb, num_linktypes >= 2);
			gtk_combo_box_set_active(GTK_COMBO_BOX(if_linktype_cb), selected);
		}
		free_if_capabilities(caps);
	}
#ifdef HAVE_PCAP_CREATE
	else {
		gtk_widget_set_sensitive(if_monitor_lb, FALSE);
		gtk_widget_set_sensitive(if_monitor_cb, FALSE);
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_monitor_cb), FALSE);
	}
#endif

	/* display the interface description from current interfaces selection */
	gtk_entry_set_text(GTK_ENTRY(if_descr_te), comment);

	/* display the "hide interface" button state from current interfaces selection */
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), hide);

	interfaces_info_nochange = FALSE;

	g_free(if_name);
	g_free(desc);
	g_free(linktype);
	g_free(comment);
}

#ifdef HAVE_PCAP_CREATE
/*
 * Monitor-mode toggle button changed callback; update displayed widgets
 * (the list of link-layer types might change) and list_store for currently
 * selected interface.
 */
static void
ifopts_edit_monitor_changed_cb(GtkToggleButton *tbt, gpointer udata)
{
	GtkTreeModel      *list_model;
	GtkTreeIter        list_iter;
	GtkListStore      *list_store;
	gchar             *if_name, *text;
	gboolean           monitor_mode;
	if_capabilities_t *caps;

	if (interfaces_info_nochange)
		return;

	if (if_selection == NULL) /* XXX: Cannot be NULL ?? */
		return;

	if (!gtk_tree_selection_get_selected (if_selection, &list_model, &list_iter)){
		return;
	}
	gtk_tree_model_get(list_model, &list_iter,
			   DEVICE_COLUMN,  &if_name,
			   -1);

	/* Ignore "changed" callbacks while we update the Properties widgets */
	interfaces_info_nochange = TRUE;

	/* display the link-layer header type from current interfaces selection */
        /*  -- remove old linktype list (if any) from the ComboBox */
	while (num_linktypes > 0) {
		num_linktypes--;
		gtk_combo_box_text_remove(GTK_COMBO_BOX_TEXT(if_linktype_cb), num_linktypes);
	}

	list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (udata))); /* Get store */

#ifdef HAVE_PCAP_CREATE
	/* get "monitor mode" button state and set status in list_store for currently selected interface */
	monitor_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tbt));
	gtk_list_store_set  (list_store, &list_iter,
			     DEF_MONITOR_MODE_COLUMN, monitor_mode,
			     -1);
	caps = capture_get_if_capabilities(if_name, monitor_mode, NULL);
#else
	/* no monitor-mode support */
	caps = capture_get_if_capabilities(if_name, FALSE, NULL);
#endif

        /*
	 * -- set the sensitivity of the monitor-mode checkbox, and
	 * build and add to the ComboBox a linktype list for the current
	 * interfaces selection, based on the interface capabilities
	 */
	if (caps != NULL) {
#ifdef HAVE_PCAP_CREATE
		gtk_widget_set_sensitive(if_monitor_lb, caps->can_set_rfmon);
		gtk_widget_set_sensitive(if_monitor_cb, caps->can_set_rfmon);
#endif
		if (caps->data_link_types != NULL) {
			GList *lt_entry;
			for (lt_entry = caps->data_link_types; lt_entry != NULL;
			    lt_entry = g_list_next(lt_entry)) {
				data_link_info_t *dli_p = lt_entry->data;
				text = (dli_p->description != NULL) ? dli_p->description : dli_p->name;
				 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT(if_linktype_cb), text);
				num_linktypes++;
			}
			gtk_widget_set_sensitive(if_linktype_lb, num_linktypes >= 2);
			gtk_widget_set_sensitive(if_linktype_cb, num_linktypes >= 2);
			gtk_combo_box_set_active(GTK_COMBO_BOX(if_linktype_cb), 0);
		}
		free_if_capabilities(caps);
	}
#ifdef HAVE_PCAP_CREATE
	else {
		gtk_widget_set_sensitive(if_monitor_lb, FALSE);
		gtk_widget_set_sensitive(if_monitor_cb, FALSE);
	}
#endif

	interfaces_info_nochange = FALSE;
	g_signal_emit_by_name(if_linktype_cb, "changed");

	g_free(if_name);
}
#endif

/*
 * Link-layer entry changed callback; update list_store for currently selected interface.
 */
static void
ifopts_edit_linktype_changed_cb(GtkComboBox *cb, gpointer udata)
{
	gchar        *ifnm, *text;
#ifdef HAVE_PCAP_CREATE
	gboolean      monitor_mode;
#endif
	gint          linktype;
	GtkTreeModel *list_model;
	GtkTreeIter   list_iter;
	GtkListStore *list_store;

	if (interfaces_info_nochange)
		return;

	if (if_selection == NULL)  /* XXX: Cannot be NULL ?? */
		return;

	if (!gtk_tree_selection_get_selected (if_selection, &list_model, &list_iter)){
		return;
	}

	gtk_tree_model_get(list_model, &list_iter,
		DEVICE_COLUMN,           &ifnm,
#ifdef HAVE_PCAP_CREATE
		DEF_MONITOR_MODE_COLUMN, &monitor_mode,
#endif
		-1);

	/* get current description text and set value in list_store for currently selected interface */
	text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT(cb));
	if (text) {
#ifdef HAVE_PCAP_CREATE
		linktype = ifopts_description_to_val(ifnm, monitor_mode, text);
#else
		linktype = ifopts_description_to_val(ifnm, FALSE, text);
#endif
		list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (udata))); /* Get store */
		gtk_list_store_set  (list_store, &list_iter,
				     DEF_LINK_LAYER_COLUMN, text,
				     DLT_COLUMN, linktype,
				     -1);
		g_free(text);
	}
}

/*
 * Comment text entry changed callback; update list_store for currently selected interface.
 */
static void
ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata)
{
	gchar        *text;
	GtkTreeModel *list_model;
	GtkTreeIter   list_iter;
	GtkListStore *list_store;

	if (interfaces_info_nochange)
		return;

	if (if_selection == NULL) /* XXX: Cannot be NULL ?? */
		return;

	if (!gtk_tree_selection_get_selected (if_selection, &list_model, &list_iter)){
		return;
	}

	/* get current description text and set value in list_store for currently selected interface */
	text = gtk_editable_get_chars(GTK_EDITABLE(ed), 0, -1);
	/* replace any reserved formatting characters "()," with spaces */
	g_strdelimit(text, "(),", ' ');

	list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (udata))); /* Get store */
	gtk_list_store_set  (list_store, &list_iter,
			     COMMENT_COLUMN, text,
			     -1);

	g_free(text);
}

/*
 * Hide toggle button changed callback; update list_store for currently selected interface .
 */
static void
ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata)
{
	GtkTreeModel *list_model;
	GtkTreeIter   list_iter;
	GtkListStore *list_store;

	if (interfaces_info_nochange)
		return;

	if (if_selection == NULL) /* XXX: Cannot be NULL ?? */
		return;

	if (!gtk_tree_selection_get_selected (if_selection, &list_model, &list_iter)){
		return;
	}

	list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (udata))); /* Get store */
	/* get "hide" button state and set status in list_store for currently selected interface */
	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tbt)) == TRUE)
		gtk_list_store_set  (list_store, &list_iter,
				     HIDE_COLUMN, TRUE,
				     -1);
	else
		gtk_list_store_set  (list_store, &list_iter,
				     HIDE_COLUMN, FALSE,
				     -1);
}

/*
 * Add any saved interface options that apply to interfaces ListStore.
 *
 * NOTE:
 *		Interfaces that have been removed from the machine or disabled and
 *		no longer apply are ignored. Therefore, if the user subsequently
 *		selects "OK", the options for these interfaces are lost (they're
 *		lost permanently if "Save" is selected).
 */
static void
ifopts_options_add(GtkListStore *list_store, if_info_t *if_info)
{
	gchar	*p;
	gchar	*ifnm;
	gchar	*desc;
	gchar	*pr_descr;
	gchar	*text[] = { NULL, NULL, NULL, NULL };
	if_capabilities_t *caps;
#ifdef HAVE_PCAP_CREATE
	gboolean monitor_mode;
#endif
	gint     linktype;
	gboolean hide;
	GtkTreeIter  iter;

	/* set device name text */
	text[0] = g_strdup(if_info->name);

	/* set OS description */
	if (if_info->description != NULL)
		text[1] = g_strdup(if_info->description);
	else
		text[1] = g_strdup("");

#ifdef HAVE_PCAP_CREATE
	/* get default monitor mode setting */
	monitor_mode = prefs_capture_device_monitor_mode(if_info->name);
	caps = capture_get_if_capabilities(if_info->name, monitor_mode, NULL);
#else
	/* no monitor-mode support */
	caps = capture_get_if_capabilities(if_info->name, FALSE, NULL);
#endif

	/* set default link-layer header type */
	linktype = capture_dev_user_linktype_find(if_info->name);
	if (caps != NULL) {
		if (caps->data_link_types != NULL) {
			GList  *lt_entry;
			for (lt_entry = caps->data_link_types; lt_entry != NULL;
			    lt_entry = g_list_next(lt_entry)) {
				data_link_info_t *dli_p = lt_entry->data;
				/* If we have no previous link-layer header type we use the first one */
				if (linktype == -1 || linktype == dli_p->dlt) {
					if (dli_p->description) {
						text[2] = g_strdup(dli_p->description);
					} else {
						text[2] = g_strdup(dli_p->name);
					}
					break;
				}
			}
		}
		free_if_capabilities(caps);
	}
	/* if we have no link-layer */
	if (text[2] == NULL)
		text[2] = g_strdup("");

	/* add interface descriptions */
	if (prefs.capture_devices_descr != NULL) {
		/* create working copy of device descriptions */
		pr_descr = g_strdup(prefs.capture_devices_descr);

		/* if we find a description for this interface */
		if ((ifnm = strstr(pr_descr, if_info->name)) != NULL) {
			p = ifnm;
			while (*p != '\0') {
				/* found left parenthesis, start of description */
				if (*p == '(') {
					p++;
					/* if syntax error */
					if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')'))
						break;

					/* save pointer to beginning of description */
					desc = p;
					p++;
					/* skip to end of description */
					while (*p != '\0') {
						/* if syntax error */
						if ((*p == ',') || (*p == '('))
							break;

						/* end of description */
						else if (*p == ')') {
							/* terminate and set description text */
							*p = '\0';
							text[3] = g_strdup(desc);
							break;
						}
						p++;
					}
					/* get out */
					break;
				} else
					p++;
			}
		}

		g_free(pr_descr);
	}

	/* if we have no description */
	if (text[3] == NULL)
		text[3] = g_strdup("");

	/* check if interface is "hidden" */
	hide = prefs_is_capture_device_hidden(if_info->name);

	/* add row to ListStore */

	gtk_list_store_insert_with_values( list_store , &iter, G_MAXINT,
			     DEVICE_COLUMN,           text[0],
			     DESC_COLUMN,             text[1],
#ifdef HAVE_PCAP_CREATE
			     DEF_MONITOR_MODE_COLUMN, monitor_mode,
#endif
			     DEF_LINK_LAYER_COLUMN,   text[2],
			     COMMENT_COLUMN,          text[3],
			     HIDE_COLUMN,             hide,
			     DLT_COLUMN,              linktype,
			     -1);

	ifopts_options_free(text);
}

static void
ifopts_options_free(gchar *text[])
{
	gint i;

	for (i=0; i < IFOPTS_LIST_TEXT_COLS; i++) {
		if (text[i] != NULL) {
			g_free(text[i]);
			text[i] = NULL;
		}
	}
}

/*
 * Add all interfaces to interfaces ListStore.
 */
static void
ifopts_if_liststore_add(void)
{
	GList	*if_list, *ifl_p;
	int	 err;
	gchar	*err_str;

	if_list = capture_interface_list(&err, &err_str);  /* if_list = ptr to first element of list (or NULL) */
	if (if_list == NULL) {
		if (err != NO_INTERFACES_FOUND) {
			simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
		}
		g_free(err_str);
		return;
	}

	/* We have an interface list.                            */
	/* add OS description + interface name text to ListStore */
	for (ifl_p = if_list; ifl_p != NULL; ifl_p = g_list_next(ifl_p)) {
		/* should never happen, but just in case */
		if ((ifl_p->data) == NULL)
			continue;
		/* fill current options ListStore with current preference values */
		ifopts_options_add(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (cur_list))),
				   (if_info_t *)ifl_p->data);
	}
	free_interface_list(if_list);
}

#ifdef HAVE_PCAP_CREATE
/*
 * Create/write new "monitor mode" interfaces string based on current CList.
 * Put it into the preferences value.
 */
static void
ifopts_write_new_monitor_mode(void)
{
	GtkListStore 	*store;
	GtkTreeIter 	 iter;
	GtkTreeModel 	*model;
	gboolean	 more_items = TRUE;
	gint		 first_if = TRUE;	/* flag to check if first in list */
	gchar		*ifnm;
	gboolean	 monitor_mode;
	gchar		*new_monitor_mode;

	/* new preferences "monitor mode" interfaces string */
	new_monitor_mode = g_malloc0(MAX_VAL_LEN);

	/* get "monitor mode" flag text for each row (interface) */
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(cur_list));
	store = GTK_LIST_STORE(model);
	if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) ) {
		while (more_items) {
			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
					   DEVICE_COLUMN,           &ifnm,
					   DEF_MONITOR_MODE_COLUMN, &monitor_mode,
					   -1);

			/* if flag text is "No", skip this interface */
			if (!monitor_mode){
				more_items = gtk_tree_model_iter_next (model,&iter);
				continue;
			}

			/*
			 * create/cat interface to new string
			 */
			if (first_if != TRUE)
				g_strlcat (new_monitor_mode, ",", MAX_VAL_LEN);
			g_strlcat (new_monitor_mode, ifnm, MAX_VAL_LEN);

			/* set first-in-list flag to false */
			first_if = FALSE;
			more_items = gtk_tree_model_iter_next (model,&iter);
		}

		/* write new "hidden" string to preferences */
		if (strlen(new_monitor_mode) > 0) {
			g_free(prefs.capture_devices_monitor_mode);
			prefs.capture_devices_monitor_mode = new_monitor_mode;
		}
		/* no "hidden" interfaces */
		else {
			g_free(prefs.capture_devices_monitor_mode);
			g_free(new_monitor_mode);
			prefs.capture_devices_monitor_mode = NULL;
		}
	}
}
#endif

/*
 * Create/write new interfaces link-layer string based on current CList.
 * Put it into the preferences value.
 */
static void
ifopts_write_new_linklayer(void)
{
	GtkListStore	*store;
	GtkTreeIter	 iter;
	GtkTreeModel 	*model;

	gboolean	 more_items = TRUE, first_if = TRUE;  /* flag to check if first in list */
	gchar		*ifnm;
	gint		 linktype;
	gchar		*tmp_linklayer;
	gchar		*new_linklayer;

	/* new preferences interfaces link-layer string */
	new_linklayer = g_malloc0(MAX_VAL_LEN);

	/* get link-layer for each row (interface) */
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(cur_list));
	store = GTK_LIST_STORE(model);
	if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) ) {

		while (more_items) {
			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
					   DEVICE_COLUMN, &ifnm,
					   DLT_COLUMN,    &linktype,
					   -1);

			if (linktype == -1){
				more_items = gtk_tree_model_iter_next (model,&iter);
				continue;
			}

			if (first_if != TRUE) {
				g_strlcat (new_linklayer, ",", MAX_VAL_LEN);
			}
			/*
			 * create/cat interface link-layer to new string
			 * (leave space for parens, comma and terminator)
			 */
			tmp_linklayer = g_strdup_printf("%s(%d)", ifnm, linktype);
			g_strlcat(new_linklayer, tmp_linklayer, MAX_VAL_LEN);
			g_free(tmp_linklayer);
			g_free(ifnm);
			/* set first-in-list flag to false */
			first_if = FALSE;
			more_items = gtk_tree_model_iter_next (model,&iter);
		}

		/* write new link-layer string to preferences */
		if (strlen(new_linklayer) > 0) {
			g_free(prefs.capture_devices_linktypes);
			prefs.capture_devices_linktypes = new_linklayer;
		}
		/* no link-layers */
		else {
			g_free(prefs.capture_devices_linktypes);
			g_free(new_linklayer);
			prefs.capture_devices_linktypes = NULL;
		}
	}
}

/*
 * Create/write new interfaces description string based on current CList.
 * Put it into the preferences value.
 */
static void
ifopts_write_new_descr(void)
{
	GtkListStore	*store;
	GtkTreeIter	 iter;
	GtkTreeModel	*model;
	gboolean	 more_items = TRUE;
	gboolean	 first_if = TRUE;	/* flag to check if first in list */
	gchar		*ifnm;
	gchar		*desc;
	gchar		*tmp_descr;
	gchar		*new_descr;

	/* new preferences interfaces description string */
	new_descr = g_malloc0(MAX_VAL_LEN);

	/* get description for each row (interface) */
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(cur_list));
	store = GTK_LIST_STORE(model);
	if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) ) {
		while (more_items) {
			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
				DEVICE_COLUMN, &ifnm,
				COMMENT_COLUMN, &desc,
				-1);

			/* if no description, skip this interface */
			if (strlen(desc) == 0){
				more_items = gtk_tree_model_iter_next (model,&iter);
				continue;
			}
			/*
			 * create/cat interface description to new string
			 * (leave space for parens, comma and terminator)
			 */
			if (first_if != TRUE) {
				g_strlcat (new_descr, ",", MAX_VAL_LEN);
			}

			tmp_descr = g_strdup_printf("%s(%s)", ifnm, desc);
			g_strlcat(new_descr, tmp_descr, MAX_VAL_LEN);
			g_free(tmp_descr);

			/* set first-in-list flag to false */
			first_if = FALSE;
			more_items = gtk_tree_model_iter_next (model,&iter);
		}

		/* write new description string to preferences */
		if (strlen(new_descr) > 0) {
			g_free(prefs.capture_devices_descr);
			prefs.capture_devices_descr = new_descr;
		}
		/* no descriptions */
		else {
			g_free(prefs.capture_devices_descr);
			g_free(new_descr);
			prefs.capture_devices_descr = NULL;
		}
	}
}

/*
 * Create/write new "hidden" interfaces string based on current CList.
 * Put it into the preferences value.
 */
static void
ifopts_write_new_hide(void)
{
	GtkListStore 	*store;
	GtkTreeIter 	 iter;
	GtkTreeModel 	*model;
	gboolean	 more_items = TRUE;
	gint		 first_if = TRUE;	/* flag to check if first in list */
	gchar		*ifnm;
	gboolean	 hide;
	gchar		*new_hide;

	/* new preferences "hidden" interfaces string */
	new_hide = g_malloc0(MAX_VAL_LEN);

	/* get "hide" flag text for each row (interface) */
	model = gtk_tree_view_get_model(GTK_TREE_VIEW(cur_list));
	store = GTK_LIST_STORE(model);
	if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) ) {
		while (more_items) {
			gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
					   DEVICE_COLUMN, &ifnm,
					   HIDE_COLUMN,   &hide,
					   -1);

			/* if flag text is "No", skip this interface */
			if (!hide){
				more_items = gtk_tree_model_iter_next (model,&iter);
				continue;
			}

			/*
			 * create/cat interface to new string
			 */
			if (first_if != TRUE)
				g_strlcat (new_hide, ",", MAX_VAL_LEN);
			g_strlcat (new_hide, ifnm, MAX_VAL_LEN);

			/* set first-in-list flag to false */
			first_if = FALSE;
			more_items = gtk_tree_model_iter_next (model,&iter);
		}

		/* write new "hidden" string to preferences */
		if (strlen(new_hide) > 0) {
			g_free(prefs.capture_devices_hide);
			prefs.capture_devices_hide = new_hide;
		}
		/* no "hidden" interfaces */
		else {
			g_free(prefs.capture_devices_hide);
			g_free(new_hide);
			prefs.capture_devices_hide = NULL;
		}
		hide_interface(g_strdup(new_hide));
	}
}

#endif /* HAVE_LIBPCAP */
