Ethereal-dev: [Ethereal-dev] patches to add interface descriptions

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Nathan Jennings <njen@xxxxxxxxxxxxx>
Date: Mon, 08 Sep 2003 00:50:58 -0400
Hello,

Attached are diff files I've created against 0.9.14. The patches allow the edit/display of optional, user-defined interface descriptions via the capture preferences dialog. The descriptions are shown in the drop-down list of interfaces in the capture dialog.

I submitted this a couple of months ago and got some good suggestions from Guy and Olivier. I've implemented them both; GUI edit/display of descriptions (Guy) and the ability to "hide" an interface (Olivier). I think it's much better now. :o)

I have two thoughts/questions:

1) I'm not sure if Windows/Unicode requires special string handling in the code I've submitted. If so, my patches do not handle it.

2) In "capture_prefs.c", I use a CList widget that's never added to a window and displayed (I don't call "gtk_container_add()" for it). I use it as a table to store option values as they're edited by the user. Do I need to manually deallocate/free this widget somehow?

I've tested this on FreeBSD 4.7, GTK/GLIB 1.2.10 and FreeBSD 4.7, GTK/GLIB 2.0.6. Portions of it have been tested on Linux 2.4 with GTK/GLIB 1.2.10.

Please let me know if I left something out or should have done it differently. Feedback is welcome.

-Nathan
--- ../ethereal-0.9.14/gtk/capture_dlg.c	Sat May 17 12:33:02 2003
+++ gtk/capture_dlg.c	Sun Aug  3 00:10:35 2003
@@ -104,6 +104,15 @@
 static void
 capture_prep_destroy_cb(GtkWidget *win, gpointer user_data);
 
+static GList *
+capture_dev_descr_add(GList *if_list);
+
+char *
+capture_dev_descr_find(gchar *devs_descr, gchar *if_name);
+
+static GList *
+capture_dev_hide(GList *if_list);
+
 void
 capture_stop_cb(GtkWidget *w _U_, gpointer d _U_)
 {
@@ -221,8 +230,15 @@
   gtk_widget_show(if_lb);
 
   if_cb = gtk_combo_new();
-  if (if_list != NULL)
+  if (if_list != NULL) {
+    /* remove interface(s) from list if "hidden" */
+    if (prefs.capture_devices_hide != NULL)
+      if_list = capture_dev_hide(if_list);
+    /* prepend interface descriptions to device name */
+    if (prefs.capture_devices_descr != NULL)
+      if_list = capture_dev_descr_add(if_list);
     gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list);
+  }
   if (cfile.iface == NULL && prefs.capture_device != NULL) {
     /* No interface was specified on the command line or in a previous
        capture, but there is one specified in the preferences file;
@@ -789,7 +805,9 @@
 
   if_text =
     g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
-  /* Windows combo entries have a description followed by the interface name */
+  /* Remove interface description. Also, Windows combo entries have a 
+     description followed by the interface name. These two cases are
+     OK as long as they're in front (see capture_dev_descr_add()). */
   if_name = strrchr(if_text, ' ');
   if (if_name == NULL) {
     if_name = if_text;
@@ -1053,6 +1071,147 @@
   gtk_widget_set_sensitive(GTK_WIDGET(ring_duration_sb),
       gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ring_duration_cb)));
 
+}
+
+/*
+ * Prepend capture devices description to interface list. Remove OS (pcap)
+ * supplied description if present.
+ */
+static GList *
+capture_dev_descr_add(GList *if_list)
+{
+
+	GList	*if_new_list = NULL;
+	char	*osd;
+	char	*tmp_descr;
+	gchar	*tmp_devs_descr;
+	gchar	*tmp_dev_name;
+	guint	i;
+	guint	nitems;
+	
+	/* Seems we need to be at list head for g_list_length()? */
+	if_list = g_list_first(if_list);
+	nitems = g_list_length(if_list);
+	
+	/* Create new interface list with "(descr) if_name". */
+	for (i=0; i < nitems; i++) {
+		tmp_dev_name = g_list_nth_data(if_list, i);
+		/* should never happen, but just in case */
+		if (tmp_dev_name == NULL) {
+			if (if_new_list != NULL)
+				free_interface_list(if_new_list);
+			return if_list;
+		}
+		/* create copy since capture_dev_descr_find() inserts terminator */
+		tmp_devs_descr = g_strdup(prefs.capture_devices_descr);
+		/* find matching description */
+		tmp_descr = capture_dev_descr_find(tmp_devs_descr, tmp_dev_name);
+		/* prepend description */
+		if (tmp_descr != NULL) {
+			/* remove OS (pcap) description */
+			if ((osd = strrchr(tmp_dev_name, ' ')) != NULL) {
+				osd++;
+				if (osd != NULL)
+					tmp_dev_name = osd;
+			}
+			if_new_list = g_list_append(if_new_list, 
+				g_strdup_printf("%s %s", tmp_descr, tmp_dev_name));
+		}
+		/* no description for this interface, just copy name */
+		else {
+			if_new_list = g_list_append(if_new_list, g_strdup(tmp_dev_name));
+		}
+		g_free(tmp_devs_descr);
+	}
+	
+	free_interface_list(if_list);
+	/* return pointer to new interface list with descriptions */
+	return if_new_list;
+}
+
+/*
+ * Find capture device description that matches interface name.
+ */
+char *
+capture_dev_descr_find(gchar *devs_descr, gchar *if_name)
+{
+	char	*p;
+	char	*p2 = NULL;
+	char	*descr = NULL;
+	int		lp = 0;
+	int		ct = 0;
+	
+	if (if_name == NULL)
+		return NULL;
+	
+	if ((p = strstr(devs_descr, if_name)) == NULL)
+		return NULL;
+	
+	while (p != NULL) {
+		/* error: ran into next interface description */
+		if (*p == ',')
+			return NULL;
+		/* found left parenthesis, start of description */
+		else if (*p == '(') {
+			lp++;
+			/* save pointer to beginning of description */
+			p2 = p;
+			p++;
+			continue;
+		}
+		else if (*p == ')') {
+			/* end of description */
+			break;
+		}
+		else {
+			p++;
+			ct++;
+		}
+	}
+	
+	if ((lp == 1) && (ct > 0) && (p2 != NULL)) {
+		/* set returned pointer to beginning of description */
+		descr = p2;
+		/* insert terminator */
+		*(p+1) = '\0';
+		return descr;
+	}
+	else
+		return NULL;
+}
+
+/*
+ * Remove "hidden" interface(s) from list.
+ */
+static GList *
+capture_dev_hide(GList *if_list)
+{
+	GList	*if_new_list = NULL;
+	gchar	*tmp_dev_name;
+	guint	i;
+	guint	nitems;
+	
+	/* Seems we need to be at list head for g_list_length()? */
+	if_list = g_list_first(if_list);
+	nitems = g_list_length(if_list);
+	
+	/* Create new list without "hidden" interfaces. */
+	for (i=0; i < nitems; i++) {
+		tmp_dev_name = g_list_nth_data(if_list, i);
+		/* should never happen, but just in case */
+		if (tmp_dev_name == NULL) {
+			if (if_new_list != NULL)
+				free_interface_list(if_new_list);
+			return if_list;
+		}
+		/* check if interface name is in "hidden" preferences string */
+		if (strstr(prefs.capture_devices_hide, tmp_dev_name) == NULL)
+			if_new_list = g_list_append(if_new_list, g_strdup(tmp_dev_name));
+	}
+	
+	free_interface_list(if_list);
+	/* return pointer to new interface list */
+	return if_new_list;
 }
 
 #endif /* HAVE_LIBPCAP */
