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