Move prefs.c and prefs.h into the epan subdirectory.
[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 "ui_util.h"
41 #include "dlg_utils.h"
42 #include "simple_dialog.h"
43 #include "pcap-util.h"
44 #include "capture_combo_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         gchar *cur_titles[] = { "Device", "Description", 
255                                                                                                 "Comment", "Hide?" };
256     int row = 0;
257
258         GtkWidget *caller = gtk_widget_get_toplevel(w);
259         
260         /* Has an edit dialog box already been opened for that top-level
261            widget? */
262         ifopts_edit_dlg = OBJECT_GET_DATA(caller, IFOPTS_DIALOG_PTR_KEY);
263         if (ifopts_edit_dlg != NULL) {
264                 /* Yes.  Just re-activate that dialog box. */
265                 reactivate_window(ifopts_edit_dlg);
266                 return;
267         }
268         
269         /* create a new dialog */
270         ifopts_edit_dlg = dlg_window_new("Ethereal: Preferences: Interface Options");
271     gtk_window_set_default_size(GTK_WINDOW(ifopts_edit_dlg), DEF_WIDTH, 300);
272
273     main_vb = gtk_vbox_new(FALSE, 1);
274         gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
275         gtk_container_add(GTK_CONTAINER(ifopts_edit_dlg), main_vb);
276         gtk_widget_show(main_vb);
277         
278         /* create current options frame */
279         cur_opts_fr = gtk_frame_new("Interfaces");
280         gtk_container_add(GTK_CONTAINER(main_vb), cur_opts_fr);
281         gtk_widget_show(cur_opts_fr);
282         
283         /* create a scrolled window to pack the current options CList widget into */
284         cur_scr_win = scrolled_window_new(NULL, NULL);
285         gtk_container_border_width(GTK_CONTAINER(cur_scr_win), 3);
286         gtk_container_add(GTK_CONTAINER(cur_opts_fr), cur_scr_win);
287         gtk_widget_show(cur_scr_win);
288         
289         /*
290          * Create current options CList.
291          */
292         cur_clist = gtk_clist_new_with_titles(IFOPTS_CLIST_COLS, cur_titles);
293         gtk_clist_set_column_width(GTK_CLIST(cur_clist), 1, 230);
294         gtk_clist_set_column_width(GTK_CLIST(cur_clist), 2, 260);
295         gtk_clist_set_column_width(GTK_CLIST(cur_clist), 3, 40);
296         gtk_clist_column_titles_passive(GTK_CLIST(cur_clist));
297         gtk_container_add(GTK_CONTAINER(cur_scr_win), cur_clist);
298         SIGNAL_CONNECT(cur_clist, "select_row", ifopts_edit_ifsel_cb, NULL);
299         gtk_widget_show(cur_clist);
300         
301         /* add interface names to cell */
302         ifopts_if_clist_add();
303     gtk_clist_columns_autosize(GTK_CLIST(cur_clist));
304         
305         /* initialize variable that saves currently selected row in "if_clist" */
306         ifrow = IFOPTS_IF_NOSEL;
307         
308         /* create edit options frame */
309         ed_opts_fr = gtk_frame_new("Properties");
310         gtk_box_pack_start(GTK_BOX(main_vb), ed_opts_fr, FALSE, FALSE, 0);
311         gtk_widget_show(ed_opts_fr);
312         
313         main_hb = gtk_hbox_new(TRUE, 5);
314         gtk_container_border_width(GTK_CONTAINER(main_hb), 3);
315         gtk_container_add(GTK_CONTAINER(ed_opts_fr), main_hb);
316         gtk_widget_show(main_hb);
317                 
318         /* table to hold description text entry and hide button */
319         main_tb = gtk_table_new(IFOPTS_TABLE_ROWS, 4, FALSE);
320         gtk_box_pack_start(GTK_BOX(main_hb), main_tb, TRUE, FALSE, 10);
321         gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
322         gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
323         gtk_widget_show(main_tb);
324
325         if_dev_lb = gtk_label_new("Device:");
326         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 0, 1, row, row+1);
327         gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 1.0, 0.5);
328         gtk_widget_show(if_dev_lb);
329     
330         if_dev_lb = gtk_label_new("");
331         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_dev_lb, 1, 2, row, row+1);
332         gtk_misc_set_alignment(GTK_MISC(if_dev_lb), 0.0, 0.5);
333         gtk_widget_show(if_dev_lb);
334     row++;
335     
336         if_name_lb = gtk_label_new("Description:");
337         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 0, 1, row, row+1);
338         gtk_misc_set_alignment(GTK_MISC(if_name_lb), 1.0, 0.5);
339         gtk_widget_show(if_name_lb);
340     
341         if_name_lb = gtk_label_new("");
342         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_name_lb, 1, 2, row, row+1);
343         gtk_misc_set_alignment(GTK_MISC(if_name_lb), 0.0, 0.5);
344         gtk_widget_show(if_name_lb);
345     row++;
346     
347         /* create interface description label and text entry */
348         if_descr_lb = gtk_label_new("Comment:");
349         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_lb, 0, 1, row, row+1);
350         gtk_misc_set_alignment(GTK_MISC(if_descr_lb), 1.0, 0.5);
351         gtk_widget_show(if_descr_lb);
352         
353         if_descr_te = gtk_entry_new();
354         SIGNAL_CONNECT(if_descr_te, "changed", ifopts_edit_descr_changed_cb, 
355                         cur_clist);
356         gtk_entry_set_max_length(GTK_ENTRY(if_descr_te), IFOPTS_MAX_DESCR_LEN);
357         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_descr_te, 1, 2, row, row+1);
358         gtk_widget_show(if_descr_te);
359     row++;
360         
361         /* create hide interface label and button */
362         if_hide_lb = gtk_label_new("Hide interface?:");
363         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_lb, 0, 1, row, row+1);
364         gtk_misc_set_alignment(GTK_MISC(if_hide_lb), 1.0, 0.5);
365         gtk_widget_show(if_hide_lb);
366         
367         if_hide_cb = gtk_check_button_new();
368         SIGNAL_CONNECT(if_hide_cb, "toggled", ifopts_edit_hide_changed_cb, 
369                         cur_clist);
370         gtk_table_attach_defaults(GTK_TABLE(main_tb), if_hide_cb, 1, 2, row, row+1);
371         gtk_widget_show(if_hide_cb);
372     row++;
373         
374         /* button row: OK and Cancel buttons */
375         bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_CANCEL, NULL);
376         gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
377         gtk_widget_show(bbox);
378
379         ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
380         SIGNAL_CONNECT(ok_bt, "clicked", ifopts_edit_ok_cb, ifopts_edit_dlg);
381
382         cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
383     window_set_cancel_button(ifopts_edit_dlg, cancel_bt, window_cancel_button_cb);
384
385         gtk_widget_grab_default(ok_bt);
386
387     SIGNAL_CONNECT(ifopts_edit_dlg, "delete_event", window_delete_event_cb,
388                  NULL);
389         /* Call a handler when we're destroyed, so we can inform
390            our caller, if any, that we've been destroyed. */
391         SIGNAL_CONNECT(ifopts_edit_dlg, "destroy", ifopts_edit_destroy_cb, NULL);
392
393         /* Set the key for the new dialog to point to our caller. */
394         OBJECT_SET_DATA(ifopts_edit_dlg, IFOPTS_CALLER_PTR_KEY, caller);
395         /* Set the key for the caller to point to us */
396         OBJECT_SET_DATA(caller, IFOPTS_DIALOG_PTR_KEY, ifopts_edit_dlg);
397
398     /* select the first row in if list, all option fields must exist for this */
399         gtk_clist_select_row(GTK_CLIST(cur_clist), 0, -1);
400     
401         gtk_widget_show(ifopts_edit_dlg);
402     window_present(ifopts_edit_dlg);
403 }
404
405 /*
406  * User selected "OK". Create/write preferences strings.
407  */
408 static void
409 ifopts_edit_ok_cb(GtkWidget *w _U_, gpointer parent_w)
410 {
411         if (ifrow != IFOPTS_IF_NOSEL) {
412                 /* create/write new interfaces description string */
413                 ifopts_write_new_descr();
414                 
415                 /* create/write new "hidden" interfaces string */
416                 ifopts_write_new_hide();
417         }
418         
419         /* Now nuke this window. */
420         gtk_grab_remove(GTK_WIDGET(parent_w));
421         window_destroy(GTK_WIDGET(parent_w));
422 }
423
424 static void
425 ifopts_edit_destroy_cb(GtkWidget *win, gpointer data _U_)
426 {
427         GtkWidget *caller;
428
429         /* Get the widget that requested that we be popped up, if any.
430            (It should arrange to destroy us if it's destroyed, so
431            that we don't get a pointer to a non-existent window here.) */
432         caller = OBJECT_GET_DATA(win, IFOPTS_CALLER_PTR_KEY);
433
434         if (caller != NULL) {
435                 /* Tell it we no longer exist. */
436                 OBJECT_SET_DATA(caller, IFOPTS_DIALOG_PTR_KEY, NULL);
437         }
438 }
439
440 /*
441  * Interface selected callback; update displayed widgets.
442  */
443 static void
444 ifopts_edit_ifsel_cb(GtkWidget          *clist _U_,
445                                          gint                   row,
446                                          gint                   column _U_,
447                                          GdkEventButton *event _U_,
448                                          gpointer               data _U_)
449 {
450         gchar *text;
451         
452         /* save currently selected row */
453         ifrow = row;
454         
455         /* get/display the interface device from current CList */
456         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 0, &text);
457     /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */
458     text = strdup(text);
459         gtk_label_set_text(GTK_LABEL(if_dev_lb), text);
460     g_free(text);
461         
462         /* get/display the interface name from current CList */
463         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 1, &text);
464     /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */
465     text = strdup(text);
466         gtk_label_set_text(GTK_LABEL(if_name_lb), text);
467     g_free(text);
468         
469         /* get/display the interface description from current CList */
470         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 2, &text);
471     /* is needed, as gtk_entry_set_text() will change text again (bug in GTK?) */
472     text = strdup(text);
473         gtk_entry_set_text(GTK_ENTRY(if_descr_te), text);
474     g_free(text);
475         
476         /* get/display the "hidden" button state from current CList */
477         gtk_clist_get_text(GTK_CLIST(cur_clist), row, 3, &text);
478         if (strcmp("Yes", text) == 0)
479                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), TRUE);
480         else
481                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(if_hide_cb), FALSE);
482 }
483
484 /*
485  * Comment text entry changed callback; update current CList.
486  */
487 static void
488 ifopts_edit_descr_changed_cb(GtkEditable *ed, gpointer udata)
489 {
490         gchar *text;
491         
492         if (ifrow == IFOPTS_IF_NOSEL)
493                 return;
494         
495         /* get current description text and set value in current CList */
496         text = gtk_editable_get_chars(GTK_EDITABLE(ed), 0, -1);
497         /* replace any reserved formatting characters "()," with spaces */
498         g_strdelimit(text, "(),", ' ');
499         gtk_clist_set_text(GTK_CLIST(udata), ifrow, 2, text);
500         g_free(text);
501 }
502
503 /*
504  * Hide toggle button changed callback; update current CList.
505  */
506 static void
507 ifopts_edit_hide_changed_cb(GtkToggleButton *tbt, gpointer udata)
508 {
509         if (ifrow == IFOPTS_IF_NOSEL)
510                 return;
511         
512         /* get "hidden" button state and set text in current CList */
513         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tbt)) == TRUE)
514                 gtk_clist_set_text(GTK_CLIST(udata), ifrow, 3, "Yes");
515         else
516                 gtk_clist_set_text(GTK_CLIST(udata), ifrow, 3, "No");
517 }
518
519 /*
520  * Add any saved options that apply to cells in current CList.
521  *
522  * NOTE:
523  *              Interfaces that have been removed from the machine or disabled and 
524  *              no longer apply are ignored. Therefore, if the user subsequently 
525  *              selects "OK", the options for these interfaces are lost (they're 
526  *              lost permanently if "Save" is selected).
527  */
528 static void
529 ifopts_options_add(GtkCList *clist, if_info_t *if_info)
530 {
531         gint    row;
532         gchar   *p;
533         gchar   *ifnm;
534         gchar   *desc;
535         gchar   *pr_descr;
536         gchar   *text[] = { NULL, NULL, NULL, NULL };
537         
538         /* add interface descriptions and "hidden" flag */
539         if (prefs.capture_devices_descr != NULL) {
540                 /* create working copy of device descriptions */
541                 pr_descr = g_strdup(prefs.capture_devices_descr);
542                 
543                 /* if we find a description for this interface */
544                 if ((ifnm = strstr(pr_descr, if_info->name)) != NULL) {
545                         p = ifnm;
546                         while (*p != '\0') {
547                                 /* found left parenthesis, start of description */
548                                 if (*p == '(') {
549                                         /* set device name text */
550                                         text[0] = g_strdup(if_info->name);
551                                         /* set OS description + device name text */
552                                         if (if_info->description != NULL)
553                                                 text[1] = g_strdup(if_info->description);
554                                         else
555                                                 text[1] = "";
556                                         /* check if interface is "hidden" */
557                                         if (prefs.capture_devices_hide != NULL) {
558                                                 if (strstr(prefs.capture_devices_hide, if_info->name) != NULL)
559                                                         text[3] = g_strdup("Yes");
560                                                 else
561                                                         text[3] = g_strdup("No");
562                                         }
563                                         else
564                                                 text[3] = g_strdup("No");
565                                         p++;
566                                         /* if syntax error */
567                                         if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
568                                                 ifopts_options_free(text);
569                                                 break;
570                                         }
571                                         /* save pointer to beginning of description */
572                                         desc = p;
573                                         p++;
574                                         /* if syntax error */
575                                         if ((*p == '\0') || (*p == ',') || (*p == '(') || (*p == ')')) {
576                                                 ifopts_options_free(text);
577                                                 break;
578                                         }
579                                         /* skip to end of description */
580                                         while (*p != '\0') {
581                                                 /* end of description */
582                                                 if (*p == ')') {
583                                                         /* terminate and set description text */
584                                                         *p = '\0';
585                                                         text[2] = g_strdup(desc);
586                                                         /* add row to CList */
587                                                         row = gtk_clist_append(GTK_CLIST(clist), text);
588                                                         gtk_clist_set_selectable(GTK_CLIST(clist), row, 
589                                                                         FALSE);
590                                                         ifopts_options_free(text);
591                                                         break;
592                                                 }
593                                                 p++;
594                                         }
595                                         /* get out */
596                                         break;
597                                 }
598                                 else
599                                         p++;
600                         }
601                 }
602                 /* if there's no description for this interface */
603                 else {
604                         /* set device name text */
605                         text[0] = g_strdup(if_info->name);
606                         /* set OS description + device name text */
607                         if (if_info->description != NULL)
608                                 text[1] = g_strdup(if_info->description);
609                         else
610                                 text[1] = "";
611                         /* set empty description */
612                         text[2] = g_strdup("");
613                         /* check if interface is "hidden" */
614                         if (prefs.capture_devices_hide != NULL) {
615                                 if (strstr(prefs.capture_devices_hide, if_info->name) != NULL)
616                                         text[3] = g_strdup("Yes");
617                                 else
618                                         text[3] = g_strdup("No");
619                         }
620                         else
621                                 text[3] = g_strdup("No");
622                         
623                         /* add row to CList */
624                         row = gtk_clist_append(GTK_CLIST(clist), text);
625                         gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
626                         ifopts_options_free(text);
627                 }
628                 
629                 g_free(pr_descr);
630         }
631         /*
632          * If we do not have any descriptions, but have "hidden" interfaces.
633          */
634         else if (prefs.capture_devices_hide != NULL) {
635                 /* set device name text */
636                 text[0] = g_strdup(if_info->name);
637                 /* set OS description + device name text */
638                 if (if_info->description != NULL)
639                         text[1] = g_strdup(if_info->description);
640                 else
641                         text[1] = g_strdup("");
642                 /* set empty description */
643                 text[2] = g_strdup("");
644                 /* check if interface is "hidden" */
645                 if (strstr(prefs.capture_devices_hide, if_info->name) != NULL)
646                         text[3] = g_strdup("Yes");
647                 else
648                         text[3] = g_strdup("No");
649                 
650                 /* add row to CList */
651                 row = gtk_clist_append(GTK_CLIST(clist), text);
652                 gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
653                 ifopts_options_free(text);
654         }
655         /*
656          * If we have no descriptions and no "hidden" interfaces.
657          */
658         else {
659                 /* set device name text */
660                 text[0] = g_strdup(if_info->name);
661                 /* set OS description + device name text */
662                 if (if_info->description != NULL)
663                         text[1] = g_strdup(if_info->description);
664                 else
665                         text[1] = g_strdup("");
666                 /* set empty description */
667                 text[2] = g_strdup("");
668                 /* interface is not "hidden" */
669                 text[3] = g_strdup("No");
670                 
671                 /* add row to CList */
672                 row = gtk_clist_append(GTK_CLIST(clist), text);
673                 gtk_clist_set_selectable(GTK_CLIST(clist), row, FALSE);
674                 ifopts_options_free(text);
675         }
676 }
677
678 static void
679 ifopts_options_free(gchar *text[])
680 {
681         gint i;
682         
683         for (i=0; i < IFOPTS_CLIST_COLS; i++) {
684                 if (text[i] != NULL) {
685                         g_free(text[i]);
686                         text[i] = NULL;
687                 }
688         }
689 }
690
691 /*
692  * Add all interfaces to interfaces CList.
693  */
694 static void
695 ifopts_if_clist_add(void)
696 {
697         GList           *if_list;
698         int             err;
699         char            err_str[PCAP_ERRBUF_SIZE];
700         gchar           *cant_get_if_list_errstr;
701         if_info_t       *if_info;
702         guint           i;
703         guint           nitems;
704         
705         if_list = get_interface_list(&err, err_str);
706         if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
707                 cant_get_if_list_errstr =
708                     cant_get_if_list_error_message(err_str);
709                 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s",
710                     cant_get_if_list_errstr);
711                 g_free(cant_get_if_list_errstr);
712                 return;
713         }
714         
715         /* Seems we need to be at list head for g_list_length()? */
716         if_list = g_list_first(if_list);
717         nitems = g_list_length(if_list);
718         
719         /* add OS description + interface name text to CList */
720         for (i=0; i < nitems; i++) {
721                 if_info = g_list_nth_data(if_list, i);
722                 /* should never happen, but just in case */
723                 if (if_info == NULL)
724                         continue;
725
726         /* fill current options CList with current preference values */
727                 ifopts_options_add(GTK_CLIST(cur_clist), if_info);
728         }
729         
730         free_interface_list(if_list);
731 }
732
733 /*
734  * Create/write new interfaces description string based on current CList.
735  * Put it into the preferences value.
736  */
737 static void
738 ifopts_write_new_descr(void)
739 {
740         gint    i;
741         gboolean        first_if = TRUE;                                /* flag to check if first in list */
742         gchar   *ifnm;
743         gchar   *desc;
744         gchar   *tmp_descr;
745         gchar   *new_descr;
746         
747         /* new preferences interfaces description string */
748         new_descr = g_malloc0(MAX_VAL_LEN);
749         
750         /* get description for each row (interface) */
751         for (i = 0; ;i++) {
752                 /* get description */
753                 if (gtk_clist_get_text(GTK_CLIST(cur_clist), i, 2, &desc) != 1)
754                         break;
755                 /* if no description, skip this interface */
756                 if (strlen(desc) == 0)
757                         continue;
758                 
759                 /* get interface name */
760                 gtk_clist_get_text(GTK_CLIST(cur_clist), i, 0, &ifnm);
761
762                 /*
763                  * create/cat interface description to new string
764                  * (leave space for parens, comma and terminator)
765                  */
766                 if (first_if == TRUE)
767                         tmp_descr = g_strdup_printf("%s(%s)", ifnm, desc);
768                 else
769                         tmp_descr = g_strdup_printf(",%s(%s)", ifnm, desc);
770                 strcat(new_descr, tmp_descr);
771         g_free(tmp_descr);
772                 /* set first-in-list flag to false */
773                 first_if = FALSE;
774         }
775         
776         /* write new description string to preferences */
777         if (strlen(new_descr) > 0) {
778                 g_free(prefs.capture_devices_descr);
779                 prefs.capture_devices_descr = new_descr;
780         }
781         /* no descriptions */
782         else {
783                 g_free(prefs.capture_devices_descr);
784                 g_free(new_descr);
785                 prefs.capture_devices_descr = NULL;
786         }
787 }
788
789 /*
790  * Create/write new "hidden" interfaces string based on current CList.
791  * Put it into the preferences value.
792  */
793 static void
794 ifopts_write_new_hide(void)
795 {
796         gint    i;
797         gint    first_if = TRUE;                                /* flag to check if first in list */
798         gchar   *ifnm;
799         gchar   *hide;
800         gchar   *tmp_hide;
801         gchar   *new_hide;
802         
803         /* new preferences "hidden" interfaces string */
804         new_hide = g_malloc0(MAX_VAL_LEN);
805         
806         /* get "hidden" flag text for each row (interface) */
807         for (i = 0; ;i++) {
808                 /* get flag */
809                 if (gtk_clist_get_text(GTK_CLIST(cur_clist), i, 3, &hide) != 1)
810                         break;
811                 /* if flag text is "No", skip this interface */
812                 if (strcmp("No", hide) == 0)
813                         continue;
814
815         /* get interface name */
816                 gtk_clist_get_text(GTK_CLIST(cur_clist), i, 0, &ifnm);
817                 
818                 /*
819                  * create/cat interface to new string
820                  */
821                 if (first_if == TRUE)
822                         tmp_hide = g_strdup_printf("%s", ifnm);
823                 else
824                         tmp_hide = g_strdup_printf(",%s", ifnm);
825
826                 strcat(new_hide, tmp_hide);
827         g_free(tmp_hide);
828                 /* set first-in-list flag to false */
829                 first_if = FALSE;
830         }
831         
832         /* write new "hidden" string to preferences */
833         if (strlen(new_hide) > 0) {
834                 g_free(prefs.capture_devices_hide);
835                 prefs.capture_devices_hide = new_hide;
836         }
837         /* no "hidden" interfaces */
838         else {
839                 g_free(prefs.capture_devices_hide);
840                 g_free(new_hide);
841                 prefs.capture_devices_hide = NULL;
842         }
843 }
844
845 #endif /* HAVE_LIBPCAP */