--- ../ethereal-0.9.14/gtk/capture_prefs.c	Tue Nov 12 20:57:44 2002
+++ gtk/capture_prefs.c	Sun Sep  7 21:53:40 2003
@@ -28,6 +28,7 @@
 
 #ifdef HAVE_LIBPCAP
 
+#include <string.h>
 #include <gtk/gtk.h>
 
 #include <pcap.h>
@@ -38,21 +39,34 @@
 #include "prefs.h"
 #include "prefs_dlg.h"
 #include "ui_util.h"
+#include "simple_dialog.h"
 #include "pcap-util.h"
 #include "main.h"
 #include "compat_macros.h"
 
-#define DEVICE_KEY		"device"
-#define PROM_MODE_KEY		"prom_mode"
+#define DEVICE_KEY				"device"
+#define PROM_MODE_KEY			"prom_mode"
 #define CAPTURE_REAL_TIME_KEY	"capture_real_time"
-#define AUTO_SCROLL_KEY		"auto_scroll"
+#define AUTO_SCROLL_KEY			"auto_scroll"
+
+#define DEVOPTS_CALLER_PTR_KEY	"devopts_caller_ptr"
+#define DEVOPTS_DIALOG_PTR_KEY	"devopts_dialog_ptr"
+
+#define CAPTURE_TABLE_ROWS 5
+#define DEVICES_OPTS_ROWS 2
+#define IF_OPTS_CLIST_COLS 3
+#define IF_OPTS_MAX_DESCR_LEN 128
+
+/* interface options dialog */
+static GtkWidget *new_clist, *if_descr_te, *if_hide_cb;
+static gint ifrow;						/* last interface row selected */
 
-#define CAPTURE_TABLE_ROWS 4
 GtkWidget*
 capture_prefs_show(void)
 {
 	GtkWidget	*main_tb, *main_vb;
 	GtkWidget	*if_cb, *if_lb, *promisc_cb, *sync_cb, *auto_scroll_cb;
+	GtkWidget	*ifopts_lb, *ifopts_bt;
 	GList		*if_list;
 	int		err;
 	char		err_str[PCAP_ERRBUF_SIZE];
@@ -69,7 +83,7 @@
 	gtk_widget_show(main_tb);
 
 	/* Default device */
-	if_lb = gtk_label_new("Interface:");
+	if_lb = gtk_label_new("Default interface:");
 	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_lb, 0, 1, 0, 1);
 	gtk_misc_set_alignment(GTK_MISC(if_lb), 1.0, 0.5);
 	gtk_widget_show(if_lb);
@@ -90,20 +104,30 @@
 
 	free_interface_list(if_list);
 
+	/* Interface options */
+	ifopts_lb = gtk_label_new("Interface options:");
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_lb, 0, 1, 1, 2);
+	gtk_misc_set_alignment(GTK_MISC(ifopts_lb), 1.0, 0.5);
+	gtk_widget_show(ifopts_lb);
+
+	ifopts_bt = gtk_button_new_with_label("Edit...");
+	SIGNAL_CONNECT(ifopts_bt, "clicked", ifopts_edit_cb, NULL);
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_bt, 1, 2, 1, 2 );
+
 	/* Promiscuous mode */
