8114a8113d494f4b36cec96c643487fd2aa3f6f4
[obnox/wireshark/wip.git] / gtk / prefs_capture.c
1 /* capture_prefs.c
2  * Dialog box for capture preferences
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #ifdef HAVE_LIBPCAP
30
31 #include <string.h>
32 #include <gtk/gtk.h>
33
34 #include <epan/prefs.h>
35
36 #include "../globals.h"
37 #include "../simple_dialog.h"
38 #include "../capture_ifinfo.h"
39 #include "../capture_ui_utils.h"
40
41 #include "gtk/prefs_capture.h"
42 #include "gtk/prefs_dlg.h"
43 #include "gtk/gui_utils.h"
44 #include "gtk/dlg_utils.h"
45 #include "gtk/main.h"
46 #include "gtk/main_welcome.h"
47 #include "gtk/help_dlg.h"
48 #include "gtk/stock_icons.h"
49 #include <epan/strutil.h>
50
51
52 #define DEVICE_KEY              "device"
53 #define PROM_MODE_KEY           "prom_mode"
54 #define PCAP_NG_KEY             "pcap_ng"
55 #define CAPTURE_REAL_TIME_KEY   "capture_real_time"
56 #define AUTO_SCROLL_KEY         "auto_scroll"
57 #define SHOW_INFO_KEY           "show_info"
58
59 #define CAPTURE_TABLE_ROWS 6
60
61 #define IFOPTS_CALLER_PTR_KEY   "ifopts_caller_ptr"
62 #define IFOPTS_DIALOG_PTR_KEY   "ifopts_dialog_ptr"
63 #define IFOPTS_TABLE_ROWS 2
64 #define IFOPTS_LIST_TEXT_COLS  4
65 #define IFOPTS_MAX_DESCR_LEN 128
66 #define IFOPTS_IF_NOSEL -1
67
68 /* interface options dialog */
69 static GtkWidget *cur_list, *if_dev_lb, *if_name_lb, *if_linktype_cb, *if_descr_te, *if_hide_cb;
70 static GtkTreeSelection *if_selection;  /* current interface row selected */
71 static int num_linktypes;
72 static gboolean interfaces_info_nochange;  /* TRUE to ignore Interface Options Properties */
73                                            /*  widgets "changed" callbacks.               */
74
75 static void ifopts_edit_cb(GtkWidget *w, gpointer data);
76 static void ifopts_edit_ok_cb(GtkWidget *w, gpointer parent_w);
77 static void ifopts_edit_destroy_cb(GtkWidget *win, gpointer data);
78 static void ifopts_edit_ifsel_cb(GtkTreeSelection *selection, gpointer data);
79 static void ifopts_edit_linktype_changed_cb(GtkComboBox *ed, gpointer udata);
80 static void ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata);
81 static void ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata);
82 static void ifopts_options_add(GtkListStore *list_store, if_info_t *if_info);
83 static void ifopts_options_free(gchar *text[]);
84 static void ifopts_if_liststore_add(void);
85 static void ifopts_write_new_linklayer(void);
86 static void ifopts_write_new_descr(void);
87 static void ifopts_write_new_hide(void);
88
89 GtkWidget*
90 capture_prefs_show(void)
91 {
92         GtkWidget       *main_tb, *main_vb;
93         GtkWidget       *if_cbxe, *if_lb, *promisc_cb, *pcap_ng_cb, *sync_cb, *auto_scroll_cb, *show_info_cb;
94         GtkWidget       *ifopts_lb, *ifopts_bt;
95         GList           *if_list, *combo_list;
96         int             err;
97         int             row = 0;
98         GtkTooltips     *tooltips = gtk_tooltips_new();
99         gchar           *tooltips_text;
100
101         /* Main vertical box */
102         main_vb = gtk_vbox_new(FALSE, 7);
103         gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
104
105         /* Main table */
106         main_tb = gtk_table_new(CAPTURE_TABLE_ROWS, 2, FALSE);
107         gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
108         gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
109         gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
110         gtk_widget_show(main_tb);
111         g_object_set_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY, tooltips);
112
113         /* Default device */
114         if_lb = gtk_label_new("Default interface:");
115         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_lb, 0, 1, row, row+1);
116         gtk_misc_set_alignment(GTK_MISC(if_lb), 1.0f, 0.5f);
117         gtk_widget_show(if_lb);
118
119         if_cbxe = gtk_combo_box_entry_new_text();
120         /*
121          * XXX - what if we can't get the list?
122          */
123         if_list = capture_interface_list(&err, NULL);
124         combo_list = build_capture_combo_list(if_list, FALSE);
125         free_interface_list(if_list);
126         if (combo_list != NULL) {
127                 GList *combo_entry;
128                 for (combo_entry = combo_list; combo_entry != NULL; combo_entry = g_list_next(combo_entry)) {
129                                 gtk_combo_box_append_text(GTK_COMBO_BOX(if_cbxe), combo_entry->data);
130                 }
131         }
132         if (prefs.capture_device) {
133                 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(if_cbxe))),
134                                    prefs.capture_device);
135         }
136         else if (combo_list != NULL) {
137                 gtk_combo_box_set_active(GTK_COMBO_BOX(if_cbxe), 0);
138         }
139         free_capture_combo_list(combo_list);
140
141         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_cbxe, 1, 2, row, row+1);
142         tooltips_text = "The default interface to be captured from.";
143         gtk_tooltips_set_tip(tooltips, if_lb, tooltips_text, NULL);
144         gtk_tooltips_set_tip(tooltips, gtk_bin_get_child(GTK_BIN(if_cbxe)), tooltips_text, NULL);
145         gtk_widget_show(if_cbxe);
146         g_object_set_data(G_OBJECT(main_vb), DEVICE_KEY, if_cbxe);
147         row++;
148
149         /* Interface properties */
150         ifopts_lb = gtk_label_new("Interfaces:");
151         gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_lb, 0, 1, row, row+1);
152         gtk_misc_set_alignment(GTK_MISC(ifopts_lb), 1.0f, 0.5f);
153         gtk_widget_show(ifopts_lb);
154
155         ifopts_bt = gtk_button_new_from_stock(WIRESHARK_STOCK_EDIT);
156         tooltips_text = "Open a dialog box to set various interface options.";
157         gtk_tooltips_set_tip(tooltips, ifopts_lb, tooltips_text, NULL);
158         gtk_tooltips_set_tip(tooltips, ifopts_bt, tooltips_text, NULL);
159         g_signal_connect(ifopts_bt, "clicked", G_CALLBACK(ifopts_edit_cb), NULL);
160         gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_bt, 1, 2, row, row+1);
161         row++;
162
163         /* Promiscuous mode */
164         promisc_cb = create_preference_check_button(main_tb, row++,
165             "Capture packets in promiscuous mode:",
166             "Usually a network card will only capture the traffic sent to its own network address. "
167             "If you want to capture all traffic that the network card can \"see\", mark this option. "
168             "See the FAQ for some more details of capturing packets from a switched network. ",
169             prefs.capture_prom_mode);
170         g_object_set_data(G_OBJECT(main_vb), PROM_MODE_KEY, promisc_cb);
171
172         /* Pcap-NG format */
173         pcap_ng_cb = create_preference_check_button(main_tb, row++,
174             "Capture packets in pcap-ng format:",
175             "Capture packets in the next-generation capture file format. "
176             "This is still experimental.",
177             prefs.capture_pcap_ng);
178         g_object_set_data(G_OBJECT(main_vb), PCAP_NG_KEY, pcap_ng_cb);
179
180         /* Real-time capture */
181         sync_cb = create_preference_check_button(main_tb, row++,
182             "Update list of packets in real time:",
183             "Update the list of packets while capture is in progress. "
184             "Don't use this option if you notice packet drops.",
185             prefs.capture_real_time);
186         g_object_set_data(G_OBJECT(main_vb), CAPTURE_REAL_TIME_KEY, sync_cb);
187
188         /* Auto-scroll real-time capture */
189         auto_scroll_cb = create_preference_check_button(main_tb, row++,
190             "Automatic scrolling in live capture:",
191             "Automatic scrolling of the packet list while live capture is in progress. ",
192             prefs.capture_auto_scroll);
193         g_object_set_data(G_OBJECT(main_vb), AUTO_SCROLL_KEY, auto_scroll_cb);
194
195         /* Show capture info dialog */
196         show_info_cb = create_preference_check_button(main_tb, row++,
197             "Hide capture info dialog:",
198             "Hide the capture info dialog while capturing. ",
199             !prefs.capture_show_info);
200         g_object_set_data(G_OBJECT(main_vb), SHOW_INFO_KEY, show_info_cb);
201
202         /* Show 'em what we got */
203         gtk_widget_show_all(main_vb);
204
205         return(main_vb);
206 }
207
208 void
209 capture_prefs_fetch(GtkWidget *w)
210 {
211         GtkWidget *if_cbxe, *promisc_cb, *pcap_ng_cb, *sync_cb, *auto_scroll_cb, *show_info_cb;
212         gchar   *if_text;
213
214         if_cbxe    = (GtkWidget *)g_object_get_data(G_OBJECT(w), DEVICE_KEY);
215         promisc_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), PROM_MODE_KEY);
216         pcap_ng_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), PCAP_NG_KEY);
217         sync_cb    = (GtkWidget *)g_object_get_data(G_OBJECT(w), CAPTURE_REAL_TIME_KEY);
218         auto_scroll_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), AUTO_SCROLL_KEY);
219         show_info_cb = (GtkWidget *)g_object_get_data(G_OBJECT(w), SHOW_INFO_KEY);
220
221         if (prefs.capture_device != NULL) {
222                 g_free(prefs.capture_device);
223                 prefs.capture_device = NULL;
224         }
225         if_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(if_cbxe)))));
226         /* Strip out white space */
227         g_strstrip(if_text);
228         /* If there was nothing but white space, treat that as an
229            indication that the user doesn't want to wire in a default
230            device, and just wants the first device in the list chosen. */
231         if (*if_text == '\0') {
232                 g_free(if_text);
233                 if_text = NULL;
234         }
235         prefs.capture_device = if_text;
236
237         prefs.capture_prom_mode = GTK_TOGGLE_BUTTON (promisc_cb)->active;
238
239         prefs.capture_pcap_ng = GTK_TOGGLE_BUTTON (pcap_ng_cb)->active;
240
241         prefs.capture_real_time = GTK_TOGGLE_BUTTON (sync_cb)->active;
242
243         prefs.capture_auto_scroll = GTK_TOGGLE_BUTTON (auto_scroll_cb)->active;
244
245         prefs.capture_show_info = !(GTK_TOGGLE_BUTTON (show_info_cb)->active);
246 }
247
248 void
249 capture_prefs_apply(GtkWidget *w _U_)
250 {
251 }
252
253 void
254 capture_prefs_destroy(GtkWidget *w)
255 {
256         GtkWidget *caller = gtk_widget_get_toplevel(w);
257         GtkWidget *dlg;
258
259         /* Is there an interface descriptions dialog associated with this
260            Preferences dialog? */
261         dlg = g_object_get_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY);
262
263         if (dlg != NULL) {
264                 /* Yes.  Destroy it. */
265                 window_destroy(dlg);
266         }
267 }
268
269 /*
270  * Create an edit interface options dialog.
271  */
272 enum
273 {
274         DEVICE_COLUMN,
275         DESC_COLUMN,
276         DEF_LINK_LAYER_COLUMN,
277         COMMENT_COLUMN,
278         HIDE_COLUMN,
279         DLT_COLUMN,
280         N_COLUMN /* The number of columns */
281 };
282
283 static void
284 ifopts_edit_cb(GtkWidget *w, gpointer data _U_)
285 {
286         GtkWidget         *ifopts_edit_dlg, *cur_scr_win, *main_hb, *main_tb,
287                           *cur_opts_fr, *ed_opts_fr, *main_vb,
288                           *if_linktype_lb, *if_descr_lb, *if_hide_lb,
289                           *bbox, *ok_bt, *cancel_bt, *help_bt;
290
291         GtkListStore      *list_store;
292         GtkWidget         *list;
293         GtkTreeViewColumn *column;
294         GtkCellRenderer   *renderer;
295         GtkTreeView       *list_view;
296         GtkTreeSelection  *selection;
297
298         int row = 0;
299
300         GtkWidget   *caller   = gtk_widget_get_toplevel(w);
301         GtkTooltips *tooltips = gtk_tooltips_new();
302
303         /* Has an edit dialog box already been opened for that top-level
304            widget? */
305         ifopts_edit_dlg = g_object_get_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY);
306         if (ifopts_edit_dlg != NULL) {
307                 /* Yes.  Just re-activate that dialog box. */
308                 reactivate_window(ifopts_edit_dlg);
309                 return;
310         }
311
312         /* create a new dialog */
313         ifopts_edit_dlg = dlg_conf_window_new("Wireshark: Preferences: Interface Options");
314         gtk_window_set_default_size(GTK_WINDOW(ifopts_edit_dlg), DEF_WIDTH, 440);
315
316         main_vb = gtk_vbox_new(FALSE, 1);
317         gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
318         gtk_container_add(GTK_CONTAINER(ifopts_edit_dlg), main_vb);
319         gtk_widget_show(main_vb);
320
321         /* create current options frame */
322         cur_opts_fr = gtk_frame_new("Interfaces");
323         gtk_container_add(GTK_CONTAINER(main_vb), cur_opts_fr);
324         gtk_widget_show(cur_opts_fr);
325
326         /* create a scrolled window to pack the current options TreeView widget into */
327         cur_scr_win = scrolled_window_new(NULL, NULL);
328         gtk_container_set_border_width(GTK_CONTAINER(cur_scr_win), 3);
329         gtk_container_add(GTK_CONTAINER(cur_opts_fr), cur_scr_win);
330         gtk_widget_show(cur_scr_win);
331
332         /*
333          * Create current options TreeView.
334          */
335         list_store = gtk_list_store_new(N_COLUMN,       /* Total number of columns XXX  */
336                                         G_TYPE_STRING,  /* Device                       */
337                                         G_TYPE_STRING,  /* Description                  */
338                                         G_TYPE_STRING,  /* Default link-layer           */
339                                         G_TYPE_STRING,  /* Comment                      */
340                                         G_TYPE_BOOLEAN, /* Hide?                        */
341                                         G_TYPE_INT);    /* Dlt                          */
342
343         list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
344
345         list_view = GTK_TREE_VIEW(list);
346
347         /* The view now holds a reference.  We can get rid of our own reference */
348         g_object_unref (G_OBJECT (list_store));
349
350         /* 
351          * Create the first column packet, associating the "text" attribute of the
352          * cell_renderer to the first column of the model 
353          */
354         renderer = gtk_cell_renderer_text_new ();
355         column = gtk_tree_view_column_new_with_attributes ("Device", renderer, 
356                                                            "text", DEVICE_COLUMN, 
357                                                            NULL);
358
359         gtk_tree_view_column_set_resizable(column, TRUE);
360         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
361 #ifdef _WIN32
362         gtk_tree_view_column_set_min_width(column, 230);
363 #else
364         gtk_tree_view_column_set_min_width(column, 70);
365 #endif
366         /* Add the column to the view. */
367         gtk_tree_view_append_column (list_view, column);
368
369         column = gtk_tree_view_column_new_with_attributes ("Description", renderer, 
370                                                            "text", DESC_COLUMN, 
371                                                            NULL);
372
373         gtk_tree_view_column_set_resizable(column, TRUE);
374         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
375         gtk_tree_view_column_set_min_width(column, 260);
376         /* Add the column to the view. */
377         gtk_tree_view_append_column (list_view, column);
378
379         column = gtk_tree_view_column_new_with_attributes ("Default link-layer", renderer, 
380                                                            "text", DEF_LINK_LAYER_COLUMN, 
381                                                            NULL);
382
383         gtk_tree_view_column_set_resizable(column, TRUE);
384         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
385         gtk_tree_view_column_set_min_width(column, 230);
386         /* Add the column to the view. */
387         gtk_tree_view_append_column (list_view, column);
388
389         column = gtk_tree_view_column_new_with_attributes ("Comment", renderer, 
390                                                            "text", COMMENT_COLUMN, 
391                                                            NULL);
392
393         gtk_tree_view_column_set_resizable(column, TRUE);
394         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
395         gtk_tree_view_column_set_min_width(column, 100);
396         /* Add the column to the view. */
397         gtk_tree_view_append_column (list_view, column);
398
399         renderer = gtk_cell_renderer_toggle_new ();
400         column = gtk_tree_view_column_new_with_attributes ("Hide?", renderer, 
401                                                            "active", HIDE_COLUMN, 
402                                                            NULL);
403
404         gtk_tree_view_column_set_resizable(column, FALSE);
405         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
406         /* Add the column to the view. */
407         gtk_tree_view_append_column (list_view, column);
408
409 #if 0
410         /* Don't show the DLT column */
411         column = gtk_tree_view_column_new_with_attributes ("DLT", renderer, 
412                                                            "text", DLT_COLUMN, 
413                                                            NULL);
414
415         gtk_tree_view_column_set_resizable(column, TRUE);
416         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
417         gtk_tree_view_column_set_min_width(column, 40);
418         /* Add the column to the view. */
419         gtk_tree_view_append_column (list_view, column);
420 #endif
421         /* Setup the selection handler */
422         selection = gtk_tree_view_get_selection(list_view);
423         gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
424
425         cur_list = list;
426         gtk_container_add(GTK_CONTAINER(cur_scr_win), cur_list);
427
428         if_selection = selection;
429
430         g_signal_connect (G_OBJECT (selection), "changed", /* select_row */
431                           G_CALLBACK (ifopts_edit_ifsel_cb),
432                           NULL);
433
434         gtk_widget_show(cur_list);
435
436         /* add interface names to cell */
437         ifopts_if_liststore_add();
438
439         /* create edit options frame */
440         ed_opts_fr = gtk_frame_new("Properties");
441         gtk_box_pack_start(GTK_BOX(main_vb), ed_opts_fr, FALSE, FALSE, 0);
442         gtk_widget_show(ed_opts_fr);
443
444         main_hb = gtk_hbox_new(TRUE, 5);
445         gtk_container_set_border_width(GTK_CONTAINER(main_hb), 3);
446         gtk_container_add(GTK_CONTAINER(ed_opts_fr), main_hb);
447         gtk_widget_show(main_hb);
448
449         /* table to hold description text entry and hide button */
450         main_tb = gtk_table_new(IFOPTS_TABLE_ROWS, 4, FALSE);
451         gtk_box_pack_start(GTK_BOX(main_hb), main_tb, TRUE, FALSE, 10);
452         gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
453         gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
454         gtk_widget_show(main_tb);
455
456         if_dev_lb = gtk_label_new("Device:");
457         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 0, 1, row, row+1);
458         gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 1.0f, 0.5f);
459         gtk_widget_show(if_dev_lb);
460
461         if_dev_lb = gtk_label_new("");
462         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 1, 2, row, row+1);
463         gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 0.0f, 0.5f);
464         gtk_widget_show(if_dev_lb);
465         row++;
466
467         if_name_lb = gtk_label_new("Description:");
468         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 0, 1, row, row+1);
469         gtk_misc_set_alignment(GTK_MISC(if_name_lb), 1.0f, 0.5f);
470         gtk_widget_show(if_name_lb);
471
472         if_name_lb = gtk_label_new("");
473         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 1, 2, row, row+1);
474         gtk_misc_set_alignment(GTK_MISC(if_name_lb), 0.0f, 0.5f);
475         gtk_widget_show(if_name_lb);
476         row++;
477
478         if_linktype_lb = gtk_label_new("Default link-layer header type:");
479         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_linktype_lb, 0, 1, row, row+1);
480         gtk_misc_set_alignment(GTK_MISC(if_linktype_lb), 1.0f, 0.5f);
481         gtk_widget_show(if_linktype_lb);
482
483         if_linktype_cb = gtk_combo_box_new_text();
484         num_linktypes = 0;
485         interfaces_info_nochange = FALSE;
486         g_signal_connect(if_linktype_cb, "changed", G_CALLBACK(ifopts_edit_linktype_changed_cb),
487                         cur_list);
488         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_linktype_cb, 1, 2, row, row+1);
489         gtk_widget_show(if_linktype_cb);
490         row++;
491
492         /* create interface description label and text entry */
493         if_descr_lb = gtk_label_new("Comment:");
494         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_lb, 0, 1, row, row+1);
495         gtk_misc_set_alignment(GTK_MISC(if_descr_lb), 1.0f, 0.5f);
496         gtk_widget_show(if_descr_lb);
497
498         if_descr_te = gtk_entry_new();
499         g_signal_connect(if_descr_te, "changed", G_CALLBACK(ifopts_edit_descr_changed_cb),
500                         cur_list);
501         gtk_entry_set_max_length(GTK_ENTRY(if_descr_te), IFOPTS_MAX_DESCR_LEN);
502         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_te, 1, 2, row, row+1);
503         gtk_widget_show(if_descr_te);
504         row++;
505
506         /* create "hide interface" label and button */
507         if_hide_lb = gtk_label_new("Hide interface?:");
508         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_lb, 0, 1, row, row+1);
509         gtk_misc_set_alignment(GTK_MISC(if_hide_lb), 1.0f, 0.5f);
510         gtk_widget_show(if_hide_lb);
511
512         if_hide_cb = gtk_check_button_new();
513         g_signal_connect(if_hide_cb, "toggled", G_CALLBACK(ifopts_edit_hide_changed_cb),
514                         cur_list);
515         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_cb, 1, 2, row, row+1);
516         gtk_widget_show(if_hide_cb);
517         row++;
518
519         /* button row: OK and Cancel buttons */
520         bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
521         gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
522         gtk_widget_show(bbox);
523
524         ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
525         gtk_tooltips_set_tip(tooltips, ok_bt,
526                              "Save changes and exit dialog", NULL);
527         g_signal_connect(ok_bt, "clicked", G_CALLBACK(ifopts_edit_ok_cb), ifopts_edit_dlg);
528
529         cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
530         gtk_tooltips_set_tip(tooltips, cancel_bt,
531                              "Cancel and exit dialog", NULL);
532         window_set_cancel_button(ifopts_edit_dlg, cancel_bt, window_cancel_button_cb);
533
534         help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
535         g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), 
536                          (gpointer)HELP_CAPTURE_INTERFACE_OPTIONS_DIALOG);
537         gtk_tooltips_set_tip (tooltips, help_bt, "Show topic specific help", NULL);
538
539         gtk_widget_grab_default(ok_bt);
540
541         g_signal_connect(ifopts_edit_dlg, "delete_event", G_CALLBACK(window_delete_event_cb),
542                  NULL);
543         /* Call a handler when we're destroyed, so we can inform
544            our caller, if any, that we've been destroyed. */
545         g_signal_connect(ifopts_edit_dlg, "destroy", G_CALLBACK(ifopts_edit_destroy_cb), NULL);
546
547         /* Set the key for the new dialog to point to our caller. */
548         g_object_set_data(G_OBJECT(ifopts_edit_dlg), IFOPTS_CALLER_PTR_KEY, caller);
549         /* Set the key for the caller to point to us */
550         g_object_set_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY, ifopts_edit_dlg);
551
552         gtk_widget_show(ifopts_edit_dlg); /* triggers ifopts_edit_ifsel_cb() with the  */
553                                           /*  "interfaces" TreeView first row selected */
554         window_present(ifopts_edit_dlg);
555 }
556
557 /*
558  * User selected "OK". Create/write preferences strings.
559  */
560 static void
561 ifopts_edit_ok_cb(GtkWidget *w _U_, gpointer parent_w)
562 {
563         if (if_selection){ /* XXX: Cannot be NULL ?? */
564                 /* create/write new interfaces link-layer string */
565                 ifopts_write_new_linklayer();
566
567                 /* create/write new interfaces description string */
568                 ifopts_write_new_descr();
569
570                 /* create/write new "hidden" interfaces string */
571                 ifopts_write_new_hide();
572         }
573
574         /* Update welcome page */
575         welcome_if_panel_reload ();
576
577         /* Now nuke this window. */
578         gtk_grab_remove(GTK_WIDGET(parent_w));
579         window_destroy(GTK_WIDGET(parent_w));
580 }
581
582 static void
583 ifopts_edit_destroy_cb(GtkWidget *win, gpointer data _U_)
584 {
585         GtkWidget *caller;
586
587         /* Get the widget that requested that we be popped up, if any.
588            (It should arrange to destroy us if it's destroyed, so
589            that we don't get a pointer to a non-existent window here.) */
590         caller = g_object_get_data(G_OBJECT(win), IFOPTS_CALLER_PTR_KEY);
591
592         if (caller != NULL) {
593                 /* Tell it we no longer exist. */
594                 g_object_set_data(G_OBJECT(caller), IFOPTS_DIALOG_PTR_KEY, NULL);
595         }
596 }
597
598 static gint
599 ifopts_description_to_val (const char *if_name, const char *descr) 
600 {
601         if_caps_t *caps;
602         int dlt = -1;
603
604         caps = capture_get_if_capabilities(if_name, FALSE, NULL);
605         if (caps != NULL) {
606                 if (caps->data_link_types != NULL) {
607                         GList  *lt_entry;
608                         /* XXX: Code skips first entry because that's the default ??? */
609                         for (lt_entry = g_list_next(caps->data_link_types);
610                             lt_entry != NULL;
611                             lt_entry = g_list_next(lt_entry)) {
612                                 data_link_info_t *dli_p = lt_entry->data;
613                                 if (dli_p->description) {
614                                         if (strcmp(dli_p->description, descr) == 0) {
615                                                 dlt = dli_p->dlt;
616                                                 break;
617                                         }
618                                 } else {
619                                         if (strcmp(dli_p->name, descr) == 0) {
620                                                 dlt = dli_p->dlt;
621                                                 break;
622                                         }
623                                 }
624                         }
625                 }
626                 free_if_capabilities(caps);
627         }
628         return dlt;
629 }
630
631 /*
632  * Interface selected callback; update displayed widgets.
633  */
634 static void
635 ifopts_edit_ifsel_cb(GtkTreeSelection   *selection _U_,
636                      gpointer            data _U_)
637 {
638         GtkTreeIter         iter;
639         GtkTreeModel       *model;
640         gchar              *desc, *comment, *text;
641         gchar              *if_name, *linktype;
642         gboolean            hide;
643         if_caps_t *caps;
644         gint                selected = 0;
645
646         /* Get list_store data for currently selected interface */
647         if (!gtk_tree_selection_get_selected (if_selection, &model, &iter)){
648                 return;
649         }
650         gtk_tree_model_get(model, &iter, 
651                            DEVICE_COLUMN,  &if_name,
652                            DESC_COLUMN,    &desc,
653                            DEF_LINK_LAYER_COLUMN, &linktype,
654                            COMMENT_COLUMN, &comment,
655                            HIDE_COLUMN,    &hide,
656                            -1);
657
658         /* display  the interface device from current interfaces selection */
659         gtk_label_set_text(GTK_LABEL(if_dev_lb), if_name);
660
661         /* display the interface name from current interfaces selection */
662         gtk_label_set_text(GTK_LABEL(if_name_lb), desc);
663
664         /* Ignore "changed" callbacks while we update the Properties widgets */
665         interfaces_info_nochange = TRUE;
666
667         /* display the link-layer header type from current interfaces selection */
668         /*  -- remove old linktype list (if any) from the ComboBox */
669         while (num_linktypes > 0) {
670                 num_linktypes--;
671                 gtk_combo_box_remove_text (GTK_COMBO_BOX(if_linktype_cb), num_linktypes);
672         }
673
674         /*  -- build and add to the ComboBox a linktype list for the current interfaces selection */
675         caps = capture_get_if_capabilities(if_name, FALSE, NULL);
676         if (caps != NULL) {
677                 if (caps->data_link_types != NULL) {
678                         GList *lt_entry;
679                         for (lt_entry = caps->data_link_types; lt_entry != NULL;
680                             lt_entry = g_list_next(lt_entry)) {
681                                 data_link_info_t *dli_p = lt_entry->data;
682                                 text = (dli_p->description != NULL) ? dli_p->description : dli_p->name;
683                                 if (strcmp(linktype, text) == 0) {
684                                         selected = num_linktypes;
685                                 }
686                                 gtk_combo_box_append_text(GTK_COMBO_BOX(if_linktype_cb), text);
687                                 num_linktypes++;
688                         }
689                         gtk_widget_set_sensitive(if_linktype_cb, num_linktypes >= 2);
690                         gtk_combo_box_set_active(GTK_COMBO_BOX(if_linktype_cb), selected);
691                 }
692                 free_if_capabilities(caps);
693         }
694
695         /* display the interface description from current interfaces selection */
696         gtk_entry_set_text(GTK_ENTRY(if_descr_te), comment);
697
698         /* display the "hide interface" button state from current interfaces selection */
699         if (hide)
700                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), TRUE);
701         else
702                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), FALSE);
703
704         interfaces_info_nochange = FALSE;
705
706         g_free(if_name);
707         g_free(desc);
708         g_free(linktype);
709         g_free(comment);
710 }
711
712 /*
713  * Link-layer entry changed callback; update list_store for currently selected interface.
714  */
715 static void
716 ifopts_edit_linktype_changed_cb(GtkComboBox *cb, gpointer udata)
717 {
718         gchar        *ifnm, *text;
719         gint          linktype;
720         GtkTreeModel *list_model;
721 #if ! GTK_CHECK_VERSION(2,6,0)
722         GtkTreeIter   iter;
723         GtkTreeModel *model;
724 #endif
725         GtkTreeIter   list_iter;
726         GtkListStore *list_store;
727
728         if (interfaces_info_nochange)
729                 return;
730
731         if (if_selection == NULL)  /* XXX: Cannot be NULL ?? */
732                 return;
733
734         if (!gtk_tree_selection_get_selected (if_selection, &list_model, &list_iter)){
735                 return;
736         }
737         
738         gtk_tree_model_get(list_model, &list_iter, 
739                 DEVICE_COLUMN, &ifnm,
740                 -1);
741
742         /* get current description text and set value in list_store for currently selected interface */
743 #if GTK_CHECK_VERSION(2,6,0)
744         text = gtk_combo_box_get_active_text(cb);
745         if (text) {
746 #else
747         if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cb), &iter)) {
748                 model = gtk_combo_box_get_model(GTK_COMBO_BOX(cb));
749                 gtk_tree_model_get(model, &iter, 0, &text, -1);
750 #endif
751                 linktype = ifopts_description_to_val(ifnm, text);
752                 list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (udata))); /* Get store */
753                 gtk_list_store_set  (list_store, &list_iter,
754                                      DEF_LINK_LAYER_COLUMN, text,
755                                      DLT_COLUMN, linktype,
756                                      -1);
757                 g_free(text);
758         }
759 }
760
761 /*
762  * Comment text entry changed callback; update list_store for currently selected interface.
763  */
764 static void
765 ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata)
766 {
767         gchar        *text;
768         GtkTreeModel *list_model;
769         GtkTreeIter   list_iter;
770         GtkListStore *list_store;
771
772         if (interfaces_info_nochange)
773                 return;
774
775         if (if_selection == NULL) /* XXX: Cannot be NULL ?? */
776                 return;
777
778         if (!gtk_tree_selection_get_selected (if_selection, &list_model, &list_iter)){
779                 return;
780         }
781
782         /* get current description text and set value in list_store for currently selected interface */
783         text = gtk_editable_get_chars(GTK_EDITABLE(ed), 0, -1);
784         /* replace any reserved formatting characters "()," with spaces */
785         g_strdelimit(text, "(),", ' ');
786
787         list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (udata))); /* Get store */
788         gtk_list_store_set  (list_store, &list_iter,
789                              COMMENT_COLUMN, text,
790                              -1);
791
792         g_free(text);
793 }
794
795 /*
796  * Hide toggle button changed callback; update list_store for currently selected interface .
797  */
798 static void
799 ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata)
800 {
801         GtkTreeModel *list_model;
802         GtkTreeIter   list_iter;
803         GtkListStore *list_store;
804
805         if (interfaces_info_nochange)
806                 return;
807
808         if (if_selection == NULL) /* XXX: Cannot be NULL ?? */
809                 return;
810
811         if (!gtk_tree_selection_get_selected (if_selection, &list_model, &list_iter)){
812                 return;
813         }
814
815         list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (udata))); /* Get store */
816         /* get "hide" button state and set status in list_store for currently selected interface */
817         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tbt)) == TRUE)
818                 gtk_list_store_set  (list_store, &list_iter,
819                                      HIDE_COLUMN, TRUE,
820                                      -1);
821         else
822                 gtk_list_store_set  (list_store, &list_iter,
823                                      HIDE_COLUMN, FALSE,
824                                      -1);
825 }
826
827 /*
828  * Add any saved interface options that apply to interfaces ListStore.
829  *
830  * NOTE:
831  *              Interfaces that have been removed from the machine or disabled and
832  *              no longer apply are ignored. Therefore, if the user subsequently
833  *              selects "OK", the options for these interfaces are lost (they're
834  *              lost permanently if "Save" is selected).
835  */
836 static void
837 ifopts_options_add(GtkListStore *list_store, if_info_t *if_info)
838 {
839         gchar   *p;
840         gchar   *ifnm;
841         gchar   *desc;
842         gchar   *pr_descr;
843         gchar   *text[] = { NULL, NULL, NULL, NULL };
844         if_caps_t *caps;
845         gint     linktype;
846         gboolean hide;
847         GtkTreeIter  iter;
848
849         /* set device name text */
850         text[0] = g_strdup(if_info->name);
851
852         /* set OS description */
853         if (if_info->description != NULL)
854                 text[1] = g_strdup(if_info->description);
855         else
856                 text[1] = g_strdup("");
857
858         /* set default link-layer header type */
859         linktype = capture_dev_user_linktype_find(if_info->name);
860         caps = capture_get_if_capabilities(if_info->name, FALSE, NULL);
861         if (caps != NULL) {
862                 if (caps->data_link_types != NULL) {
863                         GList  *lt_entry;
864                         for (lt_entry = caps->data_link_types; lt_entry != NULL;
865                             lt_entry = g_list_next(lt_entry)) {
866                                 data_link_info_t *dli_p = lt_entry->data;
867                                 /* If we have no previous link-layer header type we use the first one */
868                                 if (linktype == -1 || linktype == dli_p->dlt) {
869                                         if (dli_p->description) {
870                                                 text[2] = g_strdup(dli_p->description);
871                                         } else {
872                                                 text[2] = g_strdup(dli_p->name);
873                                         }
874                                         break;
875                                 }
876                         }
877                 }
878                 free_if_capabilities(caps);
879         }
880         /* if we have no link-layer */
881         if (text[2] == NULL)
882                 text[2] = g_strdup("");
883
884         /* add interface descriptions */
885         if (prefs.capture_devices_descr != NULL) {
886                 /* create working copy of device descriptions */
887                 pr_descr = g_strdup(prefs.capture_devices_descr);
888
889                 /* if we find a description for this interface */
890                 if ((ifnm = strstr(pr_descr, if_info->name)) != NULL) {
891                         p = ifnm;
892                         while (*p != '\0') {
893                                 /* found left parenthesis, start of description */
894                                 if (*p == '(') {
895                                         p++;
896                                         /* if syntax error */
897                                         if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')'))
898                                                 break;
899
900                                         /* save pointer to beginning of description */
901                                         desc = p;
902                                         p++;
903                                         /* skip to end of description */
904                                         while (*p != '\0') {
905                                                 /* if syntax error */
906                                                 if ((*p == ',') || (*p == '('))
907                                                         break;
908
909                                                 /* end of description */
910                                                 else if (*p == ')') {
911                                                         /* terminate and set description text */
912                                                         *p = '\0';
913                                                         text[3] = g_strdup(desc);
914                                                         break;
915                                                 }
916                                                 p++;
917                                         }
918                                         /* get out */
919                                         break;
920                                 } else
921                                         p++;
922                         }
923                 }
924
925                 g_free(pr_descr);
926         }
927
928         /* if we have no description */
929         if (text[3] == NULL)
930                 text[3] = g_strdup("");
931
932         /* check if interface is "hidden" */
933         if ((prefs.capture_devices_hide != NULL) &&
934             (strstr(prefs.capture_devices_hide, if_info->name) != NULL))
935                 hide = TRUE;
936         else
937                 hide = FALSE;
938
939         /* add row to ListStore */
940
941 #if GTK_CHECK_VERSION(2,6,0)
942         gtk_list_store_insert_with_values( list_store , &iter, G_MAXINT,
943 #else
944         gtk_list_store_append  (list_store, &iter);
945         gtk_list_store_set  (list_store, &iter,
946 #endif
947                              DEVICE_COLUMN,  text[0],
948                              DESC_COLUMN,    text[1],
949                              DEF_LINK_LAYER_COLUMN, text[2],
950                              COMMENT_COLUMN, text[3],
951                              HIDE_COLUMN,    hide,
952                              DLT_COLUMN,     linktype,
953                              -1);
954
955         ifopts_options_free(text);
956 }
957
958 static void
959 ifopts_options_free(gchar *text[])
960 {
961         gint i;
962
963         for (i=0; i < IFOPTS_LIST_TEXT_COLS; i++) {
964                 if (text[i] != NULL) {
965                         g_free(text[i]);
966                         text[i] = NULL;
967                 }
968         }
969 }
970
971 /*
972  * Add all interfaces to interfaces ListStore.
973  */
974 static void
975 ifopts_if_liststore_add(void)
976 {
977         GList   *if_list, *ifl_p;
978         int      err;
979         gchar   *err_str;
980
981         if_list = capture_interface_list(&err, &err_str);  /* if_list = ptr to first element of list (or NULL) */
982         if (if_list == NULL) {
983                 if (err != NO_INTERFACES_FOUND) {
984                         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
985                 }
986                 g_free(err_str);
987                 return;
988         }
989
990         /* We have an interface list.                            */
991         /* add OS description + interface name text to ListStore */
992         for (ifl_p = if_list; ifl_p != NULL; ifl_p = g_list_next(ifl_p)) {
993                 /* should never happen, but just in case */
994                 if ((ifl_p->data) == NULL)
995                         continue;
996                 /* fill current options ListStore with current preference values */
997                 ifopts_options_add(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (cur_list))),
998                                    (if_info_t *)ifl_p->data);
999         }
1000         free_interface_list(if_list);
1001 }
1002
1003 /*
1004  * Create/write new interfaces link-layer string based on current CList.
1005  * Put it into the preferences value.
1006  */
1007 static void
1008 ifopts_write_new_linklayer(void)
1009 {
1010         GtkListStore    *store;
1011         GtkTreeIter      iter;
1012         GtkTreeModel    *model;
1013
1014         gboolean         more_items = TRUE, first_if = TRUE;  /* flag to check if first in list */
1015         gchar           *ifnm;
1016         gint             linktype;
1017         gchar           *tmp_linklayer;
1018         gchar           *new_linklayer;
1019
1020         /* new preferences interfaces link-layer string */
1021         new_linklayer = g_malloc0(MAX_VAL_LEN);
1022
1023         /* get link-layer for each row (interface) */
1024         model = gtk_tree_view_get_model(GTK_TREE_VIEW(cur_list));
1025         store = GTK_LIST_STORE(model);
1026         if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) ) {
1027
1028                 while (more_items) {
1029                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1030                                            DEVICE_COLUMN, &ifnm,
1031                                            DLT_COLUMN,    &linktype,
1032                                            -1);
1033
1034                         if (linktype == -1){
1035                                 more_items = gtk_tree_model_iter_next (model,&iter);
1036                                 continue;
1037                         }
1038
1039                         if (first_if != TRUE) {
1040                                 g_strlcat (new_linklayer, ",", MAX_VAL_LEN);
1041                         }
1042                         /*
1043                          * create/cat interface link-layer to new string
1044                          * (leave space for parens, comma and terminator)
1045                          */                     
1046                         tmp_linklayer = g_strdup_printf("%s(%d)", ifnm, linktype);
1047                         g_strlcat(new_linklayer, tmp_linklayer, MAX_VAL_LEN);
1048                         g_free(tmp_linklayer);
1049                         g_free(ifnm);
1050                         /* set first-in-list flag to false */
1051                         first_if = FALSE;
1052                         more_items = gtk_tree_model_iter_next (model,&iter);
1053                 }
1054
1055                 /* write new link-layer string to preferences */
1056                 if (strlen(new_linklayer) > 0) {
1057                         g_free(prefs.capture_devices_linktypes);
1058                         prefs.capture_devices_linktypes = new_linklayer;
1059                 }
1060                 /* no link-layers */
1061                 else {
1062                         g_free(prefs.capture_devices_linktypes);
1063                         g_free(new_linklayer);
1064                         prefs.capture_devices_linktypes = NULL;
1065                 }
1066         }
1067 }
1068
1069 /*
1070  * Create/write new interfaces description string based on current CList.
1071  * Put it into the preferences value.
1072  */
1073 static void
1074 ifopts_write_new_descr(void)
1075 {
1076         GtkListStore    *store;
1077         GtkTreeIter      iter;
1078         GtkTreeModel    *model;
1079         gboolean         more_items = TRUE;
1080         gboolean         first_if = TRUE;       /* flag to check if first in list */
1081         gchar           *ifnm;
1082         gchar           *desc;
1083         gchar           *tmp_descr;
1084         gchar           *new_descr;
1085
1086         /* new preferences interfaces description string */
1087         new_descr = g_malloc0(MAX_VAL_LEN);
1088
1089         /* get description for each row (interface) */
1090         model = gtk_tree_view_get_model(GTK_TREE_VIEW(cur_list));
1091         store = GTK_LIST_STORE(model);
1092         if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) ) {
1093                 while (more_items) {
1094                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1095                                 DEVICE_COLUMN, &ifnm,
1096                                 COMMENT_COLUMN, &desc,
1097                                 -1);
1098
1099                         /* if no description, skip this interface */
1100                         if (strlen(desc) == 0){
1101                                 more_items = gtk_tree_model_iter_next (model,&iter);
1102                                 continue;
1103                         }
1104                         /*
1105                          * create/cat interface description to new string
1106                          * (leave space for parens, comma and terminator)
1107                          */
1108                         if (first_if != TRUE) {
1109                                 g_strlcat (new_descr, ",", MAX_VAL_LEN);
1110                         }
1111
1112                         tmp_descr = g_strdup_printf("%s(%s)", ifnm, desc);
1113                         g_strlcat(new_descr, tmp_descr, MAX_VAL_LEN);
1114                         g_free(tmp_descr);
1115
1116                         /* set first-in-list flag to false */
1117                         first_if = FALSE;
1118                         more_items = gtk_tree_model_iter_next (model,&iter);
1119                 }
1120
1121                 /* write new description string to preferences */
1122                 if (strlen(new_descr) > 0) {
1123                         g_free(prefs.capture_devices_descr);
1124                         prefs.capture_devices_descr = new_descr;
1125                 }
1126                 /* no descriptions */
1127                 else {
1128                         g_free(prefs.capture_devices_descr);
1129                         g_free(new_descr);
1130                         prefs.capture_devices_descr = NULL;
1131                 }
1132         }
1133 }
1134
1135 /*
1136  * Create/write new "hidden" interfaces string based on current CList.
1137  * Put it into the preferences value.
1138  */
1139 static void
1140 ifopts_write_new_hide(void)
1141 {
1142         GtkListStore    *store;
1143         GtkTreeIter      iter;
1144         GtkTreeModel    *model;
1145         gboolean         more_items = TRUE;
1146         gint             first_if = TRUE;       /* flag to check if first in list */
1147         gchar           *ifnm;
1148         gboolean         hide;
1149         gchar           *new_hide;
1150
1151         /* new preferences "hidden" interfaces string */
1152         new_hide = g_malloc0(MAX_VAL_LEN);
1153
1154         /* get "hide" flag text for each row (interface) */
1155         model = gtk_tree_view_get_model(GTK_TREE_VIEW(cur_list));
1156         store = GTK_LIST_STORE(model);
1157         if( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter) ) {
1158                 while (more_items) {
1159                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1160                                            DEVICE_COLUMN, &ifnm,
1161                                            HIDE_COLUMN,   &hide,
1162                                            -1);
1163
1164                         /* if flag text is "No", skip this interface */
1165                         if (!hide){
1166                                 more_items = gtk_tree_model_iter_next (model,&iter);
1167                                 continue;
1168                         }
1169
1170                         /*
1171                          * create/cat interface to new string
1172                          */
1173                         if (first_if != TRUE)
1174                                 g_strlcat (new_hide, ",", MAX_VAL_LEN);
1175                         g_strlcat (new_hide, ifnm, MAX_VAL_LEN);
1176
1177                         /* set first-in-list flag to false */
1178                         first_if = FALSE;
1179                         more_items = gtk_tree_model_iter_next (model,&iter);
1180                 }
1181
1182                 /* write new "hidden" string to preferences */
1183                 if (strlen(new_hide) > 0) {
1184                         g_free(prefs.capture_devices_hide);
1185                         prefs.capture_devices_hide = new_hide;
1186                 }
1187                 /* no "hidden" interfaces */
1188                 else {
1189                         g_free(prefs.capture_devices_hide);
1190                         g_free(new_hide);
1191                         prefs.capture_devices_hide = NULL;
1192                 }
1193         }
1194 }
1195
1196 #endif /* HAVE_LIBPCAP */