Use the tap_dfilter_dlg mechanism.
[obnox/wireshark/wip.git] / gtk / capture_prefs.c
1 /* capture_prefs.c
2  * Dialog box for capture preferences
3  *
4  * $Id$
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@ethereal.com>
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 <pcap.h>
32 #include <string.h>
33 #include <gtk/gtk.h>
34
35 #include "globals.h"
36 #include "capture_prefs.h"
37 #include "gtkglobals.h"
38 #include <epan/prefs.h>
39 #include "prefs_dlg.h"
40 #include "gui_utils.h"
41 #include "dlg_utils.h"
42 #include "simple_dialog.h"
43 #include "pcap-util.h"
44 #include "capture_ui_utils.h"
45 #include "main.h"
46 #include "compat_macros.h"
47
48 #define DEVICE_KEY                              "device"
49 #define PROM_MODE_KEY                   "prom_mode"
50 #define CAPTURE_REAL_TIME_KEY   "capture_real_time"
51 #define AUTO_SCROLL_KEY                 "auto_scroll"
52 #define SHOW_INFO_KEY           "show_info"
53
54 #define CAPTURE_TABLE_ROWS 6
55
56 #define IFOPTS_CALLER_PTR_KEY   "ifopts_caller_ptr"
57 #define IFOPTS_DIALOG_PTR_KEY   "ifopts_dialog_ptr"
58 #define IFOPTS_TABLE_ROWS 2
59 #define IFOPTS_CLIST_COLS 4
60 #define IFOPTS_MAX_DESCR_LEN 128
61 #define IFOPTS_IF_NOSEL -1
62
63 /* interface options dialog */
64 static GtkWidget *cur_clist, *if_dev_lb, *if_name_lb, *if_descr_te, *if_hide_cb;
65 static gint ifrow;                                              /* current interface row selected */
66
67 static void ifopts_edit_cb(GtkWidget *w, gpointer data);
68 static void ifopts_edit_ok_cb(GtkWidget *w, gpointer parent_w);
69 static void ifopts_edit_destroy_cb(GtkWidget *win, gpointer data);
70 static void ifopts_edit_ifsel_cb(GtkWidget *clist, gint row, gint column,
71     GdkEventButton *event, gpointer data);
72 static void ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata);
73 static void ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata);
74 static void ifopts_options_add(GtkCList *clist, if_info_t *if_info);
75 static void ifopts_options_free(gchar *text[]);
76 static void ifopts_if_clist_add(void);
77 static void ifopts_write_new_descr(void);
78 static void ifopts_write_new_hide(void);
79
80 GtkWidget*
81 capture_prefs_show(void)
82 {
83         GtkWidget       *main_tb, *main_vb;
84         GtkWidget       *if_cb, *if_lb, *promisc_cb, *sync_cb, *auto_scroll_cb, *show_info_cb;
85         GtkWidget       *ifopts_lb, *ifopts_bt;
86         GList           *if_list, *combo_list;
87         int             err;
88         char            err_str[PCAP_ERRBUF_SIZE];
89     int         row = 0;
90     GtkTooltips *tooltips = gtk_tooltips_new();
91
92         /* Main vertical box */
93         main_vb = gtk_vbox_new(FALSE, 7);
94         gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
95
96         /* Main table */
97         main_tb = gtk_table_new(CAPTURE_TABLE_ROWS, 2, FALSE);
98         gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
99         gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
100         gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
101         gtk_widget_show(main_tb);
102
103         /* Default device */
104         if_lb = gtk_label_new("Default interface:");
105         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_lb, 0, 1, row, row+1);
106         gtk_misc_set_alignment(GTK_MISC(if_lb), 1.0, 0.5);
107         gtk_widget_show(if_lb);
108
109         if_cb = gtk_combo_new();
110         /*
111          * XXX - what if we can't get the list?
112          */
113         if_list = get_interface_list(&err, err_str);
114         combo_list = build_capture_combo_list(if_list, FALSE);
115         free_interface_list(if_list);
116         if (combo_list != NULL) {
117                 gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), combo_list);
118                 free_capture_combo_list(combo_list);
119         }
120         if (prefs.capture_device)
121                 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry),
122                     prefs.capture_device);
123         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_cb, 1, 2, row, row+1);
124     gtk_tooltips_set_tip(tooltips, GTK_COMBO(if_cb)->entry, 
125         "The default interface to be captured from.", NULL);
126         gtk_widget_show(if_cb);
127         OBJECT_SET_DATA(main_vb, DEVICE_KEY, if_cb);
128     row++;
129
130         /* Interface properties */
131         ifopts_lb = gtk_label_new("Interfaces:");
132         gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_lb, 0, 1, row, row+1);
133         gtk_misc_set_alignment(GTK_MISC(ifopts_lb), 1.0, 0.5);
134         gtk_widget_show(ifopts_lb);
135
136         ifopts_bt = BUTTON_NEW_FROM_STOCK(ETHEREAL_STOCK_EDIT);
137     gtk_tooltips_set_tip(tooltips, ifopts_bt, 
138         "Open a dialog box to set various interface options.", NULL);
139         SIGNAL_CONNECT(ifopts_bt, "clicked", ifopts_edit_cb, NULL);
140         gtk_table_attach_defaults(GTK_TABLE(main_tb), ifopts_bt, 1, 2, row, row+1);
141     row++;
142
143         /* Promiscuous mode */
144         promisc_cb = create_preference_check_button(main_tb, row++,
145             "Capture packets in promiscuous mode:", NULL,
146             prefs.capture_prom_mode);
147     gtk_tooltips_set_tip(tooltips, promisc_cb, 
148         "Usually a network card will only capture the traffic sent to its own network address. "
149         "If you want to capture all traffic that the network card can \"see\", mark this option. "
150         "See the FAQ for some more details of capturing packets from a switched network.", NULL);
151         OBJECT_SET_DATA(main_vb, PROM_MODE_KEY, promisc_cb);
152
153         /* Real-time capture */
154         sync_cb = create_preference_check_button(main_tb, row++,
155             "Update list of packets in real time:", NULL,
156             prefs.capture_real_time);
157     gtk_tooltips_set_tip(tooltips, sync_cb,
158         "Update the list of packets while capture is in progress. "
159         "Don't use this option if you notice packet drops.", NULL);
160         OBJECT_SET_DATA(main_vb, CAPTURE_REAL_TIME_KEY, sync_cb);
161
162         /* Auto-scroll real-time capture */
163         auto_scroll_cb = create_preference_check_button(main_tb, row++,
164             "Automatic scrolling in live capture:", NULL,
165             prefs.capture_auto_scroll);
166     gtk_tooltips_set_tip(tooltips, auto_scroll_cb,
167         "Automatic scrolling of the packet list while live capture is in progress. ", NULL);
168         OBJECT_SET_DATA(main_vb, AUTO_SCROLL_KEY, auto_scroll_cb);
169
170         /* Show capture info dialog */
171         show_info_cb = create_preference_check_button(main_tb, row++,
172             "Hide capture info dialog:", NULL,
173             !prefs.capture_show_info);
174     gtk_tooltips_set_tip(tooltips, show_info_cb,
175         "Hide the capture info dialog while capturing. "
176         "Will only take effect, if the \"Update list of packets in real time\" "
177         "option is also used.", NULL);
178         OBJECT_SET_DATA(main_vb, SHOW_INFO_KEY, show_info_cb);
179
180         /* Show 'em what we got */
181         gtk_widget_show_all(main_vb);
182
183         return(main_vb);
184 }
185
186 void
187 capture_prefs_fetch(GtkWidget *w)
188 {
189         GtkWidget *if_cb, *promisc_cb, *sync_cb, *auto_scroll_cb, *show_info_cb;
190         gchar   *if_text;
191
192         if_cb = (GtkWidget *)OBJECT_GET_DATA(w, DEVICE_KEY);
193         promisc_cb = (GtkWidget *)OBJECT_GET_DATA(w, PROM_MODE_KEY);
194         sync_cb = (GtkWidget *)OBJECT_GET_DATA(w, CAPTURE_REAL_TIME_KEY);
195         auto_scroll_cb = (GtkWidget *)OBJECT_GET_DATA(w, AUTO_SCROLL_KEY);
196     show_info_cb = (GtkWidget *)OBJECT_GET_DATA(w, SHOW_INFO_KEY);
197
198         if (prefs.capture_device != NULL) {
199                 g_free(prefs.capture_device);
200                 prefs.capture_device = NULL;
201         }
202         if_text = g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry)));
203         /* Strip out white space */
204         g_strstrip(if_text);
205         /* If there was nothing but white space, treat that as an
206            indication that the user doesn't want to wire in a default
207            device, and just wants the first device in the list chosen. */
208         if (*if_text == '\0') {
209                 g_free(if_text);
210                 if_text = NULL;
211         }
212         prefs.capture_device = if_text;
213
214         prefs.capture_prom_mode = GTK_TOGGLE_BUTTON (promisc_cb)->active;
215
216         prefs.capture_real_time = GTK_TOGGLE_BUTTON (sync_cb)->active;
217
218         prefs.capture_auto_scroll = GTK_TOGGLE_BUTTON (auto_scroll_cb)->active;
219
220     prefs.capture_show_info = !(GTK_TOGGLE_BUTTON (show_info_cb)->active);
221 }
222
223 void
224 capture_prefs_apply(GtkWidget *w _U_)
225 {
226 }
227
228 void
229 capture_prefs_destroy(GtkWidget *w)
230 {
231         GtkWidget *caller = gtk_widget_get_toplevel(w);
232         GtkWidget *dlg;
233
234         /* Is there an interface descriptions dialog associated with this
235            Preferences dialog? */
236         dlg = OBJECT_GET_DATA(caller, IFOPTS_DIALOG_PTR_KEY);
237
238         if (dlg != NULL) {
239                 /* Yes.  Destroy it. */
240                 window_destroy(dlg);
241         }
242 }
243
244 /*
245  * Create an edit interface options dialog.
246  */
247 static void
248 ifopts_edit_cb(GtkWidget *w, gpointer data _U_)
249 {
250         GtkWidget       *ifopts_edit_dlg, *cur_scr_win, *main_hb, *main_tb,
251                                 *cur_opts_fr, *ed_opts_fr, *main_vb,
252                                 *if_descr_lb, *if_hide_lb,
253                                 *bbox, *ok_bt, *cancel_bt;
254         const gchar *cur_titles[] = { "Device", "Description", "Comment", "Hide?" };
255         int row = 0;
256
257         GtkWidget *caller = gtk_widget_get_toplevel(w);
258         
259         /* Has an edit dialog box already been opened for that top-level
260            widget? */
261         ifopts_edit_dlg = OBJECT_GET_DATA(caller, IFOPTS_DIALOG_PTR_KEY);
262         if (ifopts_edit_dlg != NULL) {
263                 /* Yes.  Just re-activate that dialog box. */
264                 reactivate_window(ifopts_edit_dlg);
265                 return;
266         }
267         
268         /* create a new dialog */
269         ifopts_edit_dlg = dlg_window_new("Ethereal: Preferences: Interface Options");
270     gtk_window_set_default_size(GTK_WINDOW(ifopts_edit_dlg), DEF_WIDTH, 300);
271
272     main_vb = gtk_vbox_new(FALSE, 1);
273         gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
274         gtk_container_add(GTK_CONTAINER(ifopts_edit_dlg), main_vb);
275         gtk_widget_show(main_vb);
276         
277         /* create current options frame */
278         cur_opts_fr = gtk_frame_new("Interfaces");
279         gtk_container_add(GTK_CONTAINER(main_vb), cur_opts_fr);
280         gtk_widget_show(cur_opts_fr);
281         
282         /* create a scrolled window to pack the current options CList widget into */
283         cur_scr_win = scrolled_window_new(NULL, NULL);
284         gtk_container_border_width(GTK_CONTAINER(cur_scr_win), 3);
285         gtk_container_add(GTK_CONTAINER(cur_opts_fr), cur_scr_win);
286         gtk_widget_show(cur_scr_win);
287         
288         /*
289          * Create current options CList.
290          */
291         cur_clist = gtk_clist_new_with_titles(IFOPTS_CLIST_COLS, (gchar **) cur_titles);
292         gtk_clist_set_column_width(GTK_CLIST(cur_clist), 1, 230);
293         gtk_clist_set_column_width(GTK_CLIST(cur_clist), 2, 260);
294         gtk_clist_set_column_width(GTK_CLIST(cur_clist), 3, 40);
295         gtk_clist_column_titles_passive(GTK_CLIST(cur_clist));
296         gtk_container_add(GTK_CONTAINER(cur_scr_win), cur_clist);
297         SIGNAL_CONNECT(cur_clist, "select_row", ifopts_edit_ifsel_cb, NULL);
298         gtk_widget_show(cur_clist);
299         
300         /* add interface names to cell */
301         ifopts_if_clist_add();
302     gtk_clist_columns_autosize(GTK_CLIST(cur_clist));
303         
304         /* initialize variable that saves currently selected row in "if_clist" */
305         ifrow = IFOPTS_IF_NOSEL;
306         
307         /* create edit options frame */
308         ed_opts_fr = gtk_frame_new("Properties");
309         gtk_box_pack_start(GTK_BOX(main_vb), ed_opts_fr, FALSE, FALSE, 0);
310         gtk_widget_show(ed_opts_fr);
311         
312         main_hb = gtk_hbox_new(TRUE, 5);
313         gtk_container_border_width(GTK_CONTAINER(main_hb), 3);
314         gtk_container_add(GTK_CONTAINER(ed_opts_fr), main_hb);
315         gtk_widget_show(main_hb);
316                 
317         /* table to hold description text entry and hide button */
318         main_tb = gtk_table_new(IFOPTS_TABLE_ROWS, 4, FALSE);
319         gtk_box_pack_start(GTK_BOX(main_hb), main_tb, TRUE, FALSE, 10);
320         gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
321         gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
322         gtk_widget_show(main_tb);
323
324         if_dev_lb = gtk_label_new("Device:");
325         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 0, 1, row, row+1);
326         gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 1.0, 0.5);
327         gtk_widget_show(if_dev_lb);
328     
329         if_dev_lb = gtk_label_new("");
330         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 1, 2, row, row+1);
331         gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 0.0, 0.5);
332         gtk_widget_show(if_dev_lb);
333     row++;
334     
335         if_name_lb = gtk_label_new("Description:");
336         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 0, 1, row, row+1);
337         gtk_misc_set_alignment(GTK_MISC(if_name_lb), 1.0, 0.5);
338         gtk_widget_show(if_name_lb);
339     
340         if_name_lb = gtk_label_new("");
341         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 1, 2, row, row+1);
342         gtk_misc_set_alignment(GTK_MISC(if_name_lb), 0.0, 0.5);
343         gtk_widget_show(if_name_lb);
344     row++;
345     
346         /* create interface description label and text entry */
347         if_descr_lb = gtk_label_new("Comment:");
348         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_lb, 0, 1, row, row+1);
349         gtk_misc_set_alignment(GTK_MISC(if_descr_lb), 1.0, 0.5);
350         gtk_widget_show(if_descr_lb);
351         
352         if_descr_te = gtk_entry_new();
353         SIGNAL_CONNECT(if_descr_te, "changed", ifopts_edit_descr_changed_cb, 
354                         cur_clist);
355         gtk_entry_set_max_length(GTK_ENTRY(if_descr_te), IFOPTS_MAX_DESCR_LEN);
356         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_te, 1, 2, row, row+1);
357         gtk_widget_show(if_descr_te);
358     row++;
359         
360         /* create hide interface label and button */
361         if_hide_lb = gtk_label_new("Hide interface?:");
362         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_lb, 0, 1, row, row+1);
363         gtk_misc_set_alignment(GTK_MISC(if_hide_lb), 1.0, 0.5);
364         gtk_widget_show(if_hide_lb);
365         
366         if_hide_cb = gtk_check_button_new();
367         SIGNAL_CONNECT(if_hide_cb, "toggled", ifopts_edit_hide_changed_cb, 
368                         cur_clist);
369         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_cb, 1, 2, row, row+1);
370         gtk_widget_show(if_hide_cb);
371     row++;
372         
373         /* button row: OK and Cancel buttons */
374         bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
375         gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
376         gtk_widget_show(bbox);
377
378         ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
379         SIGNAL_CONNECT(ok_bt, "clicked", ifopts_edit_ok_cb, ifopts_edit_dlg);
380
381         cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
382     window_set_cancel_button(ifopts_edit_dlg, cancel_bt, window_cancel_button_cb);
383
384         gtk_widget_grab_default(ok_bt);
385
386     SIGNAL_CONNECT(ifopts_edit_dlg, "delete_event", window_delete_event_cb,
387                  NULL);
388         /* Call a handler when we're destroyed, so we can inform
389            our caller, if any, that we've been destroyed. */
390         SIGNAL_CONNECT(ifopts_edit_dlg, "destroy", ifopts_edit_destroy_cb, NULL);
391
392         /* Set the key for the new dialog to point to our caller. */
393         OBJECT_SET_DATA(ifopts_edit_dlg, IFOPTS_CALLER_PTR_KEY, caller);
394         /* Set the key for the caller to point to us */
395         OBJECT_SET_DATA(caller, IFOPTS_DIALOG_PTR_KEY, ifopts_edit_dlg);
396
397     /* select the first row in if list, all option fields must exist for this */
398         gtk_clist_select_row(GTK_CLIST(cur_clist), 0, -1);
399     
400         gtk_widget_show(ifopts_edit_dlg);
401     window_present(ifopts_edit_dlg);
402 }
403
404 /*
405  * User selected "OK". Create/write preferences strings.
406  */
407 static void
408 ifopts_edit_ok_cb(GtkWidget *w _U_, gpointer parent_w)
409 {
410         if (ifrow != IFOPTS_IF_NOSEL) {
411                 /* create/write new interfaces description string */
412                 ifopts_write_new_descr();
413                 
414                 /* create/write new "hidden" interfaces string */
415                 ifopts_write_new_hide();
416         }
417         
418         /* Now nuke this window. */
419         gtk_grab_remove(GTK_WIDGET(parent_w));
420         window_destroy(GTK_WIDGET(parent_w));
421 }
422
423 static void
424 ifopts_edit_destroy_cb(GtkWidget *win, gpointer data _U_)
425 {
426         GtkWidget *caller;
427
428         /* Get the widget that requested that we be popped up, if any.
429            (It should arrange to destroy us if it's destroyed, so
430            that we don't get a pointer to a non-existent window here.) */
431         caller = OBJECT_GET_DATA(win, IFOPTS_CALLER_PTR_KEY);
432
433         if (caller != NULL) {
434                 /* Tell it we no longer exist. */
435                 OBJECT_SET_DATA(caller, IFOPTS_DIALOG_PTR_KEY, NULL);
436         }
437 }
438
439 /*
440  * Interface selected callback; update displayed widgets.
441  */
442 static void
443 ifopts_edit_ifsel_cb(GtkWidget          *clist _U_,
444                                          gint                   row,
445                                          gint                   column _U_,
446                                          GdkEventButton *event _U_,
447                                          gpointer               data _U_)
448 {
449         gchar *text;
450         
451         /* save currently selected row */
452         ifrow = row;
453         
454         /* get/display the interface device from current CList */
455         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 0, &text);
456     /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */
457     text = strdup(text);
458         gtk_label_set_text(GTK_LABEL(if_dev_lb), text);
459     g_free(text);
460         
461         /* get/display the interface name from current CList */
462         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 1, &text);
463     /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */
464     text = strdup(text);
465         gtk_label_set_text(GTK_LABEL(if_name_lb), text);
466     g_free(text);
467         
468         /* get/display the interface description from current CList */
469         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 2, &text);
470     /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */
471     text = strdup(text);
472         gtk_entry_set_text(GTK_ENTRY(if_descr_te), text);
473     g_free(text);
474         
475         /* get/display the "hidden" button state from current CList */
476         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 3, &text);
477         if (strcmp("Yes", text) == 0)
478                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), TRUE);
479         else
480                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), FALSE);
481 }
482
483 /*
484  * Comment text entry changed callback; update current CList.
485  */
486 static void
487 ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata)
488 {
489         gchar *text;
490         
491         if (ifrow == IFOPTS_IF_NOSEL)
492                 return;
493         
494         /* get current description text and set value in current CList */
495         text = gtk_editable_get_chars(GTK_EDITABLE(ed), 0, -1);
496         /* replace any reserved formatting characters "()," with spaces */
497         g_strdelimit(text, "(),", ' ');
498         gtk_clist_set_text(GTK_CLIST(udata), ifrow, 2, text);
499         g_free(text);
500 }
501
502 /*
503  * Hide toggle button changed callback; update current CList.
504  */
505 static void
506 ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata)
507 {
508         if (ifrow == IFOPTS_IF_NOSEL)
509                 return;
510         
511         /* get "hidden" button state and set text in current CList */
512         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tbt)) == TRUE)
513                 gtk_clist_set_text(GTK_CLIST(udata), ifrow, 3, "Yes");
514         else
515                 gtk_clist_set_text(GTK_CLIST(udata), ifrow, 3, "No");
516 }
517
518 /*
519  * Add any saved options that apply to cells in current CList.
520  *
521  * NOTE:
522  *              Interfaces that have been removed from the machine or disabled and 
523  *              no longer apply are ignored. Therefore, if the user subsequently 
524  *              selects "OK", the options for these interfaces are lost (they're 
525  *              lost permanently if "Save" is selected).
526  */
527 static void
528 ifopts_options_add(GtkCList *clist, if_info_t *if_info)
529 {
530         gint    row;
531         gchar   *p;
532         gchar   *ifnm;
533         gchar   *desc;
534         gchar   *pr_descr;
535         gchar   *text[] = { NULL, NULL, NULL, NULL };
536         
537         /* add interface descriptions and "hidden" flag */
538         if (prefs.capture_devices_descr != NULL) {
539                 /* create working copy of device descriptions */
540                 pr_descr = g_strdup(prefs.capture_devices_descr);
541                 
542                 /* if we find a description for this interface */
543                 if ((ifnm = strstr(pr_descr, if_info->name)) != NULL) {
544                         p = ifnm;
545                         while (*p != '\0') {
546                                 /* found left parenthesis, start of description */
547                                 if (*p == '(') {
548                                         /* set device name text */
549                                         text[0] = g_strdup(if_info->name);
550                                         /* set OS description + device name text */
551                                         if (if_info->description != NULL)
552                                                 text[1] = g_strdup(if_info->description);
553                                         else
554                                                 text[1] = g_strdup("");
555                                         /* check if interface is "hidden" */
556                                         if (prefs.capture_devices_hide != NULL) {
557                                                 if (strstr(prefs.capture_devices_hide, if_info->name) != NULL)
558                                                         text[3] = g_strdup("Yes");
559                                                 else
560                                                         text[3] = g_strdup("No");
561                                         }
562                                         else
563                                                 text[3] = g_strdup("No");
564                                         p++;
565                                         /* if syntax error */
566                                         if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
567                                                 ifopts_options_free(text);
568                                                 break;
569                                         }
570                                         /* save pointer to beginning of description */
571                                         desc = p;
572                                         p++;
573                                         /* if syntax error */
574                                         if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
575                                                 ifopts_options_free(text);
576                                                 break;
577                                         }
578                                         /* skip to end of description */
579                                         while (*p != '\0') {
580                                                 /* end of description */
581                                                 if (*p == ')') {
582                                                         /* terminate and set description text */
583                                                         *p = '\0';
584                                                         text[2] = g_strdup(desc);
585                                                         /* add row to CList */
586                                                         row = gtk_clist_append(GTK_CLIST(clist), text);
587                                                         gtk_clist_set_selectable(GTK_CLIST(clist), row, 
588                                                                         FALSE);
589                                                         ifopts_options_free(text);
590                                                         break;
591                                                 }
592                                                 p++;
593                                         }
594                                         /* get out */
595                                         break;
596                                 }
597                                 else
598                                         p++;
599                         }
600                 }
601                 /* if there's no description for this interface */
602                 else {
603                         /* set device name text */
604                         text[0] = g_strdup(if_info->name);
605                         /* set OS description + device name text */
606                         if (if_info->description != NULL)
607                                 text[1] = g_strdup(if_info->description);
608                         else
609                                 text[1] = g_strdup("");
610                         /* set empty description */
611                         text[2] = g_strdup("");
612                         /* check if interface is "hidden" */
613                         if (prefs.capture_devices_hide != NULL) {
614                                 if (strstr(prefs.capture_devices_hide, if_info->name) != NULL)
615                                         text[3] = g_strdup("Yes");
616                                 else
617                                         text[3] = g_strdup("No");
618                         }
619                         else
620                                 text[3] = g_strdup("No");
621                         
622                         /* add row to CList */
623                         row = gtk_clist_append(GTK_CLIST(clist), text);
624                         gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
625                         ifopts_options_free(text);
626                 }
627                 
628                 g_free(pr_descr);
629         }
630         /*
631          * If we do not have any descriptions, but have "hidden" interfaces.
632          */
633         else if (prefs.capture_devices_hide != NULL) {
634                 /* set device name text */
635                 text[0] = g_strdup(if_info->name);
636                 /* set OS description + device name text */
637                 if (if_info->description != NULL)
638                         text[1] = g_strdup(if_info->description);
639                 else
640                         text[1] = g_strdup("");
641                 /* set empty description */
642                 text[2] = g_strdup("");
643                 /* check if interface is "hidden" */
644                 if (strstr(prefs.capture_devices_hide, if_info->name) != NULL)
645                         text[3] = g_strdup("Yes");
646                 else
647                         text[3] = g_strdup("No");
648                 
649                 /* add row to CList */
650                 row = gtk_clist_append(GTK_CLIST(clist), text);
651                 gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
652                 ifopts_options_free(text);
653         }
654         /*
655          * If we have no descriptions and no "hidden" interfaces.
656          */
657         else {
658                 /* set device name text */
659                 text[0] = g_strdup(if_info->name);
660                 /* set OS description + device name text */
661                 if (if_info->description != NULL)
662                         text[1] = g_strdup(if_info->description);
663                 else
664                         text[1] = g_strdup("");
665                 /* set empty description */
666                 text[2] = g_strdup("");
667                 /* interface is not "hidden" */
668                 text[3] = g_strdup("No");
669                 
670                 /* add row to CList */
671                 row = gtk_clist_append(GTK_CLIST(clist), text);
672                 gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
673                 ifopts_options_free(text);
674         }
675 }
676
677 static void
678 ifopts_options_free(gchar *text[])
679 {
680         gint i;
681         
682         for (i=0; i < IFOPTS_CLIST_COLS; i++) {
683                 if (text[i] != NULL) {
684                         g_free(text[i]);
685                         text[i] = NULL;
686                 }
687         }
688 }
689
690 /*
691  * Add all interfaces to interfaces CList.
692  */
693 static void
694 ifopts_if_clist_add(void)
695 {
696         GList           *if_list;
697         int             err;
698         char            err_str[PCAP_ERRBUF_SIZE];
699         gchar           *cant_get_if_list_errstr;
700         if_info_t       *if_info;
701         guint           i;
702         guint           nitems;
703         
704         if_list = get_interface_list(&err, err_str);
705         if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
706                 cant_get_if_list_errstr =
707                     cant_get_if_list_error_message(err_str);
708                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s",
709                     cant_get_if_list_errstr);
710                 g_free(cant_get_if_list_errstr);
711                 return;
712         }
713         
714         /* Seems we need to be at list head for g_list_length()? */
715         if_list = g_list_first(if_list);
716         nitems = g_list_length(if_list);
717         
718         /* add OS description + interface name text to CList */
719         for (i=0; i < nitems; i++) {
720                 if_info = g_list_nth_data(if_list, i);
721                 /* should never happen, but just in case */
722                 if (if_info == NULL)
723                         continue;
724
725         /* fill current options CList with current preference values */
726                 ifopts_options_add(GTK_CLIST(cur_clist), if_info);
727         }
728         
729         free_interface_list(if_list);
730 }
731
732 /*
733  * Create/write new interfaces description string based on current CList.
734  * Put it into the preferences value.
735  */
736 static void
737 ifopts_write_new_descr(void)
738 {
739         gint    i;
740         gboolean        first_if = TRUE;                                /* flag to check if first in list */
741         gchar   *ifnm;
742         gchar   *desc;
743         gchar   *tmp_descr;
744         gchar   *new_descr;
745         
746         /* new preferences interfaces description string */
747         new_descr = g_malloc0(MAX_VAL_LEN);
748         
749         /* get description for each row (interface) */
750         for (i = 0; ;i++) {
751                 /* get description */
752                 if (gtk_clist_get_text(GTK_CLIST(cur_clist), i, 2, &desc) != 1)
753                         break;
754                 /* if no description, skip this interface */
755                 if (strlen(desc) == 0)
756                         continue;
757                 
758                 /* get interface name */
759                 gtk_clist_get_text(GTK_CLIST(cur_clist), i, 0, &ifnm);
760
761                 /*
762                  * create/cat interface description to new string
763                  * (leave space for parens, comma and terminator)
764                  */
765                 if (first_if == TRUE)
766                         tmp_descr = g_strdup_printf("%s(%s)", ifnm, desc);
767                 else
768                         tmp_descr = g_strdup_printf(",%s(%s)", ifnm, desc);
769                 strcat(new_descr, tmp_descr);
770         g_free(tmp_descr);
771                 /* set first-in-list flag to false */
772                 first_if = FALSE;
773         }
774         
775         /* write new description string to preferences */
776         if (strlen(new_descr) > 0) {
777                 g_free(prefs.capture_devices_descr);
778                 prefs.capture_devices_descr = new_descr;
779         }
780         /* no descriptions */
781         else {
782                 g_free(prefs.capture_devices_descr);
783                 g_free(new_descr);
784                 prefs.capture_devices_descr = NULL;
785         }
786 }
787
788 /*
789  * Create/write new "hidden" interfaces string based on current CList.
790  * Put it into the preferences value.
791  */
792 static void
793 ifopts_write_new_hide(void)
794 {
795         gint    i;
796         gint    first_if = TRUE;                                /* flag to check if first in list */
797         gchar   *ifnm;
798         gchar   *hide;
799         gchar   *tmp_hide;
800         gchar   *new_hide;
801         
802         /* new preferences "hidden" interfaces string */
803         new_hide = g_malloc0(MAX_VAL_LEN);
804         
805         /* get "hidden" flag text for each row (interface) */
806         for (i = 0; ;i++) {
807                 /* get flag */
808                 if (gtk_clist_get_text(GTK_CLIST(cur_clist), i, 3, &hide) != 1)
809                         break;
810                 /* if flag text is "No", skip this interface */
811                 if (strcmp("No", hide) == 0)
812                         continue;
813
814         /* get interface name */
815                 gtk_clist_get_text(GTK_CLIST(cur_clist), i, 0, &ifnm);
816                 
817                 /*
818                  * create/cat interface to new string
819                  */
820                 if (first_if == TRUE)
821                         tmp_hide = g_strdup_printf("%s", ifnm);
822                 else
823                         tmp_hide = g_strdup_printf(",%s", ifnm);
824
825                 strcat(new_hide, tmp_hide);
826         g_free(tmp_hide);
827                 /* set first-in-list flag to false */
828                 first_if = FALSE;
829         }
830         
831         /* write new "hidden" string to preferences */
832         if (strlen(new_hide) > 0) {
833                 g_free(prefs.capture_devices_hide);
834                 prefs.capture_devices_hide = new_hide;
835         }
836         /* no "hidden" interfaces */
837         else {
838                 g_free(prefs.capture_devices_hide);
839                 g_free(new_hide);
840                 prefs.capture_devices_hide = NULL;
841         }
842 }
843
844 #endif /* HAVE_LIBPCAP */