-	promisc_cb = create_preference_check_button(main_tb, 1,
+	promisc_cb = create_preference_check_button(main_tb, 2,
 	    "Capture packets in promiscuous mode:", NULL,
 	    prefs.capture_prom_mode);
 	OBJECT_SET_DATA(main_vb, PROM_MODE_KEY, promisc_cb);
 
 	/* Real-time capture */
-	sync_cb = create_preference_check_button(main_tb, 2,
+	sync_cb = create_preference_check_button(main_tb, 3,
 	    "Update list of packets in real time:", NULL,
 	    prefs.capture_real_time);
 	OBJECT_SET_DATA(main_vb, CAPTURE_REAL_TIME_KEY, sync_cb);
 
 	/* Auto-scroll real-time capture */
-	auto_scroll_cb = create_preference_check_button(main_tb, 3,
+	auto_scroll_cb = create_preference_check_button(main_tb, 4,
 	    "Automatic scrolling in live capture:", NULL,
 	    prefs.capture_auto_scroll);
 	OBJECT_SET_DATA(main_vb, AUTO_SCROLL_KEY, auto_scroll_cb);
@@ -154,8 +178,827 @@
 }
 
 void
-capture_prefs_destroy(GtkWidget *w _U_)
+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 = OBJECT_GET_DATA(caller, DEVOPTS_DIALOG_PTR_KEY);
+
+	if (dlg != NULL) {
+		/* Yes.  Destroy it. */
+		gtk_widget_destroy(dlg);
+	}
+}
+
+/* Create an edit interface options dialog. */
+void
+ifopts_edit_cb(GtkWidget *w, gpointer data _U_)
+{
+	GtkWidget	*ifopts_edit_dlg, *old_scr_win, *if_scr_win, *main_hb, *main_tb,
+				*old_opts_fr, *opts_fr,
+				*old_clist, *if_clist, *if_descr_lb, *if_hide_lb,
+				*bbox, *ok_bt, *cancel_bt;
+	gchar *old_titles[3] = { "Interface", "Description", "Hide?" };
+	gchar *if_title[1] = { "Interface" };
+
+	GtkWidget *caller = gtk_widget_get_toplevel(w);
+	
+	/* Has an edit dialog box already been opened for that top-level
+	   widget? */
+	ifopts_edit_dlg = OBJECT_GET_DATA(caller, DEVOPTS_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 = gtk_dialog_new();
+	gtk_window_set_title(GTK_WINDOW(ifopts_edit_dlg), 
+			"Ethereal: Preferences: Interface Options");
+	SIGNAL_CONNECT(ifopts_edit_dlg, "destroy", ifopts_edit_destroy_cb, NULL);
+	gtk_container_border_width(GTK_CONTAINER(GTK_DIALOG(ifopts_edit_dlg)->vbox),
+			5);
+	
+	/*
+	 * XXX - What code can be put here, or somewhere else, to get the Ethereal 
+	 *		 icon loaded for this window?
+	 */
+	
+	/* create old options frame */
+	old_opts_fr = gtk_frame_new("Previously saved options");
+	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(ifopts_edit_dlg)->vbox), 
+			old_opts_fr);
+	gtk_widget_show(old_opts_fr);
+	
+	/* create a scrolled window to pack the old options CList widget into */
+	old_scr_win = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(old_scr_win),
+			GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+	gtk_container_border_width(GTK_CONTAINER(old_scr_win), 3);
+	gtk_container_add(GTK_CONTAINER(old_opts_fr), old_scr_win);
+	gtk_widget_show(old_scr_win);
+	
+	/* create old options CList (previously saved options) */
+	old_clist = gtk_clist_new_with_titles(3, old_titles);
+	gtk_clist_set_column_width(GTK_CLIST(old_clist), 0, 200);
+	gtk_clist_set_column_width(GTK_CLIST(old_clist), 1, 200);
+	gtk_clist_set_column_width(GTK_CLIST(old_clist), 2, 40);
+	gtk_clist_column_titles_passive(GTK_CLIST(old_clist));
+	gtk_container_add(GTK_CONTAINER(old_scr_win), old_clist);
+	
+	/* add text to old options cells */
+	ifopts_old_options_add(GTK_CLIST(old_clist));
+	gtk_widget_show(old_clist);
+	
+	/* create new options CList to hold currently edited values */
+	/* XXX - Since this is an "invisible" widget used only as a table
+	 * for storing newly edited interface options, do we need to manually
+	 * deallocate/free it? (It's never added to a window with 
+	 * gtk_container_add().) */
+	new_clist = gtk_clist_new(3);
+	
+	/* create edit options frame */
+	opts_fr = gtk_frame_new("Edit interface options");
+	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(ifopts_edit_dlg)->vbox), 
+			opts_fr);
+	gtk_widget_show(opts_fr);
+	
+	main_hb = gtk_hbox_new(TRUE, 5);
+	gtk_container_border_width(GTK_CONTAINER(main_hb), 3);
+	gtk_container_add(GTK_CONTAINER(opts_fr), main_hb);
+	gtk_widget_show(main_hb);
+	
+	/* create a scrolled window to pack the interface CList widget into */
+	if_scr_win = gtk_scrolled_window_new(NULL, NULL);
+	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(if_scr_win),
+			GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+	gtk_box_pack_start(GTK_BOX(main_hb), if_scr_win, TRUE, TRUE, 0);
+	gtk_widget_show(if_scr_win);
+	
+	/* create interface CList */
+	if_clist = gtk_clist_new_with_titles(1, if_title);
+	SIGNAL_CONNECT(if_clist, "select_row", ifopts_edit_ifsel_cb, if_clist);
+	SIGNAL_CONNECT(if_clist, "unselect_row", ifopts_edit_ifunsel_cb, if_clist);
+	gtk_clist_set_column_width(GTK_CLIST(if_clist), 0, 75);
+	gtk_clist_column_titles_passive(GTK_CLIST(if_clist));
+	gtk_clist_set_selection_mode(GTK_CLIST(if_clist), GTK_SELECTION_SINGLE);
+	gtk_container_add(GTK_CONTAINER(if_scr_win), if_clist);
+	
+	/* initialize variable that saves the last selected row in "if_clist" */
+	ifrow = -1;
+	
+	/* add text to interface cell */
+	ifopts_if_clist_add(GTK_CLIST(if_clist));
+	gtk_widget_show(if_clist);
+	
+	/* table to hold description text entry and hide button */
+	main_tb = gtk_table_new(DEVICES_OPTS_ROWS, 2, 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);
+	
+	/* create interface description label and text entry */
+	if_descr_lb = gtk_label_new("Description:");
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_lb, 0, 1, 0, 1);
+	gtk_misc_set_alignment(GTK_MISC(if_descr_lb), 1.0, 0.5);
+	gtk_widget_show(if_descr_lb);
+	
+	if_descr_te = gtk_entry_new();
+	gtk_entry_set_max_length(GTK_ENTRY(if_descr_te), IF_OPTS_MAX_DESCR_LEN);
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_te, 1, 2, 0, 1);
+	gtk_widget_show(if_descr_te);
+	
+	/* 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, 1, 2);
+	gtk_misc_set_alignment(GTK_MISC(if_hide_lb), 1.0, 0.5);
+	gtk_widget_show(if_hide_lb);
+	
+	if_hide_cb = gtk_check_button_new();
+	gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_cb, 1, 2, 1, 2);
+	gtk_widget_show(if_hide_cb);
+	
+	/* button row: OK and Cancel buttons */
+	bbox = gtk_hbutton_box_new();
+	gtk_button_box_set_layout(GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+	gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 10);
+	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ifopts_edit_dlg)->action_area), bbox,
+			TRUE, FALSE, 0);
+	gtk_widget_show(bbox);
+
+#if GTK_MAJOR_VERSION < 2
+	ok_bt = gtk_button_new_with_label ("OK");
+#else
+	ok_bt = gtk_button_new_from_stock(GTK_STOCK_OK);
+#endif
+
+	/* Connect the OK button to ifdescr_edit_ok_cb function */
+	SIGNAL_CONNECT(ok_bt, "clicked", ifopts_edit_ok_cb, ifopts_edit_dlg);
+	GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT);
+	gtk_container_add(GTK_CONTAINER(bbox), ok_bt);
+	gtk_widget_grab_default(ok_bt);
+	gtk_widget_show(ok_bt);
+
+#if GTK_MAJOR_VERSION < 2
+  cancel_bt = gtk_button_new_with_label ("Cancel");
+#else
+  cancel_bt = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
+#endif
+
+	/* Connect the Cancel button to destroy the widget */
+	SIGNAL_CONNECT(cancel_bt, "clicked", ifopts_edit_close_cb, ifopts_edit_dlg);
+	GTK_WIDGET_SET_FLAGS(cancel_bt, GTK_CAN_DEFAULT);
+	gtk_container_add(GTK_CONTAINER(bbox), cancel_bt);
+	gtk_widget_show(cancel_bt);
+
+	/* Call a handler when we're destroyed, so we can inform
+	   our caller, if any, that we've been destroyed. */
+	SIGNAL_CONNECT(ifopts_edit_dlg, "destroy", ifopts_edit_destroy_cb, NULL);
+
+	/* Set the DEVOPTS_CALLER_PTR_KEY for the new dialog to point to
+	   our caller. */
+	OBJECT_SET_DATA(ifopts_edit_dlg, DEVOPTS_CALLER_PTR_KEY, caller);
+
+	/* Set the DEVOPTS_DIALOG_PTR_KEY for the caller to point to us */
+	OBJECT_SET_DATA(caller, DEVOPTS_DIALOG_PTR_KEY, ifopts_edit_dlg);
+	
+	/* Catch the "key_press_event" signal in the window, so that we can
+	   catch the ESC key being pressed and act as if the "Cancel" button
+	   had been selected. */
+	/*dlg_set_cancel(ifopts_edit_dlg, cancel_bt);*/
+	
+	gtk_widget_show(ifopts_edit_dlg);
+}
+
+/*
+ * User selected "OK". Create/write preferences strings.
+ */
+void
+ifopts_edit_ok_cb(GtkWidget *w _U_, gpointer parent_w)
+{
+	
+	/*
+	 * Update option values in "new" CList for the last selected interface.
+	 * (Is there a function that returns the currently selected row?)
+	 */
+	if (ifrow != -1)
+		ifopts_edit_ifunsel_cb(NULL, ifrow, 0, NULL, NULL);
+	
+	/* create/write new interfaces description string */
+	ifopts_write_new_descr();
+	
+	/* create/write new "hidden" interfaces string */
+	ifopts_write_new_hide();
+	
+	/* Now nuke this window. */
+	gtk_grab_remove(GTK_WIDGET(parent_w));
+	gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+void
+ifopts_edit_close_cb(GtkWidget *close_bt _U_, gpointer parent_w)
+{
+  gtk_grab_remove(GTK_WIDGET(parent_w));
+  gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+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 = OBJECT_GET_DATA(win, DEVOPTS_CALLER_PTR_KEY);
+
+	if (caller != NULL) {
+		/* Tell it we no longer exist. */
+		OBJECT_SET_DATA(caller, DEVOPTS_DIALOG_PTR_KEY, NULL);
+	}
+
+	/* Now nuke this window. */
+	gtk_grab_remove(GTK_WIDGET(win));
+	gtk_widget_destroy(GTK_WIDGET(win));
+}
+
+/*
+ * Interface selected callback; update displayed widgets.
+ */
+void
+ifopts_edit_ifsel_cb(GtkWidget		*clist _U_,
+					 gint			row,
+					 gint			column _U_,
+					 GdkEventButton	*event _U_,
+					 gpointer		data _U_)
+{
+	gchar *text;
+	
+	/* get/display the interface description from "new" CList */
+	gtk_clist_get_text(GTK_CLIST(new_clist), row, 1, &text);
+	gtk_entry_set_text(GTK_ENTRY(if_descr_te), text);
+	
+	/* get/display the "hidden" button state from "new" CList */
+	gtk_clist_get_text(GTK_CLIST(new_clist), row, 2, &text);
+	if (*text == '1')
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), TRUE);
+	else
+		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), FALSE);
+	
+	/* save currently selected row so we can update its values on "OK". */
+	ifrow = row;
+}
+
+/*
+ * Interface unselected callback; update "new" CList values.
+ *
+ * NOTE:
+ *		This is also called from "ifopts_edit_ok_cb" to update values in 
+ *		the "new" CList for the last selected interface; only "row" is passed
+ *		as a valid value. Others are "NULL" or "0".
+ */
+void
+ifopts_edit_ifunsel_cb(GtkWidget		*clist _U_,
+						gint			row,
+						gint			column _U_,
+						GdkEventButton	*event _U_,
+						gpointer		data _U_)
+{
+	gchar *text;
+	gchar state[2] = { '\0' };
+	
+	/* get interface description and set value in "new" CList */
+	text = gtk_editable_get_chars(GTK_EDITABLE(if_descr_te), 0, -1);
+	/* replace any reserved formatting characters "()," with spaces */
+	g_strdelimit(text, "(),", ' ');
+	gtk_clist_set_text(GTK_CLIST(new_clist), row, 1, text);
+	g_free(text);
+	
+	/* get "hidden" button state and set value in "new" CList */
+	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(if_hide_cb)) == TRUE)
+		state[0] = '1';
+	else
+		state[0] = '0';
+	gtk_clist_set_text(GTK_CLIST(new_clist), row, 2, state);
+}
+
+/*
+ * Add previously saved options to cells in "old" CList.
+ */
+void
+ifopts_old_options_add(GtkCList *clist)
+{
+	gchar	*p;
+	gchar	*ifnm;
+	gchar	*desc;
+	gchar	*pr_descr;
+	gchar	*pr_hide;
+	gchar	*text[3] = { '\0' };
+	gint	row;
+	gint	ct;
+	
+	/* add interface descriptions and "hidden" yes/no text */
+	if (prefs.capture_devices_descr != NULL) {
+		/* create working copy of device descriptions */
+		pr_descr = g_strdup(prefs.capture_devices_descr);
+		p = pr_descr;
+		ifnm = p;
+		
+		while (*p != '\0') {
+			/* found comma, start of next interface(description) */
+			if (*p == ',') {
+				/* add existing text */
+				if (text[0] != NULL) {
+					row = gtk_clist_append(GTK_CLIST(clist), text);
+					gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
+					ifopts_options_free(text);
+				}
+				p++;
+				/* reset interface name pointer to start of new name */
+				ifnm = p;
+			}
+			/* found left parenthesis, start of description */
+			else if (*p == '(') {
+				/* terminate and set interface name text */
+				*p = '\0';
+				text[0] = g_strdup(ifnm);
+				/* check if interface is "hidden" */
+				if (prefs.capture_devices_hide != NULL) {
+					if (strstr(prefs.capture_devices_hide, ifnm) != NULL)
+						text[2] = g_strdup("Yes");
+					else
+						text[2] = g_strdup("No");
+				}
+				else
+					text[2] = g_strdup("No");
+				*p = '(';
+				p++;
+				/* if syntax error */
+				if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
+					ifopts_options_free(text);
+					break;
+				}
+				/* save pointer to beginning of description */
+				desc = p;
+				p++;
+				/* if syntax error */
+				if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
+					ifopts_options_free(text);
+					break;
+				}
+				/* skip to end of description */
+				while (*p != '\0') {
+					/* end of description */
+					if (*p == ')') {
+						/* terminate and set description text */
+						*p = '\0';
+						text[1] = g_strdup(desc);
+						*p = ')';
+						p++;
+						break;
+					}
+					p++;
+				}
+				/* if we reached last interface description, add text */
+				if (*p == '\0') {
+					if (text[0] != NULL) {
+						row = gtk_clist_append(GTK_CLIST(clist), text);
+						gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
+						ifopts_options_free(text);
+					}
+				}
+			}
+			else
+				p++;
+		}
+		
+		g_free(pr_descr);
+	}
+	
+	/*
+	 * Only add "hidden" interface yes/no text here; since we may not have
+	 * any descriptions, but have "hidden" interfaces.
+	 */
+	if (prefs.capture_devices_hide != NULL) {
+		/* create working copy of hidden interfaces */
+		pr_hide = g_strdup(prefs.capture_devices_hide);
+		p = pr_hide;
+		ifnm = p;
+		ct = 0;
+		
+		while (*p != '\0') {
+			/* found comma, start of next interface */
+			if ((*p == ',') && (ct > 0)) {
+				/* terminate and set text */
+				*p = '\0';
+				text[0] = g_strdup(ifnm);
+				/* set empty description */
+				text[1] = NULL;
+				/* set "hidden" text */
+				text[2] = g_strdup("Yes");
+				/* add text if not previously added */
+				if (ifopts_old_options_chk(GTK_CLIST(clist), text[0]) == 0) {
+					row = gtk_clist_append(GTK_CLIST(clist), text);
+					gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
+				}
+				ifopts_options_free(text);
+				*p = ',';
+				p++;
+				ifnm = p;
+				ct = 0;
+			}
+			p++;
+			ct++;
+		}
+		
+		/* if we reached last "hidden" interface in list */
+		if (ct > 0) {
+			/* set text */
+			text[0] = g_strdup(ifnm);
+			/* set empty description */
+			text[1] = NULL;
+			/* set "hidden" text */
+			text[2] = g_strdup("Yes");
+			/* add text if not previously added */
+			if (ifopts_old_options_chk(GTK_CLIST(clist), text[0]) == 0) {
+				row = gtk_clist_append(GTK_CLIST(clist), text);
+				gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
+			}
+			ifopts_options_free(text);
+		}
+		
+		g_free(pr_hide);
+	}
+}
+
+/*
+ * Check to see if interface has already been added to "old" options CList.
+ * Returns "1" if it has.
+ */
+gint ifopts_old_options_chk(GtkCList *clist, gchar *ifname)
+{
+	gint	i;
+	gchar	*ifnm;
+	
+	/* get interface name for each row */
+	for (i = 0; ;i++) {
+		if (gtk_clist_get_text(GTK_CLIST(clist), i, 0, &ifnm) != 1)
+			break;
+		if (strcmp(ifnm, ifname) == 0)
+			return 1;
+	}
+	
+return 0;
+}
+
+/*
+ * Add any old options that apply to cells in "new" CList. The "new" CList
+ * is never displayed. It's used only as a table to store values as they're
+ * edited by the user.
+ *
+ * NOTE: Be careful here since interfaces may have been removed from the 
+ * machine or disabled and no longer apply.
+ */
+void ifopts_new_options_add(GtkCList *clist, gchar *ifname)
+{
+	gchar	*p;
+	gchar	*ifnm;
+	gchar	*desc;
+	gchar	*pr_descr;
+	gchar	*text[3] = { '\0' };
+	
+	/* add interface descriptions and "hidden" flag */
+	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, ifname)) != NULL) {
+			p = ifnm;
+			while (*p != '\0') {
+				/* found left parenthesis, start of description */
+				if (*p == '(') {
+					/* set interface name text */
+					text[0] = g_strdup(ifname);
+					/* check if interface is "hidden" */
+					if (prefs.capture_devices_hide != NULL) {
+						if (strstr(prefs.capture_devices_hide, ifname) != NULL)
+							text[2] = g_strdup("1");
+						else
+							text[2] = g_strdup("0");
+					}
+					else
+						text[2] = g_strdup("0");
+					p++;
+					/* if syntax error */
+					if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
+						ifopts_options_free(text);
+						break;
+					}
+					/* save pointer to beginning of description */
+					desc = p;
+					p++;
+					/* if syntax error */
+					if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
+						ifopts_options_free(text);
+						break;
+					}
+					/* skip to end of description */
+					while (*p != '\0') {
+						/* end of description */
+						if (*p == ')') {
+							/* terminate and set description text */
+							*p = '\0';
+							text[1] = g_strdup(desc);
+							/* add row to CList */
+							gtk_clist_append(GTK_CLIST(clist), text);
+							ifopts_options_free(text);
+							break;
+						}
+						p++;
+					}
+					/* get out */
+					break;
+				}
+				else
+					p++;
+			}
+		}
+		/* if there's no description for this interface */
+		else {
+			/* set interface name */
+			text[0] = g_strdup(ifname);
+			/* set empty description */
+			text[1] = NULL;
+			/* check if interface is "hidden" */
+			if (prefs.capture_devices_hide != NULL) {
+				if (strstr(prefs.capture_devices_hide, ifname) != NULL)
+					text[2] = g_strdup("1");
+				else
+					text[2] = g_strdup("0");
+			}
+			else
+				text[2] = g_strdup("0");
+			
+			/* add row to CList */
+			gtk_clist_append(GTK_CLIST(clist), text);
+			ifopts_options_free(text);
+		}
+		
+		g_free(pr_descr);
+	}
+	/*
+	 * If we do not have any descriptions, but have "hidden" interfaces.
+	 */
+	else if (prefs.capture_devices_hide != NULL) {
+		/* set interface name */
+		text[0] = g_strdup(ifname);
+		/* set empty description */
+		text[1] = NULL;
+		/* check if interface is "hidden" */
+		if (strstr(prefs.capture_devices_hide, ifname) != NULL)
+			text[2] = g_strdup("1");
+		else
+			text[2] = g_strdup("0");
+		
+		/* add row to CList */
+		gtk_clist_append(GTK_CLIST(clist), text);
+		ifopts_options_free(text);
+	}
+	/*
+	 * If we have no descriptions and no "hidden" interfaces.
+	 */
+	else {
+		/* set interface name */
+		text[0] = g_strdup(ifname);
+		/* set empty description */
+		text[1] = NULL;
+		/* interface is not "hidden" */
+		text[2] = g_strdup("0");
+		
+		/* add row to CList */
+		gtk_clist_append(GTK_CLIST(clist), text);
+		ifopts_options_free(text);
+	}
+}
+
+void ifopts_options_free(gchar *text[])
+{
+	gint i;
+	
+	for (i=0; i < IF_OPTS_CLIST_COLS; i++) {
+		if (text[i] != NULL) {
+			g_free(text[i]);
+			text[i] = NULL;
+		}
+	}
+}
+
+/*
+ * Add interfaces to displayed interfaces CList. Also, fill "new" options CList.
+ */
+void ifopts_if_clist_add(GtkCList *clist)
+{
+	GList	*if_list;
+	int		err;
+	char	err_str[PCAP_ERRBUF_SIZE];
+	gchar	*text[1];
+	guint	i;
+	guint	nitems;
+	
+	if_list = get_interface_list(&err, err_str);
+	if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
+		simple_dialog(ESD_TYPE_WARN, NULL, "Can't get list of interfaces: %s",
+				err_str);
+		return;
+	}
+	
+	/* Seems we need to be at list head for g_list_length()? */
+	if_list = g_list_first(if_list);
+	nitems = g_list_length(if_list);
+	
+	/* add interface name text to CList */
+	for (i=0; i < nitems; i++) {
+		text[0] = g_list_nth_data(if_list, i);
+		/* should never happen, but just in case */
+		if (text[0] == NULL)
+			continue;
+		gtk_clist_append(GTK_CLIST(clist), text);
+		/* fill "new" options CList with previously saved values */
+		ifopts_new_options_add(GTK_CLIST(new_clist), text[0]);
+	}
+	
+	free_interface_list(if_list);
+}
+
+/*
+ * Create/write new interfaces description string based on "new" CList.
+ */
+void ifopts_write_new_descr(void)
+{
+	gint	i;
+	gint	first_if = 1;				/* flag to check if 1st in list */
+	gchar	*ifnm;
+	gchar	*desc;
+	gchar	*tmp_descr;
+	gchar	*new_descr;
+	
+	/* new preferences interfaces description string */
+	new_descr = g_malloc0(MAX_VAL_LEN);
+	if (new_descr == NULL) {
+		simple_dialog(ESD_TYPE_WARN, NULL, "Error (1) saving interface "
+				"descriptions: malloc failure");
+		return;
+	}
+	
+	/*
+	 * current row's interface description string
+	 * (leave space for parens, comma and terminator)
+	 */
+	/*
+	 * XXX - Currently, MAX_WIN_IF_NAME_LEN is 511. This should be large 
+	 * enough for *nix. ;o)
+	 */
+	tmp_descr = g_malloc0(IF_OPTS_MAX_DESCR_LEN + MAX_WIN_IF_NAME_LEN + 4);
+	if (tmp_descr == NULL) {
+		simple_dialog(ESD_TYPE_WARN, NULL, "Error (2) saving interface "
+				"descriptions: malloc failure");
+		g_free(new_descr);
+		return;
+	}
+	
+	/* get description for each row (interface) */
+	for (i = 0; ;i++) {
+		/* get description */
+		if (gtk_clist_get_text(GTK_CLIST(new_clist), i, 1, &desc) != 1)
+			break;
+		/* if no description, skip this interface */
+		if (strlen(desc) == 0)
+			continue;
+		/* get interface name */
+		gtk_clist_get_text(GTK_CLIST(new_clist), i, 0, &ifnm);
+		
+		/*
+		 * create/cat interface description to new string
+		 * (leave space for parens, comma and terminator)
+		 */
+		if ((strlen(ifnm) + strlen(desc) + 4 + 
+				strlen(new_descr)) <  MAX_VAL_LEN) {
+			if (first_if == 1)
+				snprintf(tmp_descr, IF_OPTS_MAX_DESCR_LEN+MAX_WIN_IF_NAME_LEN+4,
+						"%s(%s)", ifnm, desc);
+			else
+				snprintf(tmp_descr, IF_OPTS_MAX_DESCR_LEN+MAX_WIN_IF_NAME_LEN+4,
+						",%s(%s)", ifnm, desc);
+			strcat(new_descr, tmp_descr);
+			/* set first-in-list flag to false */
+			first_if = 0;
+		}
+		/* interface name + description is too large */
+		else {
+			simple_dialog(ESD_TYPE_WARN, NULL, "Error saving interface "
+					"description for:\n%s\n(too long)", ifnm);
+			continue;
+		}
+	}
+	
+	/* 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 "new" CList.
+ */
+void ifopts_write_new_hide(void)
+{
+	gint	i;
+	gint	first_if = 1;				/* flag to check if 1st in list */
+	gchar	*ifnm;
+	gchar	*hide;
+	gchar	*tmp_hide;
+	gchar	*new_hide;
+	
+	/* new preferences "hidden" interfaces string */
+	new_hide = g_malloc0(MAX_VAL_LEN);
+	if (new_hide == NULL) {
+		simple_dialog(ESD_TYPE_WARN, NULL, "Error (1) saving \"hidden\" "
+				"interfaces: malloc failure");
+		return;
+	}
+	
+	/*
+	 * current row's interface name if "hidden"
+	 * (leave space for comma and terminator)
+	 */
+	/*
+	 * XXX - Currently, MAX_WIN_IF_NAME_LEN is 511. This should be large 
+	 * enough for *nix. ;o)
+	 */
+	tmp_hide = g_malloc0(MAX_WIN_IF_NAME_LEN + 2);
+	if (tmp_hide == NULL) {
+		simple_dialog(ESD_TYPE_WARN, NULL, "Error (2) saving \"hidden\" "
+				"interfaces: malloc failure");
+		g_free(new_hide);
+		return;
+	}
+	
+	/* get "hidden" flag for each row (interface) */
+	for (i = 0; ;i++) {
+		/* get flag */
+		if (gtk_clist_get_text(GTK_CLIST(new_clist), i, 2, &hide) != 1)
+			break;
+		/* if flag is not "1", skip this interface */
+		if (*hide == '0')
+			continue;
+		/* get interface name */
+		gtk_clist_get_text(GTK_CLIST(new_clist), i, 0, &ifnm);
+		
+		/*
+		 * create/cat interface to new string
+		 * (leave space for comma and terminator)
+		 */
+		if ((strlen(ifnm) + 2 + strlen(new_hide)) <  MAX_VAL_LEN) {
+			if (first_if == 1)
+				snprintf(tmp_hide, MAX_WIN_IF_NAME_LEN+2, "%s", ifnm);
+			else
+				snprintf(tmp_hide, MAX_WIN_IF_NAME_LEN+2, ",%s", ifnm);
+			strcat(new_hide, tmp_hide);
+			/* set first-in-list flag to false */
+			first_if = 0;
+		}
+		/* interface name is too large */
+		else {
+			simple_dialog(ESD_TYPE_WARN, NULL, "Error saving \"hidden\" "
+					"interface for:\n%s\n(too long)", ifnm);
+			continue;
+		}
+	}
+	
+	/* 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;
+	}
 }
 
 #endif /* HAVE_LIBPCAP */
--- ../ethereal-0.9.14/gtk/capture_prefs.h	Wed Aug 28 20:40:08 2002
+++ gtk/capture_prefs.h	Sun Sep  7 01:13:48 2003
@@ -29,5 +29,18 @@
 void capture_prefs_fetch(GtkWidget *w);
 void capture_prefs_apply(GtkWidget *w);
 void capture_prefs_destroy(GtkWidget *w);
+void ifopts_edit_cb(GtkWidget *w, gpointer data);
+void ifopts_edit_ok_cb(GtkWidget *w, gpointer parent_w);
+void ifopts_edit_close_cb(GtkWidget *close_bt, gpointer parent_w);
+void ifopts_edit_destroy_cb(GtkWidget *win, gpointer data);
+void ifopts_edit_ifsel_cb(GtkWidget	*clist, gint row, gint column, GdkEventButton *event, gpointer data);
+void ifopts_edit_ifunsel_cb(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data);
+void ifopts_old_options_add(GtkCList *clist);
+gint ifopts_old_options_chk(GtkCList *clist, gchar *ifname);
+void ifopts_new_options_add(GtkCList *clist, gchar *ifname);
+void ifopts_options_free(gchar *text[]);
+void ifopts_if_clist_add(GtkCList *clist);
+void ifopts_write_new_descr(void);
+void ifopts_write_new_hide(void);
 
 #endif
--- ../ethereal-0.9.14/pcap-util.c	Wed Jul  9 21:20:13 2003
+++ pcap-util.c	Sat Sep  6 01:21:18 2003
@@ -398,7 +398,6 @@
 		search_user_data->found = TRUE;
 }
 #else /* Windows */
-#define MAX_WIN_IF_NAME_LEN 511
 GList *
 get_interface_list(int *err, char *err_str) {
   GList  *il = NULL;
--- ../ethereal-0.9.14/pcap-util.h	Wed Aug 28 20:40:05 2002
+++ pcap-util.h	Sat Sep  6 01:21:47 2003
@@ -33,6 +33,7 @@
 
 int get_pcap_linktype(pcap_t *pch, char *devname);
 
+#define MAX_WIN_IF_NAME_LEN 511
 GList *get_interface_list(int *err, char *err_str);
 
 /* Error values from "get_interface_list()". */
--- ../ethereal-0.9.14/prefs.c	Mon Jul 21 23:14:28 2003
+++ prefs.c	Sat Sep  6 01:23:27 2003
@@ -842,8 +842,6 @@
  *
  */
 
-#define MAX_VAR_LEN    48
-#define MAX_VAL_LEN  1024
 
 #define DEF_NUM_COLS    6
 
@@ -979,6 +977,8 @@
 
 /* set the default values for the capture dialog box */
     prefs.capture_device           = NULL;
+    prefs.capture_devices_descr    = NULL;
+    prefs.capture_devices_hide     = NULL;
     prefs.capture_prom_mode        = TRUE;
     prefs.capture_real_time        = FALSE;
     prefs.capture_auto_scroll      = FALSE;
@@ -1252,10 +1252,12 @@
 #define PRS_CAP_NAME_RESOLVE "capture.name_resolve"
 
 /*  values for the capture dialog box */
-#define PRS_CAP_DEVICE      "capture.device"
-#define PRS_CAP_PROM_MODE   "capture.prom_mode"
-#define PRS_CAP_REAL_TIME   "capture.real_time_update"
-#define PRS_CAP_AUTO_SCROLL "capture.auto_scroll"
+#define PRS_CAP_DEVICE        "capture.device"
+#define PRS_CAP_DEVICES_DESCR "capture.devices_descr"
+#define PRS_CAP_DEVICES_HIDE  "capture.devices_hide"
+#define PRS_CAP_PROM_MODE     "capture.prom_mode"
+#define PRS_CAP_REAL_TIME     "capture.real_time_update"
+#define PRS_CAP_AUTO_SCROLL   "capture.auto_scroll"
 
 #define RED_COMPONENT(x)   ((((x) >> 16) & 0xff) * 65535 / 255)
 #define GREEN_COMPONENT(x) ((((x) >>  8) & 0xff) * 65535 / 255)
@@ -1514,6 +1516,14 @@
     if (prefs.capture_device != NULL)
       g_free(prefs.capture_device);
     prefs.capture_device = g_strdup(value);
+  } else if (strcmp(pref_name, PRS_CAP_DEVICES_DESCR) == 0) {
+    if (prefs.capture_devices_descr != NULL)
+      g_free(prefs.capture_devices_descr);
+    prefs.capture_devices_descr = g_strdup(value);
+  } else if (strcmp(pref_name, PRS_CAP_DEVICES_HIDE) == 0) {
+    if (prefs.capture_devices_hide != NULL)
+      g_free(prefs.capture_devices_hide);
+    prefs.capture_devices_hide = g_strdup(value);
   } else if (strcmp(pref_name, PRS_CAP_PROM_MODE) == 0) {
     prefs.capture_prom_mode = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
   } else if (strcmp(pref_name, PRS_CAP_REAL_TIME) == 0) {
@@ -2047,6 +2057,16 @@
     fprintf(pf, PRS_CAP_DEVICE ": %s\n", prefs.capture_device);
   }
 
+  if (prefs.capture_devices_descr != NULL) {
+    fprintf(pf, "\n# Interface descriptions. Ex: eth0(eth0 descr),eth1(eth1 descr),...\n");
+    fprintf(pf, PRS_CAP_DEVICES_DESCR ": %s\n", prefs.capture_devices_descr);
+  }
+
+  if (prefs.capture_devices_hide != NULL) {
+    fprintf(pf, "\n# Hide interface? Ex: eth0,eth3,...\n");
+    fprintf(pf, PRS_CAP_DEVICES_HIDE ": %s\n", prefs.capture_devices_hide);
+  }
+
   fprintf(pf, "\n# Capture in promiscuous mode? TRUE/FALSE\n");
   fprintf(pf, PRS_CAP_PROM_MODE ": %s\n",
 		  prefs.capture_prom_mode == TRUE ? "TRUE" : "FALSE");
@@ -2112,6 +2132,8 @@
   dest->gui_geometry_main_height = src->gui_geometry_main_height;
 /*  values for the capture dialog box */
   dest->capture_device = g_strdup(src->capture_device);
+  dest->capture_devices_descr = g_strdup(src->capture_devices_descr);
+  dest->capture_devices_hide = g_strdup(src->capture_devices_hide);
   dest->capture_prom_mode = src->capture_prom_mode;
   dest->capture_real_time = src->capture_real_time;
   dest->capture_auto_scroll = src->capture_auto_scroll;
@@ -2140,6 +2162,14 @@
   if (pr->capture_device != NULL) {
     g_free(pr->capture_device);
     pr->capture_device = NULL;
+  }
+  if (pr->capture_devices_descr != NULL) {
+    g_free(pr->capture_devices_descr);
+    pr->capture_devices_descr = NULL;
+  }
+  if (pr->capture_devices_hide != NULL) {
+    g_free(pr->capture_devices_hide);
+    pr->capture_devices_hide = NULL;
   }
 }
 
--- ../ethereal-0.9.14/prefs.h	Mon Jul 21 23:14:28 2003
+++ prefs.h	Sat Sep  6 01:23:50 2003
@@ -35,6 +35,9 @@
 #define DEF_WIDTH 750
 #define DEF_HEIGHT 550
 
+#define MAX_VAR_LEN    48
+#define MAX_VAL_LEN  1024
+
 /*
  * Convert a string listing name resolution types to a bitmask of
  * those types.
@@ -71,6 +74,8 @@
   guint32  name_resolve;
   gint     name_resolve_concurrency;
   gchar   *capture_device;
+  gchar   *capture_devices_descr;
+  gchar   *capture_devices_hide;
   gboolean capture_prom_mode;
   gboolean capture_real_time;
   gboolean capture_auto_scroll;