Handle NAL-unit start code correctly.
[metze/wireshark/wip.git] / gtk / prefs_dlg.c
1 /* prefs_dlg.c
2  * Routines for handling 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 #include <gtk/gtk.h>
30
31 #include <string.h>
32
33 #include <epan/filesystem.h>
34 #include <epan/packet.h>
35 #include <epan/prefs.h>
36 #include <epan/strutil.h>
37 #include <epan/prefs-int.h>
38
39 #include "../file.h"
40 #include "../print.h"
41 #include "../simple_dialog.h"
42
43 #include "gtk/main.h"
44 #include "gtk/prefs_column.h"
45 #include "gtk/prefs_dlg.h"
46 #include "gtk/prefs_print.h"
47 #include "gtk/prefs_stream.h"
48 #include "gtk/prefs_gui.h"
49 #include "gtk/prefs_layout.h"
50 #include "gtk/prefs_capture.h"
51 #include "gtk/prefs_nameres.h"
52 #include "gtk/prefs_taps.h"
53 #include "gtk/prefs_protocols.h"
54 #include "gtk/gui_utils.h"
55 #include "gtk/dlg_utils.h"
56 #include "gtk/stock_icons.h"
57 #include "gtk/help_dlg.h"
58 #include "gtk/keys.h"
59 #include "gtk/uat_gui.h"
60
61
62 #ifdef HAVE_LIBPCAP
63 #ifdef _WIN32
64 #include "capture-wpcap.h"
65 #endif /* _WIN32 */
66 #ifdef HAVE_AIRPCAP
67 #include "airpcap.h"
68 #include "airpcap_loader.h"
69 #include "airpcap_gui_utils.h"
70 #endif
71 #endif
72
73
74 static void     prefs_main_ok_cb(GtkWidget *, gpointer);
75 static void     prefs_main_apply_cb(GtkWidget *, gpointer);
76 static void     prefs_main_save_cb(GtkWidget *, gpointer);
77 static void     prefs_main_cancel_cb(GtkWidget *, gpointer);
78 static gboolean prefs_main_delete_event_cb(GtkWidget *, GdkEvent *, gpointer);
79 static void     prefs_main_destroy_cb(GtkWidget *, gpointer);
80 static void     prefs_tree_select_cb(GtkTreeSelection *, gpointer);
81
82
83 #define E_PREFSW_SCROLLW_KEY    "prefsw_scrollw"
84 #define E_PREFSW_TREE_KEY       "prefsw_tree"
85 #define E_PREFSW_NOTEBOOK_KEY   "prefsw_notebook"
86 #define E_PREFSW_SAVE_BT_KEY    "prefsw_save_bt"
87 #define E_PAGE_ITER_KEY         "page_iter"
88 #define E_PAGE_MODULE_KEY       "page_module"
89 #define E_PAGESW_FRAME_KEY      "pagesw_frame"
90
91 #define E_GUI_PAGE_KEY          "gui_options_page"
92 #define E_GUI_LAYOUT_PAGE_KEY   "gui_layout_page"
93 #define E_GUI_COLUMN_PAGE_KEY   "gui_column_options_page"
94 #define E_GUI_FONT_PAGE_KEY     "gui_font_options_page"
95 #define E_GUI_COLORS_PAGE_KEY   "gui_colors_options_page"
96 #define E_CAPTURE_PAGE_KEY      "capture_options_page"
97 #define E_PRINT_PAGE_KEY        "printer_options_page"
98 #define E_NAMERES_PAGE_KEY      "nameres_options_page"
99 #define E_TAPS_PAGE_KEY         "taps_options_page"
100 #define E_PROTOCOLS_PAGE_KEY    "protocols_options_page"
101
102 /*
103  * Keep a static pointer to the current "Preferences" window, if any, so that
104  * if somebody tries to do "Edit:Preferences" while there's already a
105  * "Preferences" window up, we just pop up the existing one, rather than
106  * creating a new one.
107  */
108 static GtkWidget *prefs_w;
109
110 /*
111  * Save the value of the preferences as of when the preferences dialog
112  * box was first popped up, so we can revert to those values if the
113  * user selects "Cancel".
114  */
115 static e_prefs saved_prefs;
116
117 struct ct_struct {
118   GtkWidget    *main_vb;
119   GtkWidget    *notebook;
120   GtkWidget    *tree;
121   GtkTreeIter  iter;
122   GtkTooltips  *tooltips;
123   gint         page;
124   gboolean     is_protocol;
125 };
126
127 static gint protocols_page = 0;
128
129 static guint
130 pref_exists(pref_t *pref _U_, gpointer user_data _U_)
131 {
132   return 1;
133 }
134
135 /* show a single preference on the GtkTable of a preference page */
136 static guint
137 pref_show(pref_t *pref, gpointer user_data)
138 {
139   GtkWidget *main_tb = user_data;
140   const char *title;
141   char *label_string;
142   size_t label_len;
143   char uint_str[10+1];
144
145   /* Give this preference a label which is its title, followed by a colon,
146      and left-align it. */
147   title = pref->title;
148   label_len = strlen(title) + 2;
149   label_string = g_malloc(label_len);
150   g_strlcpy(label_string, title, label_len);
151
152   /*
153    * Sometimes we don't want to append a ':' after a static text string...
154    * If it is needed, we will specify it in the string itself.
155    */
156   if(pref->type != PREF_STATIC_TEXT)
157     g_strlcat(label_string, ":", label_len);
158
159   /* Save the current value of the preference, so that we can revert it if
160      the user does "Apply" and then "Cancel", and create the control for
161      editing the preference. */
162   switch (pref->type) {
163
164   case PREF_UINT:
165     pref->saved_val.uint = *pref->varp.uint;
166
167     /* XXX - there are no uint spinbuttons, so we can't use a spinbutton.
168        Even more annoyingly, even if there were, GLib doesn't define
169        G_MAXUINT - but I think ANSI C may define UINT_MAX, so we could
170        use that. */
171     switch (pref->info.base) {
172
173     case 10:
174       g_snprintf(uint_str, sizeof(uint_str), "%u", pref->saved_val.uint);
175       break;
176
177     case 8:
178       g_snprintf(uint_str, sizeof(uint_str), "%o", pref->saved_val.uint);
179       break;
180
181     case 16:
182       g_snprintf(uint_str, sizeof(uint_str), "%x", pref->saved_val.uint);
183       break;
184     }
185     pref->control = create_preference_entry(main_tb, pref->ordinal,
186                                             label_string, pref->description,
187                                             uint_str);
188     break;
189
190   case PREF_BOOL:
191     pref->saved_val.boolval = *pref->varp.boolp;
192     pref->control = create_preference_check_button(main_tb, pref->ordinal,
193                                                label_string, pref->description,
194                                                pref->saved_val.boolval);
195     break;
196
197   case PREF_ENUM:
198     pref->saved_val.enumval = *pref->varp.enump;
199     if (pref->info.enum_info.radio_buttons) {
200       /* Show it as radio buttons. */
201       pref->control = create_preference_radio_buttons(main_tb, pref->ordinal,
202                                                   label_string, pref->description,
203                                                   pref->info.enum_info.enumvals,
204                                                   pref->saved_val.enumval);
205     } else {
206       /* Show it as an option menu. */
207       pref->control = create_preference_option_menu(main_tb, pref->ordinal,
208                                          label_string, pref->description,
209                                          pref->info.enum_info.enumvals,
210                                          pref->saved_val.enumval);
211     }
212     break;
213
214   case PREF_STRING:
215     g_free(pref->saved_val.string);
216     pref->saved_val.string = g_strdup(*pref->varp.string);
217     pref->control = create_preference_entry(main_tb, pref->ordinal,
218                                             label_string, pref->description,
219                                             pref->saved_val.string);
220     break;
221
222   case PREF_RANGE:
223   {
224     char *range_string;
225
226     g_free(pref->saved_val.range);
227     pref->saved_val.range = range_copy(*pref->varp.range);
228     range_string = range_convert_range(*pref->varp.range);
229     pref->control = create_preference_entry(main_tb, pref->ordinal,
230                                             label_string, pref->description,
231                                             range_string);
232     break;
233   }
234
235   case PREF_STATIC_TEXT:
236   {
237     pref->control = create_preference_static_text(main_tb, pref->ordinal,
238                                             label_string, pref->description);
239     break;
240   }
241
242   case PREF_UAT:
243   {
244     pref->control = create_preference_uat(main_tb, pref->ordinal,
245                                           label_string, pref->description,
246                                                                                   pref->varp.uat);
247     break;
248   }
249           
250   case PREF_OBSOLETE:
251     g_assert_not_reached();
252     break;
253   }
254   g_free(label_string);
255
256   return 0;
257 }
258
259 #define MAX_TREE_NODE_NAME_LEN 64
260 /* show prefs page for each registered module (protocol) */
261 static guint
262 module_prefs_show(module_t *module, gpointer user_data)
263 {
264   struct ct_struct *cts = user_data;
265   struct ct_struct child_cts;
266   GtkWidget        *main_vb, *main_tb, *frame, *main_sw;
267   gchar            label_str[MAX_TREE_NODE_NAME_LEN];
268   GtkTreeStore     *model;
269   GtkTreeIter      iter;
270
271   /*
272    * Is this module a subtree, with modules underneath it?
273    */
274   if (!prefs_module_has_submodules(module)) {
275     /*
276      * No.
277      * Does it have any preferences (other than possibly obsolete ones)?
278      */
279     if (prefs_pref_foreach(module, pref_exists, NULL) == 0) {
280       /*
281        * No.  Don't put the module into the preferences window.
282        * XXX - we should do the same for subtrees; if a subtree has
283        * nothing under it that will be displayed, don't put it into
284        * the window.
285        */
286       return 0;
287     }
288   }
289
290   /*
291    * Add this module to the tree.
292    */
293   g_strlcpy(label_str, module->title, MAX_TREE_NODE_NAME_LEN);
294   model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(cts->tree)));
295   if (prefs_module_has_submodules(module) && !cts->iter.stamp)
296     gtk_tree_store_append(model, &iter, NULL);
297   else 
298     gtk_tree_store_append(model, &iter, &cts->iter);
299
300   /*
301    * Is this a subtree?
302    */
303   if (prefs_module_has_submodules(module)) {
304     /*
305      * Yes.
306      */
307
308     gtk_tree_store_set(model, &iter, 0, label_str, 1, -1, -1);
309
310     /*
311      * Walk the subtree and attach stuff to it.
312      */
313     child_cts = *cts;
314     child_cts.iter = iter;
315     if (module == protocols_module)
316       child_cts.is_protocol = TRUE;
317     prefs_modules_foreach_submodules(module, module_prefs_show, &child_cts);
318
319     /* keep the page count right */
320     cts->page = child_cts.page;
321
322   } 
323   if(module->prefs) {
324     /*
325      * Has preferences.  Create a notebook page for it.
326      */
327
328     /* Scrolled window */
329     main_sw = gtk_scrolled_window_new(NULL, NULL);
330     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(main_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
331
332     /* Frame */
333     frame = gtk_frame_new(module->description);
334     gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
335     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(main_sw), frame);
336     g_object_set_data(G_OBJECT(main_sw), E_PAGESW_FRAME_KEY, frame);
337
338     /* Main vertical box */
339     main_vb = gtk_vbox_new(FALSE, 5);
340     gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
341     gtk_container_add(GTK_CONTAINER(frame), main_vb);
342
343     /* Main table */
344     main_tb = gtk_table_new(module->numprefs, 2, FALSE);
345     gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
346     gtk_table_set_row_spacings(GTK_TABLE(main_tb), 10);
347     gtk_table_set_col_spacings(GTK_TABLE(main_tb), 15);
348     g_object_set_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY, cts->tooltips);
349
350     /* Add items for each of the preferences */
351     prefs_pref_foreach(module, pref_show, main_tb);
352
353     /* Associate this module with the page's frame. */
354     g_object_set_data(G_OBJECT(frame), E_PAGE_MODULE_KEY, module);
355
356     /* Add the page to the notebook */
357     gtk_notebook_append_page(GTK_NOTEBOOK(cts->notebook), main_sw, NULL);
358
359     /* Attach the page to the tree item */
360     gtk_tree_store_set(model, &iter, 0, label_str, 1, cts->page, -1);
361     g_object_set_data(G_OBJECT(frame), E_PAGE_ITER_KEY, gtk_tree_iter_copy(&iter));
362
363     cts->page++;
364
365     /* Show 'em what we got */
366     gtk_widget_show_all(main_sw);
367   } else {
368     /* show the protocols page */
369
370     gtk_tree_store_set(model, &iter, 0, label_str, 1, protocols_page, -1);  
371
372   }
373
374   return 0;
375 }
376
377
378 #define prefs_tree_iter GtkTreeIter
379
380 /* add a page to the tree */
381 static prefs_tree_iter
382 prefs_tree_page_add(const gchar *title, gint page_nr,
383                     gpointer store, prefs_tree_iter *parent_iter)
384 {
385   prefs_tree_iter   iter;
386
387   gtk_tree_store_append(store, &iter, parent_iter);
388   gtk_tree_store_set(store, &iter, 0, title, 1, page_nr, -1);
389   return iter;
390 }
391
392 /* add a page to the notebook */
393 static GtkWidget *
394 prefs_nb_page_add(GtkWidget *notebook, const gchar *title, GtkWidget *page, const char *page_key)
395 {
396   GtkWidget         *frame;
397
398   frame = gtk_frame_new(title);
399   gtk_widget_show(frame);
400   if(page) {
401     gtk_container_add(GTK_CONTAINER(frame), page);
402     g_object_set_data(G_OBJECT(prefs_w), page_key, page);
403   }
404   gtk_notebook_append_page (GTK_NOTEBOOK(notebook), frame, NULL);
405
406   return frame;
407 }
408
409
410 /* show the dialog */
411 void
412 prefs_cb(GtkWidget *w _U_, gpointer dummy _U_)
413 {
414   GtkWidget         *top_hb, *bbox, *prefs_nb, *ct_sb,
415                     *ok_bt, *apply_bt, *save_bt, *cancel_bt, *help_bt;
416   GtkWidget         *gui_font_pg;
417   gchar             label_str[MAX_TREE_NODE_NAME_LEN];
418   struct ct_struct  cts;
419   GtkTreeStore      *store;
420   GtkTreeSelection  *selection;
421   GtkCellRenderer   *renderer;
422   GtkTreeViewColumn *column;
423   gint              col_offset;
424   prefs_tree_iter   gui_iter;
425
426
427   if (prefs_w != NULL) {
428     /* There's already a "Preferences" dialog box; reactivate it. */
429     reactivate_window(prefs_w);
430     return;
431   }
432
433   /* Save the current preferences, so we can revert to those values
434      if the user presses "Cancel". */
435   copy_prefs(&saved_prefs, &prefs);
436
437   prefs_w = dlg_conf_window_new("Wireshark: Preferences");
438
439   /*
440    * Unfortunately, we can't arrange that a GtkTable widget wrap an event box
441    * around a table row, so the spacing between the preference item's label
442    * and its control widgets is inactive and the tooltip doesn't pop up when
443    * the mouse is over it.
444    */
445   cts.tooltips = gtk_tooltips_new();
446
447   /* Container for each row of widgets */
448   cts.main_vb = gtk_vbox_new(FALSE, 5);
449   gtk_container_set_border_width(GTK_CONTAINER(cts.main_vb), 5);
450   gtk_container_add(GTK_CONTAINER(prefs_w), cts.main_vb);
451   gtk_widget_show(cts.main_vb);
452
453   /* Top row: Preferences tree and notebook */
454   top_hb = gtk_hbox_new(FALSE, 10);
455   gtk_container_add(GTK_CONTAINER(cts.main_vb), top_hb);
456   gtk_widget_show(top_hb);
457
458   /* scrolled window on the left for the categories tree */
459   ct_sb = scrolled_window_new(NULL, NULL);
460   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ct_sb),
461                                    GTK_SHADOW_IN);
462   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ct_sb),
463         GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
464   gtk_container_add(GTK_CONTAINER(top_hb), ct_sb);
465   gtk_widget_show(ct_sb);
466   g_object_set_data(G_OBJECT(prefs_w), E_PREFSW_SCROLLW_KEY, ct_sb);
467
468   /* categories tree */
469   store = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
470   cts.tree = tree_view_new(GTK_TREE_MODEL(store));
471   cts.iter.stamp = 0; /* mark this as the toplevel */
472   g_object_set_data(G_OBJECT(prefs_w), E_PREFSW_TREE_KEY, cts.tree);
473   gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(cts.tree), FALSE);
474   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(cts.tree));
475   gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
476   renderer = gtk_cell_renderer_text_new();
477   col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(cts.tree),
478                                                            -1, "Name", renderer,
479                                                            "text", 0, NULL);
480   column = gtk_tree_view_get_column(GTK_TREE_VIEW(cts.tree),
481                                     col_offset - 1);
482   gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
483                                   GTK_TREE_VIEW_COLUMN_AUTOSIZE);
484   g_signal_connect(selection, "changed", G_CALLBACK(prefs_tree_select_cb), NULL);
485   gtk_container_add(GTK_CONTAINER(ct_sb), cts.tree);
486   gtk_widget_show(cts.tree);
487
488   /* A notebook widget without tabs is used to flip between prefs */
489   prefs_nb = gtk_notebook_new();
490   g_object_set_data(G_OBJECT(prefs_w), E_PREFSW_NOTEBOOK_KEY, prefs_nb);
491   gtk_notebook_set_show_tabs(GTK_NOTEBOOK(prefs_nb), FALSE);
492   gtk_notebook_set_show_border(GTK_NOTEBOOK(prefs_nb), FALSE);
493   gtk_container_add(GTK_CONTAINER(top_hb), prefs_nb);
494   gtk_widget_show(prefs_nb);
495
496   cts.page = 0;
497
498   /* Preferences common for all protocols */
499   g_strlcpy(label_str, "Protocols", MAX_TREE_NODE_NAME_LEN);
500   prefs_nb_page_add(prefs_nb, label_str, protocols_prefs_show(), E_PROTOCOLS_PAGE_KEY);
501   protocols_page = cts.page++;
502
503   /* GUI prefs */
504   g_strlcpy(label_str, "User Interface", MAX_TREE_NODE_NAME_LEN);
505   prefs_nb_page_add(prefs_nb, label_str, gui_prefs_show(), E_GUI_PAGE_KEY);
506   gui_iter = prefs_tree_page_add(label_str, cts.page, store, NULL);
507   cts.page++;
508
509   /* GUI layout prefs */
510   g_strlcpy(label_str, "Layout", MAX_TREE_NODE_NAME_LEN);
511   prefs_nb_page_add(prefs_nb, label_str, layout_prefs_show(), E_GUI_LAYOUT_PAGE_KEY);
512   prefs_tree_page_add(label_str, cts.page, store, &gui_iter);
513   cts.page++;
514
515   /* GUI Column prefs */
516   g_strlcpy(label_str, "Columns", MAX_TREE_NODE_NAME_LEN);
517   prefs_nb_page_add(prefs_nb, label_str, column_prefs_show(prefs_w), E_GUI_COLUMN_PAGE_KEY);
518   prefs_tree_page_add(label_str, cts.page, store, &gui_iter);
519   cts.page++;
520
521   /* GUI Font prefs */
522   g_strlcpy(label_str, "Font", MAX_TREE_NODE_NAME_LEN);
523   gui_font_pg = gui_font_prefs_show();
524   prefs_nb_page_add(prefs_nb, label_str, gui_font_pg, E_GUI_FONT_PAGE_KEY);
525   prefs_tree_page_add(label_str, cts.page, store, &gui_iter);
526   cts.page++;
527
528   gtk_container_set_border_width( GTK_CONTAINER(gui_font_pg), 5 );
529
530   /* IMPORTANT: the following gtk_font_selection_set_font_name() function will
531      only work if the widget and it's corresponding window is already shown
532      (so don't put the following into gui_font_prefs_show()) !!! */
533
534   /* We set the current font now, because setting it appears not to work 
535      when run before appending the frame to the notebook. */
536
537   gtk_font_selection_set_font_name(
538             GTK_FONT_SELECTION(gui_font_pg), prefs.gui_font_name);
539
540   /* GUI Colors prefs */
541   g_strlcpy(label_str, "Colors", MAX_TREE_NODE_NAME_LEN);
542   prefs_nb_page_add(prefs_nb, label_str, stream_prefs_show(), E_GUI_COLORS_PAGE_KEY);
543   prefs_tree_page_add(label_str, cts.page, store, &gui_iter);
544   cts.page++;
545
546   /* select the main GUI page as the default page and expand it's children */
547   gtk_tree_selection_select_iter(selection, &gui_iter);
548   /* (expand will only take effect, when at least one child exists) */
549   gtk_tree_view_expand_all(GTK_TREE_VIEW(cts.tree));
550
551 #ifdef HAVE_LIBPCAP
552 #ifdef _WIN32
553   /* Is WPcap loaded? */
554   if (has_wpcap) {
555 #endif /* _WIN32 */
556   /* capture prefs */
557   g_strlcpy(label_str, "Capture", MAX_TREE_NODE_NAME_LEN);
558   prefs_nb_page_add(prefs_nb, label_str, capture_prefs_show(), E_CAPTURE_PAGE_KEY);
559   prefs_tree_page_add(label_str, cts.page, store, NULL);
560   cts.page++;
561 #ifdef _WIN32
562   }
563 #endif /* _WIN32 */
564 #endif /* HAVE_LIBPCAP */
565
566   /* Printing prefs */
567   g_strlcpy(label_str, "Printing", MAX_TREE_NODE_NAME_LEN);
568   prefs_nb_page_add(prefs_nb, label_str, printer_prefs_show(), E_PRINT_PAGE_KEY);
569   prefs_tree_page_add(label_str, cts.page, store, NULL);
570   cts.page++;
571
572   /* Name resolution prefs */
573   g_strlcpy(label_str, "Name Resolution", MAX_TREE_NODE_NAME_LEN);
574   prefs_nb_page_add(prefs_nb, label_str, nameres_prefs_show(), E_NAMERES_PAGE_KEY);
575   prefs_tree_page_add(label_str, cts.page, store, NULL);
576   cts.page++;
577
578   /* TAPS player prefs */
579   g_strlcpy(label_str, "Statistics", MAX_TREE_NODE_NAME_LEN);
580   prefs_nb_page_add(prefs_nb, label_str, stats_prefs_show(), E_TAPS_PAGE_KEY);
581   prefs_tree_page_add(label_str, cts.page, store, NULL);
582   cts.page++;
583
584   /* Registered prefs */
585   cts.notebook = prefs_nb;
586   cts.is_protocol = FALSE;
587   prefs_modules_foreach_submodules(NULL, module_prefs_show, &cts);
588
589   /* Button row: OK and alike buttons */
590   bbox = dlg_button_row_new(GTK_STOCK_HELP, GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_SAVE, GTK_STOCK_CANCEL, NULL);
591   gtk_box_pack_start(GTK_BOX(cts.main_vb), bbox, FALSE, FALSE, 0);
592   gtk_widget_show(bbox);
593
594   ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
595   g_signal_connect(ok_bt, "clicked", G_CALLBACK(prefs_main_ok_cb), prefs_w);
596
597   apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
598   g_signal_connect(apply_bt, "clicked", G_CALLBACK(prefs_main_apply_cb), prefs_w);
599
600   save_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_SAVE);
601   g_signal_connect(save_bt, "clicked", G_CALLBACK(prefs_main_save_cb), prefs_w);
602   g_object_set_data(G_OBJECT(prefs_w), E_PREFSW_SAVE_BT_KEY, save_bt);
603
604   cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
605   g_signal_connect(cancel_bt, "clicked", G_CALLBACK(prefs_main_cancel_cb), prefs_w);
606   window_set_cancel_button(prefs_w, cancel_bt, NULL);
607
608   gtk_widget_grab_default(ok_bt);
609
610   help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
611   g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_PREFERENCES_DIALOG);
612
613   g_signal_connect(prefs_w, "delete_event", G_CALLBACK(prefs_main_delete_event_cb), prefs_w);
614   g_signal_connect(prefs_w, "destroy", G_CALLBACK(prefs_main_destroy_cb), prefs_w);
615
616   gtk_widget_show(prefs_w);
617
618   /* hide the Save button if the user uses implicit save */
619   if(!prefs.gui_use_pref_save) {
620     gtk_widget_hide(save_bt);
621   }
622
623   window_present(prefs_w);
624
625   g_object_unref(G_OBJECT(store));
626 }
627
628 static void
629 set_option_label(GtkWidget *main_tb, int table_position,
630     const gchar *label_text, const gchar *tooltip_text, GtkTooltips *tooltips)
631 {
632         GtkWidget *label;
633         GtkWidget *event_box;
634
635         label = gtk_label_new(label_text);
636         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
637         gtk_widget_show(label);
638
639         event_box = gtk_event_box_new();
640         gtk_event_box_set_visible_window (GTK_EVENT_BOX(event_box), FALSE);
641         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 0, 1,
642             table_position, table_position + 1);
643         if (tooltip_text != NULL && tooltips != NULL)
644                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
645         gtk_container_add(GTK_CONTAINER(event_box), label);
646         gtk_widget_show(event_box);
647 }
648
649 GtkWidget *
650 create_preference_check_button(GtkWidget *main_tb, int table_position,
651     const gchar *label_text, const gchar *tooltip_text, gboolean active)
652 {
653         GtkTooltips *tooltips;
654         GtkWidget *check_box;
655
656         tooltips = g_object_get_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY);
657
658         set_option_label(main_tb, table_position, label_text, tooltip_text,
659             tooltips);
660
661         check_box = gtk_check_button_new();
662         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box), active);
663         gtk_table_attach_defaults(GTK_TABLE(main_tb), check_box, 1, 2,
664             table_position, table_position + 1);
665         if (tooltip_text != NULL && tooltips != NULL)
666                 gtk_tooltips_set_tip(tooltips, check_box, tooltip_text, NULL);
667
668         return check_box;
669 }
670
671 GtkWidget *
672 create_preference_radio_buttons(GtkWidget *main_tb, int table_position,
673     const gchar *label_text, const gchar *tooltip_text,
674     const enum_val_t *enumvals, gint current_val)
675 {
676         GtkTooltips *tooltips;
677         GtkWidget *radio_button_hbox, *button = NULL;
678         GSList *rb_group;
679         int index;
680         const enum_val_t *enum_valp;
681         GtkWidget *event_box;
682
683         tooltips = g_object_get_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY);
684
685         set_option_label(main_tb, table_position, label_text, tooltip_text,
686             tooltips);
687
688         radio_button_hbox = gtk_hbox_new(FALSE, 0);
689         rb_group = NULL;
690         for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
691             enum_valp++, index++) {
692                 button = gtk_radio_button_new_with_label(rb_group,
693                     enum_valp->description);
694                 gtk_widget_show(button);
695                 rb_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
696                 gtk_box_pack_start(GTK_BOX(radio_button_hbox), button, FALSE,
697                     FALSE, 10);
698                 if (enum_valp->value == current_val) {
699                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button),
700                             TRUE);
701                 }
702         }
703         gtk_widget_show(radio_button_hbox);
704
705         event_box = gtk_event_box_new();
706         gtk_event_box_set_visible_window (GTK_EVENT_BOX(event_box), FALSE);
707         gtk_container_add(GTK_CONTAINER(event_box), radio_button_hbox);
708         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box, 1, 2,
709             table_position, table_position+1);
710         if (tooltip_text != NULL && tooltips != NULL)
711                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
712         gtk_widget_show(event_box);
713
714         /*
715          * It doesn't matter which of the buttons we return - we fetch
716          * the value by looking at the entire radio button group to
717          * which it belongs, and we can get that from any button.
718          */
719         return button;
720 }
721
722 static gint
723 label_to_enum_val(GtkWidget *label, const enum_val_t *enumvals)
724 {
725         char *label_string;
726         int i;
727
728         /* Get the label's text, and translate it to a value.
729            We match only the descriptions, as those are what appear in
730            the option menu items or as labels for radio buttons.
731            We fail if we don't find a match, as that "can't happen". */
732         gtk_label_get(GTK_LABEL(label), &label_string);
733
734         for (i = 0; enumvals[i].name != NULL; i++) {
735                 if (g_ascii_strcasecmp(label_string, enumvals[i].description) == 0) {
736                         return enumvals[i].value;
737                 }
738         }
739         g_assert_not_reached();
740         return -1;
741 }
742
743 gint
744 fetch_preference_radio_buttons_val(GtkWidget *button,
745     const enum_val_t *enumvals)
746 {
747         GSList *rb_group;
748         GSList *rb_entry;
749
750         /*
751          * Go through the list of of radio buttons in the button's group,
752          * and find the first one that's active.
753          */
754         rb_group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button));
755         button = NULL;
756         for (rb_entry = rb_group; rb_entry != NULL;
757             rb_entry = g_slist_next(rb_entry)) {
758                 button = rb_entry->data;
759                 if (GTK_TOGGLE_BUTTON(button)->active)
760                         break;
761         }
762
763         /* OK, now return the value corresponding to that button's label. */
764         return label_to_enum_val(GTK_BIN(button)->child, enumvals);
765 }
766
767 GtkWidget *
768 create_preference_option_menu(GtkWidget *main_tb, int table_position,
769     const gchar *label_text, const gchar *tooltip_text,
770     const enum_val_t *enumvals, gint current_val)
771 {
772         GtkTooltips *tooltips;
773         GtkWidget *menu_box, *menu, *menu_item, *option_menu;
774         int menu_index, index;
775         const enum_val_t *enum_valp;
776         GtkWidget *event_box;
777
778         tooltips = g_object_get_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY);
779
780         set_option_label(main_tb, table_position, label_text, tooltip_text,
781             tooltips);
782
783         /* Create a menu from the enumvals */
784         menu = gtk_menu_new();
785         if (tooltip_text != NULL && tooltips != NULL)
786                 gtk_tooltips_set_tip(tooltips, menu, tooltip_text, NULL);
787         menu_index = -1;
788         for (enum_valp = enumvals, index = 0; enum_valp->name != NULL;
789             enum_valp++, index++) {
790                 menu_item = gtk_menu_item_new_with_label(enum_valp->description);
791                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
792                 if (enum_valp->value == current_val)
793                         menu_index = index;
794                 gtk_widget_show(menu_item);
795         }
796
797         /* Create the option menu from the menu */
798         option_menu = gtk_option_menu_new();
799         gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu);
800
801         /* Set its current value to the variable's current value */
802         if (menu_index != -1)
803                 gtk_option_menu_set_history(GTK_OPTION_MENU(option_menu),
804                     menu_index);
805
806         /*
807          * Put the option menu in an hbox, so that it's only as wide
808          * as the widest entry, rather than being as wide as the table
809          * space.
810          */
811         menu_box = gtk_hbox_new(FALSE, 0);
812         gtk_box_pack_start(GTK_BOX(menu_box), option_menu, FALSE, FALSE, 0);
813
814         event_box = gtk_event_box_new();
815         gtk_event_box_set_visible_window (GTK_EVENT_BOX(event_box), FALSE);
816         gtk_table_attach_defaults(GTK_TABLE(main_tb), event_box,
817             1, 2, table_position, table_position + 1);
818         if (tooltip_text != NULL && tooltips != NULL)
819                 gtk_tooltips_set_tip(tooltips, event_box, tooltip_text, NULL);
820         gtk_container_add(GTK_CONTAINER(event_box), menu_box);
821
822         return option_menu;
823 }
824
825 gint
826 fetch_preference_option_menu_val(GtkWidget *optmenu, const enum_val_t *enumvals)
827 {
828         /*
829          * OK, now return the value corresponding to the label for the
830          * currently active entry in the option menu.
831          *
832          * Yes, this is how you get the label for that entry.  See FAQ
833          * 6.8 in the GTK+ FAQ.
834          */
835         return label_to_enum_val(GTK_BIN(optmenu)->child, enumvals);
836 }
837
838 GtkWidget *
839 create_preference_entry(GtkWidget *main_tb, int table_position,
840     const gchar *label_text, const gchar *tooltip_text, char *value)
841 {
842         GtkTooltips *tooltips;
843         GtkWidget *entry;
844
845         tooltips = g_object_get_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY);
846
847         set_option_label(main_tb, table_position, label_text, tooltip_text,
848             tooltips);
849
850         entry = gtk_entry_new();
851         if (value != NULL)
852                 gtk_entry_set_text(GTK_ENTRY(entry), value);
853         gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2,
854             table_position, table_position + 1);
855         if (tooltip_text != NULL && tooltips != NULL)
856                 gtk_tooltips_set_tip(tooltips, entry, tooltip_text, NULL);
857         gtk_widget_show(entry);
858
859         return entry;
860 }
861
862 GtkWidget *
863 create_preference_static_text(GtkWidget *main_tb, int table_position,
864     const gchar *label_text, const gchar *tooltip_text)
865 {
866         GtkTooltips *tooltips;
867         GtkWidget *label;
868
869         tooltips = g_object_get_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY);
870
871         if(label_text != NULL)
872                 label = gtk_label_new(label_text);
873         else
874                 label = gtk_label_new("");
875         gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 2,
876             table_position, table_position + 1);
877         if (tooltip_text != NULL && tooltips != NULL)
878                 gtk_tooltips_set_tip(tooltips, label, tooltip_text, NULL);
879         gtk_widget_show(label);
880
881         return label;
882 }
883
884 GtkWidget *
885 create_preference_uat(GtkWidget *main_tb, int table_position,
886     const gchar *label_text, const gchar *tooltip_text, void* uat)
887 {
888         GtkTooltips *tooltips;
889         GtkWidget *button = NULL;
890         
891         tooltips = g_object_get_data(G_OBJECT(main_tb), E_TOOLTIPS_KEY);
892         
893         set_option_label(main_tb, table_position, label_text, tooltip_text,
894                                          tooltips);
895         
896         button = gtk_button_new_from_stock(WIRESHARK_STOCK_EDIT);
897         
898         g_signal_connect(button, "clicked", G_CALLBACK(uat_window_cb), uat);
899
900         gtk_table_attach_defaults(GTK_TABLE(main_tb), button, 1, 2,
901                                                           table_position, table_position+1);
902         if (tooltip_text != NULL && tooltips != NULL)
903                 gtk_tooltips_set_tip(tooltips, button, tooltip_text, NULL);
904         gtk_widget_show(button);
905         
906         return button;
907 }
908
909
910 static guint
911 pref_check(pref_t *pref, gpointer user_data)
912 {
913   const char *str_val;
914   char *p;
915   guint uval;
916   pref_t **badpref = user_data;
917
918   /* Fetch the value of the preference, and check whether it's valid. */
919   switch (pref->type) {
920
921   case PREF_UINT:
922     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
923     uval = strtoul(str_val, &p, pref->info.base);
924     if (p == str_val || *p != '\0') {
925       *badpref = pref;
926       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
927     }
928     break;
929
930   case PREF_BOOL:
931     /* Value can't be bad. */
932     break;
933
934   case PREF_ENUM:
935     /* Value can't be bad. */
936     break;
937
938   case PREF_STRING:
939     /* Value can't be bad. */
940     break;
941
942   case PREF_RANGE:
943     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
944
945     if (strlen(str_val) != 0) {
946         range_t *newrange;
947
948         if (range_convert_str(&newrange, str_val, pref->info.max_value) !=
949             CVT_NO_ERROR) {
950             *badpref = pref;
951             return PREFS_SET_SYNTAX_ERR;        /* range was bad */
952         }
953         g_free(newrange);
954     }
955     break;
956
957   case PREF_STATIC_TEXT:
958   case PREF_UAT:
959     /* Value can't be bad. */
960     break;
961
962   case PREF_OBSOLETE:
963     g_assert_not_reached();
964     break;
965   }
966   return 0;
967 }
968
969 static guint
970 module_prefs_check(module_t *module, gpointer user_data)
971 {
972   /* For all preferences in this module, fetch its value from this
973      module's notebook page and check whether it's valid. */
974   return prefs_pref_foreach(module, pref_check, user_data);
975 }
976
977 static guint
978 pref_fetch(pref_t *pref, gpointer user_data)
979 {
980   const char *str_val;
981   char *p;
982   guint uval;
983   gboolean bval;
984   gint enumval;
985   gboolean *pref_changed_p = user_data;
986
987   /* Fetch the value of the preference, and set the appropriate variable
988      to it. */
989   switch (pref->type) {
990
991   case PREF_UINT:
992     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
993     uval = strtoul(str_val, &p, pref->info.base);
994 #if 0
995     if (p == value || *p != '\0')
996       return PREFS_SET_SYNTAX_ERR;      /* number was bad */
997 #endif
998     if (*pref->varp.uint != uval) {
999       *pref_changed_p = TRUE;
1000       *pref->varp.uint = uval;
1001     }
1002     break;
1003
1004   case PREF_BOOL:
1005     bval = GTK_TOGGLE_BUTTON(pref->control)->active;
1006     if (*pref->varp.boolp != bval) {
1007       *pref_changed_p = TRUE;
1008       *pref->varp.boolp = bval;
1009     }
1010     break;
1011
1012   case PREF_ENUM:
1013     if (pref->info.enum_info.radio_buttons) {
1014       enumval = fetch_preference_radio_buttons_val(pref->control,
1015           pref->info.enum_info.enumvals);
1016     } else {
1017       enumval = fetch_preference_option_menu_val(pref->control,
1018           pref->info.enum_info.enumvals);
1019     }
1020
1021     if (*pref->varp.enump != enumval) {
1022       *pref_changed_p = TRUE;
1023       *pref->varp.enump = enumval;
1024     }
1025     break;
1026
1027   case PREF_STRING:
1028     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
1029     if (strcmp(*pref->varp.string, str_val) != 0) {
1030       *pref_changed_p = TRUE;
1031       g_free((void *)*pref->varp.string);
1032       *pref->varp.string = g_strdup(str_val);
1033     }
1034     break;
1035
1036   case PREF_RANGE:
1037   {
1038     range_t *newrange;
1039     convert_ret_t ret;
1040
1041     str_val = gtk_entry_get_text(GTK_ENTRY(pref->control));
1042     ret = range_convert_str(&newrange, str_val, pref->info.max_value);
1043     if (ret != CVT_NO_ERROR)
1044 #if 0
1045       return PREFS_SET_SYNTAX_ERR;      /* range was bad */
1046 #else
1047       return 0; /* XXX - should fail */
1048 #endif
1049
1050     if (!ranges_are_equal(*pref->varp.range, newrange)) {
1051       *pref_changed_p = TRUE;
1052       g_free(*pref->varp.range);
1053       *pref->varp.range = newrange;
1054     } else
1055       g_free(newrange);
1056
1057     break;
1058   }
1059
1060   case PREF_STATIC_TEXT:
1061   case PREF_UAT:
1062     break;
1063
1064   case PREF_OBSOLETE:
1065     g_assert_not_reached();
1066     break;
1067   }
1068   return 0;
1069 }
1070
1071 static guint
1072 module_prefs_fetch(module_t *module, gpointer user_data)
1073 {
1074   gboolean *must_redissect_p = user_data;
1075
1076   /* For all preferences in this module, fetch its value from this
1077      module's notebook page.  Find out whether any of them changed. */
1078   module->prefs_changed = FALSE;        /* assume none of them changed */
1079   prefs_pref_foreach(module, pref_fetch, &module->prefs_changed);
1080
1081   /* If any of them changed, indicate that we must redissect and refilter
1082      the current capture (if we have one), as the preference change
1083      could cause packets to be dissected differently. */
1084   if (module->prefs_changed)
1085     *must_redissect_p = TRUE;
1086
1087   return 0;     /* keep fetching module preferences */
1088 }
1089
1090 #ifdef HAVE_AIRPCAP
1091 /*
1092  * This function is used to apply changes and update the Wireless Toolbar
1093  * whenever we apply some changes to the WEP preferences
1094  */
1095 static void
1096 prefs_airpcap_update()
1097 {
1098   GtkWidget *decryption_cm;
1099   GtkWidget *decryption_en;
1100   gboolean wireshark_decryption_was_enabled;
1101   gboolean airpcap_decryption_was_enabled;
1102   gboolean wireshark_decryption_is_now_enabled;
1103
1104   decryption_cm = GTK_WIDGET(g_object_get_data(G_OBJECT(airpcap_tb),AIRPCAP_TOOLBAR_DECRYPTION_KEY));
1105   decryption_en = GTK_WIDGET(GTK_ENTRY(GTK_COMBO(decryption_cm)->entry));
1106
1107   if( g_ascii_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK) == 0 )
1108   {
1109     wireshark_decryption_was_enabled = TRUE;
1110     airpcap_decryption_was_enabled = FALSE;
1111   }
1112   else if( g_ascii_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_AIRPCAP) == 0 )
1113   {
1114     wireshark_decryption_was_enabled = FALSE;
1115     airpcap_decryption_was_enabled = TRUE;
1116   }
1117   else if( g_ascii_strcasecmp(gtk_entry_get_text(GTK_ENTRY(decryption_en)),AIRPCAP_DECRYPTION_TYPE_STRING_NONE) == 0 )
1118   {
1119     wireshark_decryption_was_enabled = FALSE;
1120     airpcap_decryption_was_enabled = FALSE;
1121   }
1122
1123   wireshark_decryption_is_now_enabled = wireshark_decryption_on();
1124
1125   if(wireshark_decryption_is_now_enabled && airpcap_decryption_was_enabled)
1126   {
1127     set_airpcap_decryption(FALSE);
1128     gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK);
1129   }
1130   if(wireshark_decryption_is_now_enabled && !airpcap_decryption_was_enabled)
1131   {
1132     set_airpcap_decryption(FALSE);
1133     gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_WIRESHARK);
1134   }
1135   else if(!wireshark_decryption_is_now_enabled && wireshark_decryption_was_enabled)
1136   {
1137     if(airpcap_decryption_was_enabled)
1138     {
1139       set_airpcap_decryption(TRUE);
1140       gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_AIRPCAP);
1141     }
1142     else
1143     {
1144       set_airpcap_decryption(FALSE);
1145       gtk_entry_set_text(GTK_ENTRY(decryption_en),AIRPCAP_DECRYPTION_TYPE_STRING_NONE);
1146     }
1147   }
1148 }
1149 #endif
1150
1151 static guint
1152 pref_clean(pref_t *pref, gpointer user_data _U_)
1153 {
1154   switch (pref->type) {
1155
1156   case PREF_UINT:
1157     break;
1158
1159   case PREF_BOOL:
1160     break;
1161
1162   case PREF_ENUM:
1163     break;
1164
1165   case PREF_STRING:
1166     if (pref->saved_val.string != NULL) {
1167       g_free(pref->saved_val.string);
1168       pref->saved_val.string = NULL;
1169     }
1170     break;
1171
1172   case PREF_RANGE:
1173     if (pref->saved_val.range != NULL) {
1174       g_free(pref->saved_val.range);
1175       pref->saved_val.range = NULL;
1176     }
1177     break;
1178
1179   case PREF_STATIC_TEXT:
1180   case PREF_UAT:
1181     break;
1182
1183   case PREF_OBSOLETE:
1184     g_assert_not_reached();
1185     break;
1186   }
1187   return 0;
1188 }
1189
1190 static guint
1191 module_prefs_clean(module_t *module, gpointer user_data _U_)
1192 {
1193   /* For all preferences in this module, clean up any cruft allocated for
1194      use by the GUI code. */
1195   prefs_pref_foreach(module, pref_clean, NULL);
1196   return 0;     /* keep cleaning modules */
1197 }
1198
1199 /* fetch all pref values from all pages */
1200 static gboolean
1201 prefs_main_fetch_all(GtkWidget *dlg, gboolean *must_redissect)
1202 {
1203   pref_t *badpref;
1204
1205   /* First, check that the values are all valid. */
1206   /* XXX - check the non-registered preferences too */
1207   switch (prefs_modules_foreach(module_prefs_check, (gpointer)&badpref)) {
1208
1209   case PREFS_SET_SYNTAX_ERR:
1210     switch (badpref->type) {
1211
1212     case PREF_UINT:
1213       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1214                     "The value for \"%s\" isn't a valid number.",
1215                     badpref->title);
1216       return FALSE;
1217
1218     case PREF_RANGE:
1219       simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1220                     "The value for \"%s\" isn't a valid range.",
1221                     badpref->title);
1222       return FALSE;
1223
1224     default:
1225       g_assert_not_reached();
1226       break;
1227     }
1228   }
1229
1230   /* Fetch the preferences (i.e., make sure all the values set in all of
1231      the preferences panes have been copied to "prefs" and the registered
1232      preferences). */
1233   gui_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_GUI_PAGE_KEY));
1234   layout_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_GUI_LAYOUT_PAGE_KEY));
1235   column_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_GUI_COLUMN_PAGE_KEY));
1236   stream_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_GUI_COLORS_PAGE_KEY));
1237
1238 #ifdef HAVE_LIBPCAP
1239 #ifdef _WIN32
1240   /* Is WPcap loaded? */
1241   if (has_wpcap) {
1242 #endif /* _WIN32 */
1243   capture_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_CAPTURE_PAGE_KEY));
1244 #ifdef _WIN32
1245   }
1246 #endif /* _WIN32 */
1247 #endif /* HAVE_LIBPCAP */
1248   printer_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_PRINT_PAGE_KEY));
1249   nameres_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_NAMERES_PAGE_KEY));
1250   stats_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_TAPS_PAGE_KEY));
1251   protocols_prefs_fetch(g_object_get_data(G_OBJECT(dlg), E_PROTOCOLS_PAGE_KEY));
1252   prefs_modules_foreach(module_prefs_fetch, must_redissect);
1253
1254   return TRUE;
1255 }
1256
1257 /* apply all pref values to the real world */
1258 static void
1259 prefs_main_apply_all(GtkWidget *dlg, gboolean redissect)
1260 {
1261   GtkWidget *save_bt;
1262
1263   /*
1264    * Apply the protocol preferences first - "gui_prefs_apply()" could
1265    * cause redissection, and we have to make sure the protocol
1266    * preference changes have been fully applied.
1267    */
1268   prefs_apply_all();
1269
1270   gui_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_GUI_PAGE_KEY), redissect);
1271   layout_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_GUI_LAYOUT_PAGE_KEY));
1272   column_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_GUI_COLUMN_PAGE_KEY));
1273   stream_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_GUI_COLORS_PAGE_KEY));
1274
1275 #ifdef HAVE_LIBPCAP
1276 #ifdef _WIN32
1277   /* Is WPcap loaded? */
1278   if (has_wpcap) {
1279 #endif /* _WIN32 */
1280   capture_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_CAPTURE_PAGE_KEY));
1281 #ifdef _WIN32
1282   }
1283 #endif /* _WIN32 */
1284 #endif /* HAVE_LIBPCAP */
1285   printer_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_PRINT_PAGE_KEY));
1286   nameres_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_NAMERES_PAGE_KEY));
1287   stats_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_TAPS_PAGE_KEY));
1288   protocols_prefs_apply(g_object_get_data(G_OBJECT(dlg), E_PROTOCOLS_PAGE_KEY));
1289
1290   /* show/hide the Save button - depending on setting */
1291   save_bt = g_object_get_data(G_OBJECT(prefs_w), E_PREFSW_SAVE_BT_KEY);
1292   if(prefs.gui_use_pref_save) {
1293     gtk_widget_show(save_bt);
1294   } else {
1295     gtk_widget_hide(save_bt);
1296   }
1297 }
1298
1299
1300 /* destroy all preferences ressources from all pages */
1301 static void
1302 prefs_main_destroy_all(GtkWidget *dlg)
1303 {
1304   int page_num;
1305   GtkWidget *frame;
1306
1307   for (page_num = 0;
1308        (frame = gtk_notebook_get_nth_page(g_object_get_data(G_OBJECT(prefs_w), E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
1309        page_num++) {
1310            if(g_object_get_data(G_OBJECT(frame), E_PAGE_ITER_KEY))
1311                gtk_tree_iter_free(g_object_get_data(G_OBJECT(frame), E_PAGE_ITER_KEY));
1312            }
1313
1314   gui_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_GUI_PAGE_KEY));
1315   layout_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_GUI_LAYOUT_PAGE_KEY));
1316   column_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_GUI_COLUMN_PAGE_KEY));
1317   stream_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_GUI_COLORS_PAGE_KEY));
1318
1319 #ifdef HAVE_LIBPCAP
1320 #ifdef _WIN32
1321   /* Is WPcap loaded? */
1322   if (has_wpcap) {
1323 #endif /* _WIN32 */
1324   capture_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_CAPTURE_PAGE_KEY));
1325 #ifdef _WIN32
1326   }
1327 #endif /* _WIN32 */
1328 #endif /* HAVE_LIBPCAP */
1329   printer_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_PRINT_PAGE_KEY));
1330   nameres_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_NAMERES_PAGE_KEY));
1331   stats_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_TAPS_PAGE_KEY));
1332
1333   /* Free up the saved preferences (both for "prefs" and for registered
1334      preferences). */
1335   free_prefs(&saved_prefs);
1336   prefs_modules_foreach(module_prefs_clean, NULL);
1337   protocols_prefs_destroy(g_object_get_data(G_OBJECT(dlg), E_PROTOCOLS_PAGE_KEY));
1338 }
1339
1340
1341 void
1342 prefs_main_write(void)
1343 {
1344   int err;
1345   char *pf_dir_path;
1346   char *pf_path;
1347
1348   /* Create the directory that holds personal configuration files, if
1349      necessary.  */
1350   if (create_persconffile_dir(&pf_dir_path) == -1) {
1351      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1352       "Can't create directory\n\"%s\"\nfor preferences file: %s.", pf_dir_path,
1353       strerror(errno));
1354      g_free(pf_dir_path);
1355   } else {
1356     /* Write the preferencs out. */
1357     err = write_prefs(&pf_path);
1358     if (err != 0) {
1359        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1360         "Can't open preferences file\n\"%s\": %s.", pf_path,
1361         strerror(err));
1362        g_free(pf_path);
1363     }
1364   }
1365
1366 #ifdef HAVE_AIRPCAP
1367   /*
1368    * Load the Wireshark decryption keys (just set) and save
1369    * the changes to the adapters' registry
1370    */
1371   airpcap_load_decryption_keys(airpcap_if_list);
1372 #endif
1373 }
1374
1375
1376 static void
1377 prefs_main_ok_cb(GtkWidget *ok_bt _U_, gpointer parent_w)
1378 {
1379   gboolean must_redissect = FALSE;
1380
1381   if (!prefs_main_fetch_all(parent_w, &must_redissect))
1382     return; /* Errors in some preference setting - already reported */
1383
1384   /* if we don't have a Save button, just save the settings now */
1385   if (!prefs.gui_use_pref_save) {
1386       prefs_main_write();
1387   }
1388
1389   prefs_main_apply_all(parent_w, must_redissect);
1390
1391   /* Fill in capture options with values from the preferences */
1392   prefs_to_capture_opts();
1393
1394 #ifdef HAVE_AIRPCAP
1395   prefs_airpcap_update();
1396 #endif
1397
1398   /* Now destroy the "Preferences" dialog. */
1399   window_destroy(GTK_WIDGET(parent_w));
1400
1401   if (must_redissect) {
1402     /* Redissect all the packets, and re-evaluate the display filter. */
1403     cf_redissect_packets(&cfile);
1404   }
1405
1406 }
1407
1408 static void
1409 prefs_main_apply_cb(GtkWidget *apply_bt _U_, gpointer parent_w)
1410 {
1411   gboolean must_redissect = FALSE;
1412
1413   if (!prefs_main_fetch_all(parent_w, &must_redissect))
1414     return; /* Errors in some preference setting - already reported */
1415
1416   /* if we don't have a Save button, just save the settings now */
1417   if (!prefs.gui_use_pref_save) {
1418       prefs_main_write();
1419   }
1420
1421   prefs_main_apply_all(parent_w, must_redissect);
1422
1423   /* Fill in capture options with values from the preferences */
1424   prefs_to_capture_opts();
1425
1426 #ifdef HAVE_AIRPCAP
1427   prefs_airpcap_update();
1428 #endif
1429
1430   if (must_redissect) {
1431     /* Redissect all the packets, and re-evaluate the display filter. */
1432     cf_redissect_packets(&cfile);
1433   }
1434 }
1435
1436 static void
1437 prefs_main_save_cb(GtkWidget *save_bt _U_, gpointer parent_w)
1438 {
1439   gboolean must_redissect = FALSE;
1440
1441   if (!prefs_main_fetch_all(parent_w, &must_redissect))
1442     return; /* Errors in some preference setting - already reported */
1443
1444   prefs_main_write();
1445
1446   /* Now apply those preferences.
1447      XXX - should we do this?  The user didn't click "OK" or "Apply".
1448      However:
1449
1450         1) by saving the preferences they presumably indicate that they
1451            like them;
1452
1453         2) the next time they fire Wireshark up, those preferences will
1454            apply;
1455
1456         3) we'd have to buffer "must_redissect" so that if they do
1457            "Apply" after this, we know we have to redissect;
1458
1459         4) we did apply the protocol preferences, at least, in the past. */
1460   prefs_main_apply_all(parent_w, must_redissect);
1461
1462   /* Fill in capture options with values from the preferences */
1463   prefs_to_capture_opts();
1464
1465   if (must_redissect) {
1466     /* Redissect all the packets, and re-evaluate the display filter. */
1467     cf_redissect_packets(&cfile);
1468   }
1469 }
1470
1471 static guint
1472 pref_revert(pref_t *pref, gpointer user_data)
1473 {
1474   gboolean *pref_changed_p = user_data;
1475
1476   /* Revert the preference to its saved value. */
1477   switch (pref->type) {
1478
1479   case PREF_UINT:
1480     if (*pref->varp.uint != pref->saved_val.uint) {
1481       *pref_changed_p = TRUE;
1482       *pref->varp.uint = pref->saved_val.uint;
1483     }
1484     break;
1485
1486   case PREF_BOOL:
1487     if (*pref->varp.boolp != pref->saved_val.boolval) {
1488       *pref_changed_p = TRUE;
1489       *pref->varp.boolp = pref->saved_val.boolval;
1490     }
1491     break;
1492
1493   case PREF_ENUM:
1494     if (*pref->varp.enump != pref->saved_val.enumval) {
1495       *pref_changed_p = TRUE;
1496       *pref->varp.enump = pref->saved_val.enumval;
1497     }
1498     break;
1499
1500   case PREF_STRING:
1501     if (strcmp(*pref->varp.string, pref->saved_val.string) != 0) {
1502       *pref_changed_p = TRUE;
1503       g_free((void *)*pref->varp.string);
1504       *pref->varp.string = g_strdup(pref->saved_val.string);
1505     }
1506     break;
1507
1508   case PREF_RANGE:
1509     if (!ranges_are_equal(*pref->varp.range, pref->saved_val.range)) {
1510       *pref_changed_p = TRUE;
1511       g_free(*pref->varp.range);
1512       *pref->varp.range = range_copy(pref->saved_val.range);
1513     }
1514     break;
1515
1516   case PREF_STATIC_TEXT:
1517   case PREF_UAT:
1518     break;
1519
1520   case PREF_OBSOLETE:
1521     g_assert_not_reached();
1522     break;
1523   }
1524   return 0;
1525 }
1526
1527 static guint
1528 module_prefs_revert(module_t *module, gpointer user_data)
1529 {
1530   gboolean *must_redissect_p = user_data;
1531
1532   /* For all preferences in this module, revert its value to the value
1533      it had when we popped up the Preferences dialog.  Find out whether
1534      this changes any of them. */
1535   module->prefs_changed = FALSE;        /* assume none of them changed */
1536   prefs_pref_foreach(module, pref_revert, &module->prefs_changed);
1537
1538   /* If any of them changed, indicate that we must redissect and refilter
1539      the current capture (if we have one), as the preference change
1540      could cause packets to be dissected differently. */
1541   if (module->prefs_changed)
1542     *must_redissect_p = TRUE;
1543   return 0;     /* keep processing modules */
1544 }
1545
1546 /* cancel button pressed, revert prefs to saved and exit dialog */
1547 static void
1548 prefs_main_cancel_cb(GtkWidget *cancel_bt _U_, gpointer parent_w)
1549 {
1550   gboolean must_redissect = FALSE;
1551
1552   /* Free up the current preferences and copy the saved preferences to the
1553      current preferences. */
1554   free_prefs(&prefs);
1555   copy_prefs(&prefs, &saved_prefs);
1556
1557   /* Now revert the registered preferences. */
1558   prefs_modules_foreach(module_prefs_revert, &must_redissect);
1559
1560   /* Now apply the reverted-to preferences. */
1561   prefs_main_apply_all(parent_w, must_redissect);
1562
1563   window_destroy(GTK_WIDGET(parent_w));
1564
1565   if (must_redissect) {
1566     /* Redissect all the packets, and re-evaluate the display filter. */
1567     cf_redissect_packets(&cfile);
1568   }
1569 }
1570
1571 /* Treat this as a cancel, by calling "prefs_main_cancel_cb()" */
1572 static gboolean
1573 prefs_main_delete_event_cb(GtkWidget *prefs_w, GdkEvent *event _U_,
1574                            gpointer parent_w _U_)
1575 {
1576   prefs_main_cancel_cb(NULL, prefs_w);
1577   return FALSE;
1578 }
1579
1580
1581 /* dialog *is* already destroyed, clean up memory and such */
1582 static void
1583 prefs_main_destroy_cb(GtkWidget *win _U_, gpointer parent_w)
1584 {
1585   prefs_main_destroy_all(parent_w);
1586
1587   /* Note that we no longer have a "Preferences" dialog box. */
1588   prefs_w = NULL;
1589 }
1590
1591 struct properties_data {
1592   const char *title;
1593   module_t *module;
1594 };
1595
1596 static guint
1597 module_search_properties(module_t *module, gpointer user_data)
1598 {
1599   struct properties_data *p = (struct properties_data *)user_data;
1600
1601   /* If this module has the specified title, remember it. */
1602   if (strcmp(module->title, p->title) == 0) {
1603     p->module = module;
1604     return 1;   /* stops the search */
1605   }
1606   
1607   if(prefs_module_has_submodules(module))
1608     return prefs_modules_foreach_submodules(module, module_search_properties, p);
1609
1610   return 0;
1611 }
1612
1613 static void
1614 tree_expand_row(GtkTreeModel *model, GtkTreeView *tree_view, GtkTreeIter *iter)
1615 {
1616   GtkTreeIter   parent;
1617   GtkTreePath   *path;
1618
1619   /* expand the parent first */
1620   if(gtk_tree_model_iter_parent(model, &parent, iter))
1621     tree_expand_row(model, tree_view, &parent);
1622
1623   path = gtk_tree_model_get_path(model, iter);
1624   gtk_tree_view_expand_row(tree_view, path, FALSE);
1625   /*expand_tree(tree_view, &parent, NULL, NULL);*/
1626
1627   gtk_tree_path_free(path);
1628 }
1629
1630 /* select a node in the tree view */
1631 /* XXX - this is almost 100% copied from byte_view_select() in proto_draw.c,
1632  *       find a way to combine both to have a generic function for this */
1633 void
1634 tree_select_node(GtkWidget *tree, prefs_tree_iter *iter)
1635 {
1636     GtkTreeIter  local_iter = *iter;
1637     GtkTreeView  *tree_view = GTK_TREE_VIEW(tree);
1638     GtkTreeModel *model;
1639     GtkTreePath  *first_path;
1640
1641     model = gtk_tree_view_get_model(tree_view);
1642
1643     /* Expand our field's row */
1644     first_path = gtk_tree_model_get_path(model, &local_iter);
1645
1646     /* expand from the top down */
1647     tree_expand_row(model, tree_view, &local_iter);
1648
1649     /* select our field's row */
1650     gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree_view),
1651                                    first_path);
1652
1653     /* And position the window so the selection is visible.
1654      * Position the selection in the middle of the viewable
1655      * pane. */
1656     gtk_tree_view_scroll_to_cell(tree_view, first_path, NULL, TRUE, 0.5, 0.0);
1657
1658     gtk_tree_path_free(first_path);
1659 }
1660
1661
1662 /* search the corresponding protocol page of the currently selected field */
1663 void
1664 properties_cb(GtkWidget *w, gpointer dummy)
1665 {
1666   header_field_info *hfinfo;
1667   const gchar *title;
1668   struct properties_data p;
1669   int page_num;
1670   GtkWidget *sw;
1671   GtkWidget *frame;
1672   module_t *page_module;
1673
1674   if (cfile.finfo_selected == NULL) {
1675     /* There is no field selected */
1676     return;
1677   }
1678
1679   /* Find the title for the protocol for the selected field. */
1680   hfinfo = cfile.finfo_selected->hfinfo;
1681   if (hfinfo->parent == -1)
1682     title = prefs_get_title_by_name(hfinfo->abbrev);
1683   else
1684     title = prefs_get_title_by_name(proto_registrar_get_abbrev(hfinfo->parent));
1685   if (!title)
1686     return;     /* Couldn't find it. XXX - just crash? "Can't happen"? */
1687
1688   /* Find the module for that protocol by searching for one with that title.
1689      XXX - should we just associate protocols with modules directly? */
1690   p.title = title;
1691   p.module = NULL;
1692   prefs_modules_foreach_submodules(protocols_module, module_search_properties,
1693                             &p);
1694   if (p.module == NULL) {
1695     /* We didn't find it - that protocol probably has no preferences. */
1696     return;
1697   }
1698
1699   /* Create a preferences window, or pop up an existing one. */
1700   if (prefs_w != NULL) {
1701     reactivate_window(prefs_w);
1702   } else {
1703     prefs_cb(w, dummy);
1704   }
1705
1706   /* Search all the pages in that window for the one with the specified
1707      module. */
1708   for (page_num = 0;
1709        (sw = gtk_notebook_get_nth_page(g_object_get_data(G_OBJECT(prefs_w), E_PREFSW_NOTEBOOK_KEY), page_num)) != NULL;
1710        page_num++) {
1711     /* Get the frame from the scrollable window */
1712     frame = g_object_get_data(G_OBJECT(sw), E_PAGESW_FRAME_KEY);
1713     /* Get the module for this page (non-protocol prefs don't have one). */
1714     if(frame) {
1715       page_module = g_object_get_data(G_OBJECT(frame), E_PAGE_MODULE_KEY);
1716       if (page_module != NULL) {
1717         if (page_module == p.module) {
1718           tree_select_node(
1719                   g_object_get_data(G_OBJECT(prefs_w), E_PREFSW_TREE_KEY),
1720                   g_object_get_data(G_OBJECT(frame), E_PAGE_ITER_KEY));
1721           return;
1722         }
1723       }
1724     }
1725   }
1726 }
1727
1728 /* Prefs tree selection callback.  The node data has been loaded with
1729    the proper notebook page to load. */
1730 static void
1731 prefs_tree_select_cb(GtkTreeSelection *sel, gpointer dummy _U_)
1732 {
1733   gint page;
1734   GtkTreeModel *model;
1735   GtkTreeIter   iter;
1736
1737   if (gtk_tree_selection_get_selected(sel, &model, &iter))
1738   {
1739     gtk_tree_model_get(model, &iter, 1, &page, -1);
1740     if (page >= 0)
1741         gtk_notebook_set_current_page(g_object_get_data(G_OBJECT(prefs_w), E_PREFSW_NOTEBOOK_KEY), page);
1742   }
1743 }