Catch attempts to pass unregistered protocols to prefs routines.
[metze/wireshark/wip.git] / epan / prefs.c
1 /* prefs.c
2  * Routines for handling preferences
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include <glib.h>
30
31 #include <stdio.h>
32 #include <wsutil/filesystem.h>
33 #include <epan/address.h>
34 #include <epan/addr_resolv.h>
35 #include <epan/oids.h>
36 #ifdef HAVE_GEOIP
37 #include <epan/geoip_db.h>
38 #endif
39 #include <epan/packet.h>
40 #include <epan/prefs.h>
41 #include <epan/proto.h>
42 #include <epan/strutil.h>
43 #include <epan/column.h>
44 #include <epan/decode_as.h>
45 #include "print.h"
46 #include <wsutil/file_util.h>
47 #include <wsutil/ws_printf.h> /* ws_g_warning */
48 #include <wsutil/report_message.h>
49
50 #include <epan/prefs-int.h>
51 #include <epan/uat-int.h>
52
53 #include "epan/filter_expressions.h"
54
55 #include "epan/wmem/wmem.h"
56 #include <epan/stats_tree.h>
57
58 /* Internal functions */
59 static module_t *find_subtree(module_t *parent, const char *tilte);
60 static module_t *prefs_register_module_or_subtree(module_t *parent,
61     const char *name, const char *title, const char *description, gboolean is_subtree,
62     void (*apply_cb)(void), gboolean use_gui);
63 static void prefs_register_modules(void);
64 static prefs_set_pref_e set_pref(gchar*, const gchar*, void *, gboolean);
65 static void free_col_info(GList *);
66 static void pre_init_prefs(void);
67 static gboolean prefs_is_column_visible(const gchar *cols_hidden, fmt_data *cfmt);
68 static gboolean parse_column_format(fmt_data *cfmt, const char *fmt);
69 static void try_convert_to_custom_column(gpointer *el_data);
70
71 #define IS_PREF_OBSOLETE(p) ((p) & PREF_OBSOLETE)
72 #define SET_PREF_OBSOLETE(p) ((p) |= PREF_OBSOLETE)
73 #define RESET_PREF_OBSOLETE(p) ((p) &= ~PREF_OBSOLETE)
74
75 #define PF_NAME         "preferences"
76 #define OLD_GPF_NAME    "wireshark.conf" /* old name for global preferences file */
77
78 static gboolean prefs_initialized = FALSE;
79 static gchar *gpf_path = NULL;
80 static gchar *cols_hidden_list = NULL;
81
82 /*
83  * XXX - variables to allow us to attempt to interpret the first
84  * "mgcp.{tcp,udp}.port" in a preferences file as
85  * "mgcp.{tcp,udp}.gateway_port" and the second as
86  * "mgcp.{tcp,udp}.callagent_port".
87  */
88 static int mgcp_tcp_port_count;
89 static int mgcp_udp_port_count;
90
91 e_prefs prefs;
92
93 static const enum_val_t gui_ptree_line_style[] = {
94     {"NONE", "NONE", 0},
95     {"SOLID", "SOLID", 1},
96     {"DOTTED", "DOTTED", 2},
97     {"TABBED", "TABBED", 3},
98     {NULL, NULL, -1}
99 };
100
101 static const enum_val_t gui_ptree_expander_style[] = {
102     {"NONE", "NONE", 0},
103     {"SQUARE", "SQUARE", 1},
104     {"TRIANGLE", "TRIANGLE", 2},
105     {"CIRCULAR", "CIRCULAR", 3},
106     {NULL, NULL, -1}
107 };
108
109 static const enum_val_t gui_hex_dump_highlight_style[] = {
110     {"BOLD", "BOLD", 0},
111     {"INVERSE", "INVERSE", 1},
112     {NULL, NULL, -1}
113 };
114
115 static const enum_val_t gui_console_open_type[] = {
116     {"NEVER", "NEVER", console_open_never},
117     {"AUTOMATIC", "AUTOMATIC", console_open_auto},
118     {"ALWAYS", "ALWAYS", console_open_always},
119     {NULL, NULL, -1}
120 };
121
122 static const enum_val_t gui_version_placement_type[] = {
123     {"WELCOME", "WELCOME", version_welcome_only},
124     {"TITLE", "TITLE", version_title_only},
125     {"BOTH", "BOTH", version_both},
126     {"NEITHER", "NEITHER", version_neither},
127     {NULL, NULL, -1}
128 };
129
130 static const enum_val_t gui_fileopen_style[] = {
131     {"LAST_OPENED", "LAST_OPENED", 0},
132     {"SPECIFIED", "SPECIFIED", 1},
133     {NULL, NULL, -1}
134 };
135
136 /* GTK knows of two ways representing "both", vertical and horizontal aligned.
137  * as this may not work on other guis, we use only "both" in general here */
138 static const enum_val_t gui_toolbar_style[] = {
139     {"ICONS", "ICONS", 0},
140     {"TEXT", "TEXT", 1},
141     {"BOTH", "BOTH", 2},
142     {NULL, NULL, -1}
143 };
144
145 static const enum_val_t gui_layout_content[] = {
146     {"NONE", "NONE", 0},
147     {"PLIST", "PLIST", 1},
148     {"PDETAILS", "PDETAILS", 2},
149     {"PBYTES", "PBYTES", 3},
150     {NULL, NULL, -1}
151 };
152
153 static const enum_val_t gui_update_channel[] = {
154     {"DEVELOPMENT", "DEVELOPMENT", UPDATE_CHANNEL_DEVELOPMENT},
155     {"STABLE", "STABLE", UPDATE_CHANNEL_STABLE},
156     {NULL, NULL, -1}
157 };
158
159 #if defined(HAVE_PCAP_CREATE)
160 /* Can set monitor mode and buffer size. */
161 static gint num_capture_cols = 7;
162 static const gchar *capture_cols[7] = {
163     "INTERFACE",
164     "LINK",
165     "PMODE",
166     "SNAPLEN",
167     "MONITOR",
168     "BUFFER",
169     "FILTER"
170 };
171 #define CAPTURE_COL_TYPE_DESCRIPTION \
172     "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n"
173 #elif defined(CAN_SET_CAPTURE_BUFFER_SIZE)
174 /* Can set buffer size but not monitor mode. */
175 static gint num_capture_cols = 6;
176 static const gchar *capture_cols[6] = {
177     "INTERFACE",
178     "LINK",
179     "PMODE",
180     "SNAPLEN",
181     "BUFFER",
182     "FILTER"
183 };
184 #define CAPTURE_COL_TYPE_DESCRIPTION \
185     "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, BUFFER, FILTER\n"
186 #else
187 /* Can neither set buffer size nor monitor mode. */
188 static gint num_capture_cols = 5;
189 static const gchar *capture_cols[5] = {
190     "INTERFACE",
191     "LINK",
192     "PMODE",
193     "SNAPLEN",
194     "FILTER"
195 };
196 #define CAPTURE_COL_TYPE_DESCRIPTION \
197     "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, FILTER\n"
198 #endif
199
200 static const enum_val_t gui_packet_list_elide_mode[] = {
201     {"LEFT", "LEFT", ELIDE_LEFT},
202     {"RIGHT", "RIGHT", ELIDE_RIGHT},
203     {"MIDDLE", "MIDDLE", ELIDE_MIDDLE},
204     {"NONE", "NONE", ELIDE_NONE},
205     {NULL, NULL, -1}
206 };
207
208 /** Struct to hold preference data */
209 struct preference {
210     const char *name;                /**< name of preference */
211     const char *title;               /**< title to use in GUI */
212     const char *description;         /**< human-readable description of preference */
213     int ordinal;                     /**< ordinal number of this preference */
214     int type;                        /**< type of that preference */
215     gui_type_t gui;                  /**< type of the GUI (QT, GTK or both) the preference is registered for */
216     union {                          /* The Qt preference code assumes that these will all be pointers (and unique) */
217         guint *uint;
218         gboolean *boolp;
219         gint *enump;
220         char **string;
221         range_t **range;
222         struct epan_uat* uat;
223         color_t *colorp;
224         GList** list;
225     } varp;                          /**< pointer to variable storing the value */
226     union {
227         guint uint;
228         gboolean boolval;
229         gint enumval;
230         char *string;
231         range_t *range;
232         color_t color;
233         GList* list;
234     } stashed_val;                     /**< original value, when editing from the GUI */
235     union {
236         guint uint;
237         gboolean boolval;
238         gint enumval;
239         char *string;
240         range_t *range;
241         color_t color;
242         GList* list;
243     } default_val;                   /**< the default value of the preference */
244     union {
245       guint base;                    /**< input/output base, for PREF_UINT */
246       guint32 max_value;             /**< maximum value of a range */
247       struct {
248         const enum_val_t *enumvals;  /**< list of name & values */
249         gboolean radio_buttons;      /**< TRUE if it should be shown as
250                                           radio buttons rather than as an
251                                           option menu or combo box in
252                                           the preferences tab */
253       } enum_info;                   /**< for PREF_ENUM */
254     } info;                          /**< display/text file information */
255     struct pref_custom_cbs custom_cbs;   /**< for PREF_CUSTOM */
256     void    *control;                /**< handle for GUI control for this preference. GTK+ only? */
257 };
258
259 const char* prefs_get_description(pref_t *pref)
260 {
261     return pref->description;
262 }
263
264 const char* prefs_get_title(pref_t *pref)
265 {
266     return pref->title;
267 }
268
269 int prefs_get_type(pref_t *pref)
270 {
271     return pref->type;
272 }
273
274 gui_type_t prefs_get_gui_type(pref_t *pref)
275 {
276     return pref->gui;
277 }
278
279 const char* prefs_get_name(pref_t *pref)
280 {
281     return pref->name;
282 }
283
284 guint32 prefs_get_max_value(pref_t *pref)
285 {
286     return pref->info.max_value;
287 }
288
289 void* prefs_get_control(pref_t *pref)
290 {
291     return pref->control;
292 }
293
294 void prefs_set_control(pref_t *pref, void* control)
295 {
296     pref->control = control;
297 }
298
299 int prefs_get_ordinal(pref_t *pref)
300 {
301     return pref->ordinal;
302 }
303
304 /*
305  * List of all modules with preference settings.
306  */
307 static wmem_tree_t *prefs_modules = NULL;
308
309 /*
310  * List of all modules that should show up at the top level of the
311  * tree in the preference dialog box.
312  */
313 static wmem_tree_t *prefs_top_level_modules = NULL;
314
315 /** Sets up memory used by proto routines. Called at program startup */
316 void
317 prefs_init(void)
318 {
319     memset(&prefs, 0, sizeof(prefs));
320     prefs_modules = wmem_tree_new(wmem_epan_scope());
321     prefs_top_level_modules = wmem_tree_new(wmem_epan_scope());
322 }
323
324 /*
325  * Free the strings for a string-like preference.
326  */
327 static void
328 free_string_like_preference(pref_t *pref)
329 {
330     g_free(*pref->varp.string);
331     *pref->varp.string = NULL;
332     g_free(pref->default_val.string);
333     pref->default_val.string = NULL;
334 }
335
336 static void
337 free_pref(gpointer data, gpointer user_data _U_)
338 {
339     pref_t *pref = (pref_t *)data;
340     int type = pref->type;
341
342     /* we reset the PREF_OBSOLETE bit in order to allow the original preference to be freed */
343     RESET_PREF_OBSOLETE(type);
344
345     switch (type) {
346     case PREF_BOOL:
347     case PREF_ENUM:
348     case PREF_UINT:
349     case PREF_DECODE_AS_UINT:
350     case PREF_STATIC_TEXT:
351     case PREF_UAT:
352     case PREF_COLOR:
353         break;
354     case PREF_STRING:
355     case PREF_FILENAME:
356     case PREF_DIRNAME:
357         g_free(*pref->varp.string);
358         *pref->varp.string = NULL;
359         g_free(pref->default_val.string);
360         pref->default_val.string = NULL;
361         break;
362     case PREF_RANGE:
363     case PREF_DECODE_AS_RANGE:
364         wmem_free(wmem_epan_scope(), *pref->varp.range);
365         *pref->varp.range = NULL;
366         wmem_free(wmem_epan_scope(), pref->default_val.range);
367         pref->default_val.range = NULL;
368         break;
369     case PREF_CUSTOM:
370         if (strcmp(pref->name, "columns") == 0)
371           pref->stashed_val.boolval = TRUE;
372         pref->custom_cbs.free_cb(pref);
373         break;
374     }
375
376     g_free(pref);
377 }
378
379 static guint
380 free_module_prefs(module_t *module, gpointer data _U_)
381 {
382     if (module->prefs) {
383         g_list_foreach(module->prefs, free_pref, NULL);
384         g_list_free(module->prefs);
385     }
386     module->prefs = NULL;
387     module->numprefs = 0;
388     if (module->submodules) {
389         prefs_modules_foreach_submodules(module, free_module_prefs, NULL);
390     }
391     /*  We don't free the actual module: its submodules pointer points to
392         a wmem_tree and the module itself is stored in a wmem_tree
393      */
394
395     return 0;
396 }
397
398 /** Frees memory used by proto routines. Called at program shutdown */
399 void
400 prefs_cleanup(void)
401 {
402     /*  This isn't strictly necessary since we're exiting anyway, but let's
403      *  do what clean up we can.
404      */
405     prefs_modules_foreach(free_module_prefs, NULL);
406
407     /* Clean the uats */
408     uat_cleanup();
409
410     g_free(prefs.saved_at_version);
411     g_free(gpf_path);
412     gpf_path = NULL;
413 }
414
415 /*
416  * Register a module that will have preferences.
417  * Specify the module under which to register it or NULL to register it
418  * at the top level, the name used for the module in the preferences file,
419  * the title used in the tab for it in a preferences dialog box, and a
420  * routine to call back when we apply the preferences.
421  */
422 static module_t *
423 prefs_register_module(module_t *parent, const char *name, const char *title,
424                       const char *description, void (*apply_cb)(void),
425                       const gboolean use_gui)
426 {
427     return prefs_register_module_or_subtree(parent, name, title, description,
428                                             FALSE, apply_cb, use_gui);
429 }
430
431 static void
432 prefs_deregister_module(module_t *parent, const char *name, const char *title)
433 {
434     /* Remove this module from the list of all modules */
435     module_t *module = (module_t *)wmem_tree_remove_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE);
436
437     if (!module)
438         return;
439
440     if (parent == NULL) {
441         /* Remove from top */
442         wmem_tree_remove_string(prefs_top_level_modules, title, WMEM_TREE_STRING_NOCASE);
443     } else if (parent->submodules) {
444         /* Remove from parent */
445         wmem_tree_remove_string(parent->submodules, title, WMEM_TREE_STRING_NOCASE);
446     }
447
448     free_module_prefs(module, NULL);
449     wmem_free(wmem_epan_scope(), module);
450 }
451
452 /*
453  * Register a subtree that will have modules under it.
454  * Specify the module under which to register it or NULL to register it
455  * at the top level and the title used in the tab for it in a preferences
456  * dialog box.
457  */
458 static module_t *
459 prefs_register_subtree(module_t *parent, const char *title, const char *description,
460                        void (*apply_cb)(void))
461 {
462     return prefs_register_module_or_subtree(parent, NULL, title, description,
463                                             TRUE, apply_cb,
464                                             parent ? parent->use_gui : FALSE);
465 }
466
467 static module_t *
468 prefs_register_module_or_subtree(module_t *parent, const char *name,
469                                  const char *title, const char *description,
470                                  gboolean is_subtree, void (*apply_cb)(void),
471                                  gboolean use_gui)
472 {
473     module_t *module;
474     const char *p;
475     guchar c;
476
477     /* this module may have been created as a subtree item previously */
478     if ((module = find_subtree(parent, title))) {
479         /* the module is currently a subtree */
480         module->name = name;
481         module->apply_cb = apply_cb;
482         module->description = description;
483
484         if (prefs_find_module(name) == NULL) {
485             wmem_tree_insert_string(prefs_modules, name, module,
486                                   WMEM_TREE_STRING_NOCASE);
487         }
488
489         return module;
490     }
491
492     module = wmem_new(wmem_epan_scope(), module_t);
493     module->name = name;
494     module->title = title;
495     module->description = description;
496     module->apply_cb = apply_cb;
497     module->prefs = NULL;    /* no preferences, to start */
498     module->parent = parent;
499     module->submodules = NULL;    /* no submodules, to start */
500     module->numprefs = 0;
501     module->prefs_changed = FALSE;
502     module->obsolete = FALSE;
503     module->use_gui = use_gui;
504
505     /*
506      * Do we have a module name?
507      */
508     if (name != NULL) {
509         /*
510          * Yes.
511          * Make sure that only lower-case ASCII letters, numbers,
512          * underscores, hyphens, and dots appear in the name.
513          *
514          * Crash if there is, as that's an error in the code;
515          * you can make the title a nice string with capitalization,
516          * white space, punctuation, etc., but the name can be used
517          * on the command line, and shouldn't require quoting,
518          * shifting, etc.
519          */
520         for (p = name; (c = *p) != '\0'; p++) {
521             if (!(g_ascii_islower(c) || g_ascii_isdigit(c) || c == '_' ||
522                   c == '-' || c == '.'))
523                 g_error("Preference module \"%s\" contains invalid characters", name);
524         }
525
526         /*
527          * Make sure there's not already a module with that
528          * name.  Crash if there is, as that's an error in the
529          * code, and the code has to be fixed not to register
530          * more than one module with the same name.
531          *
532          * We search the list of all modules; the subtree stuff
533          * doesn't require preferences in subtrees to have names
534          * that reflect the subtree they're in (that would require
535          * protocol preferences to have a bogus "protocol.", or
536          * something such as that, to be added to all their names).
537          */
538         g_assert(prefs_find_module(name) == NULL);
539
540         /*
541          * Insert this module in the list of all modules.
542          */
543         wmem_tree_insert_string(prefs_modules, name, module, WMEM_TREE_STRING_NOCASE);
544     } else {
545         /*
546          * This has no name, just a title; check to make sure it's a
547          * subtree, and crash if it's not.
548          */
549         g_assert(is_subtree);
550     }
551
552     /*
553      * Insert this module into the appropriate place in the display
554      * tree.
555      */
556     if (parent == NULL) {
557         /*
558          * It goes at the top.
559          */
560         wmem_tree_insert_string(prefs_top_level_modules, title, module, WMEM_TREE_STRING_NOCASE);
561     } else {
562         /*
563          * It goes into the list for this module.
564          */
565
566         if (parent->submodules == NULL)
567             parent->submodules = wmem_tree_new(wmem_epan_scope());
568
569         wmem_tree_insert_string(parent->submodules, title, module, WMEM_TREE_STRING_NOCASE);
570     }
571
572     return module;
573 }
574
575 /*
576  * Register that a protocol has preferences.
577  */
578 module_t *protocols_module = NULL;
579
580 module_t *
581 prefs_register_protocol(int id, void (*apply_cb)(void))
582 {
583     protocol_t *protocol;
584
585     /*
586      * Have we yet created the "Protocols" subtree?
587      */
588     if (protocols_module == NULL) {
589         /*
590          * No.  Register Protocols subtree as well as any preferences
591          * for non-dissector modules.
592          */
593         pre_init_prefs();
594         prefs_register_modules();
595     }
596     protocol = find_protocol_by_id(id);
597     if (protocol == NULL)
598         g_error("Protocol preferences being registered with an invalid protocol ID");
599     return prefs_register_module(protocols_module,
600                                  proto_get_protocol_filter_name(id),
601                                  proto_get_protocol_short_name(protocol),
602                                  proto_get_protocol_name(id), apply_cb, TRUE);
603 }
604
605 void
606 prefs_deregister_protocol (int id)
607 {
608     protocol_t *protocol = find_protocol_by_id(id);
609     if (protocol == NULL)
610         g_error("Protocol preferences being de-registered with an invalid protocol ID");
611     prefs_deregister_module (protocols_module,
612                              proto_get_protocol_filter_name(id),
613                              proto_get_protocol_short_name(protocol));
614 }
615
616 module_t *
617 prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(void))
618 {
619     protocol_t *protocol;
620     module_t   *subtree_module;
621     module_t   *new_module;
622     char       *sep = NULL, *ptr = NULL, *orig = NULL;
623
624     /*
625      * Have we yet created the "Protocols" subtree?
626      * XXX - can we just do this by registering Protocols/{subtree}?
627      * If not, why not?
628      */
629     if (protocols_module == NULL) {
630         /*
631          * No.  Register Protocols subtree as well as any preferences
632          * for non-dissector modules.
633          */
634         pre_init_prefs();
635         prefs_register_modules();
636     }
637
638     subtree_module = protocols_module;
639
640     if (subtree) {
641         /* take a copy of the buffer, orig keeps a base pointer while ptr
642          * walks through the string */
643         orig = ptr = g_strdup(subtree);
644
645         while (ptr && *ptr) {
646
647             if ((sep = strchr(ptr, '/')))
648                 *sep++ = '\0';
649
650             if (!(new_module = find_subtree(subtree_module, ptr))) {
651                 /*
652                  * There's no such module; create it, with the description
653                  * being the name (if it's later registered explicitly
654                  * with a description, that will override it).
655                  */
656                 ptr = wmem_strdup(wmem_epan_scope(), ptr),
657                 new_module = prefs_register_subtree(subtree_module, ptr, ptr, NULL);
658             }
659
660             subtree_module = new_module;
661             ptr = sep;
662
663         }
664
665         g_free(orig);
666     }
667
668     protocol = find_protocol_by_id(id);
669     if (protocol == NULL)
670         g_error("Protocol subtree being registered with an invalid protocol ID");
671     return prefs_register_module(subtree_module,
672                                  proto_get_protocol_filter_name(id),
673                                  proto_get_protocol_short_name(protocol),
674                                  proto_get_protocol_name(id), apply_cb, TRUE);
675 }
676
677
678 /*
679  * Register that a protocol used to have preferences but no longer does,
680  * by creating an "obsolete" module for it.
681  */
682 module_t *
683 prefs_register_protocol_obsolete(int id)
684 {
685     module_t *module;
686     protocol_t *protocol;
687
688     /*
689      * Have we yet created the "Protocols" subtree?
690      */
691     if (protocols_module == NULL) {
692         /*
693          * No.  Register Protocols subtree as well as any preferences
694          * for non-dissector modules.
695          */
696         pre_init_prefs();
697         prefs_register_modules();
698     }
699     protocol = find_protocol_by_id(id);
700     if (protocol == NULL)
701         g_error("Protocol being registered with an invalid protocol ID");
702     module = prefs_register_module(protocols_module,
703                                    proto_get_protocol_filter_name(id),
704                                    proto_get_protocol_short_name(protocol),
705                                    proto_get_protocol_name(id), NULL, TRUE);
706     module->obsolete = TRUE;
707     return module;
708 }
709
710 /*
711  * Register that a statistical tap has preferences.
712  *
713  * "name" is a name for the tap to use on the command line with "-o"
714  * and in preference files.
715  *
716  * "title" is a short human-readable name for the tap.
717  *
718  * "description" is a longer human-readable description of the tap.
719  */
720 module_t *stats_module = NULL;
721
722 module_t *
723 prefs_register_stat(const char *name, const char *title,
724                     const char *description, void (*apply_cb)(void))
725 {
726     /*
727      * Have we yet created the "Statistics" subtree?
728      */
729     if (stats_module == NULL) {
730         /*
731          * No.  Register Statistics subtree as well as any preferences
732          * for non-dissector modules.
733          */
734         pre_init_prefs();
735         prefs_register_modules();
736     }
737
738     return prefs_register_module(stats_module, name, title, description,
739                                  apply_cb, TRUE);
740 }
741
742 module_t *
743 prefs_find_module(const char *name)
744 {
745     return (module_t *)wmem_tree_lookup_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE);
746 }
747
748 static module_t *
749 find_subtree(module_t *parent, const char *name)
750 {
751     return (module_t *)wmem_tree_lookup_string(parent ? parent->submodules : prefs_top_level_modules, name, WMEM_TREE_STRING_NOCASE);
752 }
753
754 /*
755  * Call a callback function, with a specified argument, for each module
756  * in a list of modules.  If the list is NULL, searches the top-level
757  * list in the display tree of modules.  If any callback returns a
758  * non-zero value, we stop and return that value, otherwise we
759  * return 0.
760  *
761  * Ignores "obsolete" modules; their sole purpose is to allow old
762  * preferences for dissectors that no longer have preferences to be
763  * silently ignored in preference files.  Does not ignore subtrees,
764  * as this can be used when walking the display tree of modules.
765  */
766
767 typedef struct {
768     module_cb callback;
769     gpointer user_data;
770     guint ret;
771 } call_foreach_t;
772
773 static gboolean
774 call_foreach_cb(const void *key _U_, void *value, void *data)
775 {
776     module_t *module = (module_t*)value;
777     call_foreach_t *call_data = (call_foreach_t*)data;
778
779     if (!module->obsolete)
780         call_data->ret = (*call_data->callback)(module, call_data->user_data);
781
782     return (call_data->ret != 0);
783 }
784
785 static guint
786 prefs_module_list_foreach(wmem_tree_t *module_list, module_cb callback,
787                           gpointer user_data)
788 {
789     call_foreach_t call_data;
790
791     if (module_list == NULL)
792         module_list = prefs_top_level_modules;
793
794     call_data.callback = callback;
795     call_data.user_data = user_data;
796     call_data.ret = 0;
797     wmem_tree_foreach(module_list, call_foreach_cb, &call_data);
798     return call_data.ret;
799 }
800
801 /*
802  * Returns TRUE if module has any submodules
803  */
804 gboolean
805 prefs_module_has_submodules(module_t *module)
806 {
807     if (module->submodules == NULL) {
808         return FALSE;
809     }
810
811     if (wmem_tree_is_empty(module->submodules)) {
812         return FALSE;
813     }
814
815     return TRUE;
816 }
817
818 /*
819  * Call a callback function, with a specified argument, for each module
820  * in the list of all modules.  (This list does not include subtrees.)
821  *
822  * Ignores "obsolete" modules; their sole purpose is to allow old
823  * preferences for dissectors that no longer have preferences to be
824  * silently ignored in preference files.
825  */
826 guint
827 prefs_modules_foreach(module_cb callback, gpointer user_data)
828 {
829     return prefs_module_list_foreach(prefs_modules, callback, user_data);
830 }
831
832 /*
833  * Call a callback function, with a specified argument, for each submodule
834  * of specified modules.  If the module is NULL, goes through the top-level
835  * list in the display tree of modules.
836  *
837  * Ignores "obsolete" modules; their sole purpose is to allow old
838  * preferences for dissectors that no longer have preferences to be
839  * silently ignored in preference files.  Does not ignore subtrees,
840  * as this can be used when walking the display tree of modules.
841  */
842 guint
843 prefs_modules_foreach_submodules(module_t *module, module_cb callback,
844                                  gpointer user_data)
845 {
846     return prefs_module_list_foreach((module)?module->submodules:prefs_top_level_modules, callback, user_data);
847 }
848
849 static gboolean
850 call_apply_cb(const void *key _U_, void *value, void *data _U_)
851 {
852     module_t *module = (module_t *)value;
853
854     if (module->obsolete)
855         return FALSE;
856     if (module->prefs_changed) {
857         if (module->apply_cb != NULL)
858             (*module->apply_cb)();
859         module->prefs_changed = FALSE;
860     }
861     if (module->submodules)
862         wmem_tree_foreach(module->submodules, call_apply_cb, NULL);
863     return FALSE;
864 }
865
866 /*
867  * Call the "apply" callback function for each module if any of its
868  * preferences have changed, and then clear the flag saying its
869  * preferences have changed, as the module has been notified of that
870  * fact.
871  */
872 void
873 prefs_apply_all(void)
874 {
875     wmem_tree_foreach(prefs_modules, call_apply_cb, NULL);
876 }
877
878 /*
879  * Call the "apply" callback function for a specific module if any of
880  * its preferences have changed, and then clear the flag saying its
881  * preferences have changed, as the module has been notified of that
882  * fact.
883  */
884 void
885 prefs_apply(module_t *module)
886 {
887     if (module && module->prefs_changed)
888         call_apply_cb(NULL, module, NULL);
889 }
890
891 /*
892  * Register a preference in a module's list of preferences.
893  * If it has a title, give it an ordinal number; otherwise, it's a
894  * preference that won't show up in the UI, so it shouldn't get an
895  * ordinal number (the ordinal should be the ordinal in the set of
896  * *visible* preferences).
897  */
898 static pref_t *
899 register_preference(module_t *module, const char *name, const char *title,
900                     const char *description, int type)
901 {
902     pref_t *preference;
903     const gchar *p;
904     const char *name_prefix = (module->name != NULL) ? module->name : module->parent->name;
905
906     preference = g_new(pref_t,1);
907     preference->name = name;
908     preference->title = title;
909     preference->description = description;
910     preference->type = type;
911     preference->gui = GUI_ALL;  /* default */
912     if (title != NULL)
913         preference->ordinal = module->numprefs;
914     else
915         preference->ordinal = -1;    /* no ordinal for you */
916
917     /*
918      * Make sure that only lower-case ASCII letters, numbers,
919      * underscores, and dots appear in the preference name.
920      *
921      * Crash if there is, as that's an error in the code;
922      * you can make the title and description nice strings
923      * with capitalization, white space, punctuation, etc.,
924      * but the name can be used on the command line,
925      * and shouldn't require quoting, shifting, etc.
926      */
927     for (p = name; *p != '\0'; p++)
928         if (!(g_ascii_islower(*p) || g_ascii_isdigit(*p) || *p == '_' || *p == '.'))
929             g_error("Preference \"%s.%s\" contains invalid characters", module->name, name);
930
931     /*
932      * Make sure there's not already a preference with that
933      * name.  Crash if there is, as that's an error in the
934      * code, and the code has to be fixed not to register
935      * more than one preference with the same name.
936      */
937     if (prefs_find_preference(module, name) != NULL)
938         g_error("Preference %s has already been registered", name);
939
940     if ((!IS_PREF_OBSOLETE(type)) &&
941         /* Don't compare if it's a subtree */
942         (module->name != NULL)) {
943         /*
944          * Make sure the preference name doesn't begin with the
945          * module name, as that's redundant and Just Silly.
946          */
947         if (!((strncmp(name, module->name, strlen(module->name)) != 0) ||
948             (((name[strlen(module->name)]) != '.') && ((name[strlen(module->name)]) != '_'))))
949             g_error("Preference %s begins with the module name", name);
950     }
951
952     /* The title shows up in the preferences dialog. Make sure it's UI-friendly. */
953     if (preference->title) {
954         const char *cur_char;
955         if (preference->type != PREF_STATIC_TEXT && g_utf8_strlen(preference->title, -1) > 80) { // Arbitrary.
956             g_error("Title for preference %s.%s is too long: %s", name_prefix, preference->name, preference->title);
957         }
958
959         if (!g_utf8_validate(preference->title, -1, NULL)) {
960             g_error("Title for preference %s.%s isn't valid UTF-8.", name_prefix, preference->name);
961         }
962
963         for (cur_char = preference->title; *cur_char; cur_char = g_utf8_next_char(cur_char)) {
964             if (!g_unichar_isprint(g_utf8_get_char(cur_char))) {
965                 g_error("Title for preference %s.%s isn't printable UTF-8.", name_prefix, preference->name);
966             }
967         }
968     }
969
970     if (preference->description) {
971         if (!g_utf8_validate(preference->description, -1, NULL)) {
972             g_error("Description for preference %s.%s isn't valid UTF-8.", name_prefix, preference->name);
973         }
974     }
975
976     /*
977      * We passed all of our checks. Add the preference.
978      */
979     module->prefs = g_list_append(module->prefs, preference);
980     if (title != NULL)
981         module->numprefs++;
982
983     return preference;
984 }
985
986 /*
987  * Find a preference in a module's list of preferences, given the module
988  * and the preference's name.
989  */
990 typedef struct {
991     GList *list_entry;
992     const char *name;
993     module_t *submodule;
994 } find_pref_arg_t;
995
996 static gint
997 preference_match(gconstpointer a, gconstpointer b)
998 {
999     const pref_t *pref = (const pref_t *)a;
1000     const char *name = (const char *)b;
1001
1002     return strcmp(name, pref->name);
1003 }
1004
1005 static gboolean
1006 module_find_pref_cb(const void *key _U_, void *value, void *data)
1007 {
1008     find_pref_arg_t* arg = (find_pref_arg_t*)data;
1009     GList *list_entry;
1010     module_t *module = (module_t *)value;
1011
1012     if (module == NULL)
1013         return FALSE;
1014
1015     list_entry = g_list_find_custom(module->prefs, arg->name,
1016         preference_match);
1017
1018     if (list_entry == NULL)
1019         return FALSE;
1020
1021     arg->list_entry = list_entry;
1022     arg->submodule = module;
1023     return TRUE;
1024 }
1025
1026 /* Tries to find a preference, setting containing_module to the (sub)module
1027  * holding this preference. */
1028 static struct preference *
1029 prefs_find_preference_with_submodule(module_t *module, const char *name,
1030         module_t **containing_module)
1031 {
1032     find_pref_arg_t arg;
1033     GList *list_entry;
1034
1035     if (module == NULL)
1036         return NULL;    /* invalid parameters */
1037
1038     list_entry = g_list_find_custom(module->prefs, name,
1039         preference_match);
1040     arg.submodule = NULL;
1041
1042     if (list_entry == NULL)
1043     {
1044         arg.list_entry = NULL;
1045         if (module->submodules != NULL)
1046         {
1047             arg.name = name;
1048             wmem_tree_foreach(module->submodules, module_find_pref_cb, &arg);
1049         }
1050
1051         list_entry = arg.list_entry;
1052     }
1053
1054     if (list_entry == NULL)
1055         return NULL;    /* no such preference */
1056
1057     if (containing_module)
1058         *containing_module = arg.submodule ? arg.submodule : module;
1059
1060     return (struct preference *) list_entry->data;
1061 }
1062
1063 struct preference *
1064 prefs_find_preference(module_t *module, const char *name)
1065 {
1066     return prefs_find_preference_with_submodule(module, name, NULL);
1067 }
1068
1069 /*
1070  * Returns TRUE if the given protocol has registered preferences
1071  */
1072 gboolean
1073 prefs_is_registered_protocol(const char *name)
1074 {
1075     module_t *m = prefs_find_module(name);
1076
1077     return (m != NULL && !m->obsolete);
1078 }
1079
1080 /*
1081  * Returns the module title of a registered protocol
1082  */
1083 const char *
1084 prefs_get_title_by_name(const char *name)
1085 {
1086     module_t *m = prefs_find_module(name);
1087
1088     return (m != NULL && !m->obsolete) ? m->title : NULL;
1089 }
1090
1091 /*
1092  * Register a preference with an unsigned integral value.
1093  */
1094 void
1095 prefs_register_uint_preference(module_t *module, const char *name,
1096                                const char *title, const char *description,
1097                                guint base, guint *var)
1098 {
1099     pref_t *preference;
1100
1101     preference = register_preference(module, name, title, description,
1102                                      PREF_UINT);
1103     preference->varp.uint = var;
1104     preference->default_val.uint = *var;
1105     g_assert(base > 0 && base != 1 && base < 37);
1106     preference->info.base = base;
1107 }
1108
1109 /*
1110  * XXX Add a prefs_register_{uint16|port}_preference which sets max_value?
1111  */
1112
1113
1114 /*
1115  * Register a "custom" preference with a unsigned integral value.
1116  * XXX - This should be temporary until we can find a better way
1117  * to do "custom" preferences
1118  */
1119 static void
1120 prefs_register_uint_custom_preference(module_t *module, const char *name,
1121                                       const char *title, const char *description,
1122                                       struct pref_custom_cbs* custom_cbs, guint *var)
1123 {
1124     pref_t *preference;
1125
1126     preference = register_preference(module, name, title, description,
1127                                      PREF_CUSTOM);
1128
1129     preference->custom_cbs = *custom_cbs;
1130     preference->varp.uint = var;
1131     preference->default_val.uint = *var;
1132 }
1133
1134 /*
1135  * Register a preference with an Boolean value.
1136  */
1137 void
1138 prefs_register_bool_preference(module_t *module, const char *name,
1139                                const char *title, const char *description,
1140                                gboolean *var)
1141 {
1142     pref_t *preference;
1143
1144     preference = register_preference(module, name, title, description,
1145                                      PREF_BOOL);
1146     preference->varp.boolp = var;
1147     preference->default_val.boolval = *var;
1148 }
1149
1150 gboolean prefs_set_bool_value(pref_t *pref, gboolean value, pref_source_t source)
1151 {
1152     gboolean changed = FALSE;
1153
1154     switch (source)
1155     {
1156     case pref_default:
1157         if (pref->default_val.boolval != value) {
1158             pref->default_val.boolval = value;
1159             changed = TRUE;
1160         }
1161         break;
1162     case pref_stashed:
1163         if (pref->stashed_val.boolval != value) {
1164             pref->stashed_val.boolval = value;
1165             changed = TRUE;
1166         }
1167         break;
1168     case pref_current:
1169         if (*pref->varp.boolp != value) {
1170             *pref->varp.boolp = value;
1171             changed = TRUE;
1172         }
1173         break;
1174     default:
1175         g_assert_not_reached();
1176         break;
1177     }
1178
1179     return changed;
1180 }
1181
1182 void prefs_invert_bool_value(pref_t *pref, pref_source_t source)
1183 {
1184     switch (source)
1185     {
1186     case pref_default:
1187         pref->default_val.boolval = !pref->default_val.boolval;
1188         break;
1189     case pref_stashed:
1190         pref->stashed_val.boolval = !pref->stashed_val.boolval;
1191         break;
1192     case pref_current:
1193         *pref->varp.boolp = !(*pref->varp.boolp);
1194         break;
1195     default:
1196         g_assert_not_reached();
1197         break;
1198     }
1199 }
1200
1201 gboolean prefs_get_bool_value(pref_t *pref, pref_source_t source)
1202 {
1203     switch (source)
1204     {
1205     case pref_default:
1206         return pref->default_val.boolval;
1207         break;
1208     case pref_stashed:
1209         return pref->stashed_val.boolval;
1210         break;
1211     case pref_current:
1212         return *pref->varp.boolp;
1213         break;
1214     default:
1215         g_assert_not_reached();
1216         break;
1217     }
1218
1219     return FALSE;
1220 }
1221
1222 /*
1223  * Register a preference with an enumerated value.
1224  */
1225 /*
1226  * XXX Should we get rid of the radio_buttons parameter and make that
1227  * behavior automatic depending on the number of items?
1228  */
1229 void
1230 prefs_register_enum_preference(module_t *module, const char *name,
1231                                const char *title, const char *description,
1232                                gint *var, const enum_val_t *enumvals,
1233                                gboolean radio_buttons)
1234 {
1235     pref_t *preference;
1236
1237     preference = register_preference(module, name, title, description,
1238                                      PREF_ENUM);
1239     preference->varp.enump = var;
1240     preference->default_val.enumval = *var;
1241     preference->info.enum_info.enumvals = enumvals;
1242     preference->info.enum_info.radio_buttons = radio_buttons;
1243 }
1244
1245 gboolean prefs_set_enum_value(pref_t *pref, gint value, pref_source_t source)
1246 {
1247     gboolean changed = FALSE;
1248
1249     switch (source)
1250     {
1251     case pref_default:
1252         if (pref->default_val.enumval != value) {
1253             pref->default_val.enumval = value;
1254             changed = TRUE;
1255         }
1256         break;
1257     case pref_stashed:
1258         if (pref->stashed_val.enumval != value) {
1259             pref->stashed_val.enumval = value;
1260             changed = TRUE;
1261         }
1262         break;
1263     case pref_current:
1264         if (*pref->varp.enump != value) {
1265             *pref->varp.enump = value;
1266             changed = TRUE;
1267         }
1268         break;
1269     default:
1270         g_assert_not_reached();
1271         break;
1272     }
1273
1274     return changed;
1275 }
1276
1277 gint prefs_get_enum_value(pref_t *pref, pref_source_t source)
1278 {
1279     switch (source)
1280     {
1281     case pref_default:
1282         return pref->default_val.enumval;
1283         break;
1284     case pref_stashed:
1285         return pref->stashed_val.enumval;
1286         break;
1287     case pref_current:
1288         return *pref->varp.enump;
1289         break;
1290     default:
1291         g_assert_not_reached();
1292         break;
1293     }
1294
1295     return 0;
1296 }
1297
1298 const enum_val_t* prefs_get_enumvals(pref_t *pref)
1299 {
1300     return pref->info.enum_info.enumvals;
1301 }
1302
1303 gboolean prefs_get_enum_radiobuttons(pref_t *pref)
1304 {
1305     return pref->info.enum_info.radio_buttons;
1306 }
1307
1308 static void
1309 register_string_like_preference(module_t *module, const char *name,
1310                                 const char *title, const char *description,
1311                                 char **var, int type,
1312                                 struct pref_custom_cbs* custom_cbs,
1313                                 gboolean free_tmp)
1314 {
1315     pref_t *pref;
1316     gchar *tmp;
1317
1318     pref = register_preference(module, name, title, description, type);
1319
1320     /*
1321      * String preference values should be non-null (as you can't
1322      * keep them null after using the preferences GUI, you can at best
1323      * have them be null strings) and freeable (as we free them
1324      * if we change them).
1325      *
1326      * If the value is a null pointer, make it a copy of a null
1327      * string, otherwise make it a copy of the value.
1328      */
1329     tmp = *var;
1330     if (*var == NULL) {
1331         *var = g_strdup("");
1332     } else {
1333         *var = g_strdup(*var);
1334     }
1335     if (free_tmp) {
1336         g_free(tmp);
1337     }
1338     pref->varp.string = var;
1339     pref->default_val.string = g_strdup(*var);
1340     pref->stashed_val.string = NULL;
1341     if (type == PREF_CUSTOM) {
1342         g_assert(custom_cbs);
1343         pref->custom_cbs = *custom_cbs;
1344     }
1345 }
1346
1347 /*
1348  * For use by UI code that sets preferences.
1349  */
1350 gboolean
1351 prefs_set_string_value(pref_t *pref, const char* value, pref_source_t source)
1352 {
1353     gboolean changed = FALSE;
1354
1355     switch (source)
1356     {
1357     case pref_default:
1358         if (*pref->default_val.string) {
1359             if (strcmp(pref->default_val.string, value) != 0) {
1360                 changed = TRUE;
1361                 g_free(pref->default_val.string);
1362                 pref->default_val.string = g_strdup(value);
1363             }
1364         } else if (value) {
1365             pref->default_val.string = g_strdup(value);
1366         }
1367         break;
1368     case pref_stashed:
1369         if (pref->stashed_val.string) {
1370             if (strcmp(pref->stashed_val.string, value) != 0) {
1371                 changed = TRUE;
1372                 g_free(pref->stashed_val.string);
1373                 pref->stashed_val.string = g_strdup(value);
1374             }
1375         } else if (value) {
1376             pref->stashed_val.string = g_strdup(value);
1377         }
1378         break;
1379     case pref_current:
1380         if (*pref->varp.string) {
1381             if (strcmp(*pref->varp.string, value) != 0) {
1382                 changed = TRUE;
1383                 g_free(*pref->varp.string);
1384                 *pref->varp.string = g_strdup(value);
1385             }
1386         } else if (value) {
1387             *pref->varp.string = g_strdup(value);
1388         }
1389         break;
1390     default:
1391         g_assert_not_reached();
1392         break;
1393     }
1394
1395     return changed;
1396 }
1397
1398 char* prefs_get_string_value(pref_t *pref, pref_source_t source)
1399 {
1400     switch (source)
1401     {
1402     case pref_default:
1403         return pref->default_val.string;
1404     case pref_stashed:
1405         return pref->stashed_val.string;
1406     case pref_current:
1407         return *pref->varp.string;
1408     default:
1409         g_assert_not_reached();
1410         break;
1411     }
1412
1413     return NULL;
1414 }
1415
1416 /*
1417  * Reset the value of a string-like preference.
1418  */
1419 static void
1420 reset_string_like_preference(pref_t *pref)
1421 {
1422     g_free(*pref->varp.string);
1423     *pref->varp.string = g_strdup(pref->default_val.string);
1424 }
1425
1426 /*
1427  * Register a preference with a character-string value.
1428  */
1429 void
1430 prefs_register_string_preference(module_t *module, const char *name,
1431                                  const char *title, const char *description,
1432                                  const char **var)
1433 {
1434 DIAG_OFF(cast-qual)
1435     register_string_like_preference(module, name, title, description,
1436                                     (char **)var, PREF_STRING, NULL, FALSE);
1437 DIAG_ON(cast-qual)
1438 }
1439
1440 /*
1441  * Register a preference with a file name (string) value.
1442  */
1443 void
1444 prefs_register_filename_preference(module_t *module, const char *name,
1445                                    const char *title, const char *description,
1446                                    const char **var)
1447 {
1448 DIAG_OFF(cast-qual)
1449     register_string_like_preference(module, name, title, description,
1450                                     (char **)var, PREF_FILENAME, NULL, FALSE);
1451 DIAG_ON(cast-qual)
1452 }
1453
1454 /*
1455  * Register a preference with a directory name (string) value.
1456  */
1457 void
1458 prefs_register_directory_preference(module_t *module, const char *name,
1459                                    const char *title, const char *description,
1460                                    const char **var)
1461 {
1462 DIAG_OFF(cast-qual)
1463     register_string_like_preference(module, name, title, description,
1464                                     (char **)var, PREF_DIRNAME, NULL, FALSE);
1465 DIAG_ON(cast-qual)
1466 }
1467
1468 /* Refactoring to handle both PREF_RANGE and PREF_DECODE_AS_RANGE */
1469 static void
1470 prefs_register_range_preference_common(module_t *module, const char *name,
1471                                 const char *title, const char *description,
1472                                 range_t **var, guint32 max_value, int type)
1473 {
1474     pref_t *preference;
1475
1476     preference = register_preference(module, name, title, description, type);
1477     preference->info.max_value = max_value;
1478
1479     /*
1480      * Range preference values should be non-null (as you can't
1481      * keep them null after using the preferences GUI, you can at best
1482      * have them be empty ranges) and freeable (as we free them
1483      * if we change them).
1484      *
1485      * If the value is a null pointer, make it an empty range.
1486      */
1487     if (*var == NULL)
1488         *var = range_empty(wmem_epan_scope());
1489     preference->varp.range = var;
1490     preference->default_val.range = range_copy(wmem_epan_scope(), *var);
1491     preference->stashed_val.range = NULL;
1492 }
1493
1494 /*
1495  * Register a preference with a ranged value.
1496  */
1497 void
1498 prefs_register_range_preference(module_t *module, const char *name,
1499                                 const char *title, const char *description,
1500                                 range_t **var, guint32 max_value)
1501 {
1502     prefs_register_range_preference_common(module, name, title,
1503                 description, var, max_value, PREF_RANGE);
1504 }
1505
1506 gboolean
1507 prefs_set_range_value_work(pref_t *pref, const gchar *value,
1508                            gboolean return_range_errors, gboolean *changed)
1509 {
1510     range_t *newrange;
1511
1512     if (range_convert_str_work(wmem_epan_scope(), &newrange, value, pref->info.max_value,
1513                                return_range_errors) != CVT_NO_ERROR) {
1514         return FALSE;        /* number was bad */
1515     }
1516
1517     if (!ranges_are_equal(*pref->varp.range, newrange)) {
1518         *changed = TRUE;
1519         wmem_free(wmem_epan_scope(), *pref->varp.range);
1520         *pref->varp.range = newrange;
1521     } else {
1522         wmem_free(wmem_epan_scope(), newrange);
1523     }
1524     return TRUE;
1525 }
1526
1527 /*
1528  * For use by UI code that sets preferences.
1529  */
1530 gboolean
1531 prefs_set_stashed_range_value(pref_t *pref, const gchar *value)
1532 {
1533     range_t *newrange;
1534
1535     if (range_convert_str_work(wmem_epan_scope(), &newrange, value, pref->info.max_value,
1536                                TRUE) != CVT_NO_ERROR) {
1537         return FALSE;        /* number was bad */
1538     }
1539
1540     if (!ranges_are_equal(pref->stashed_val.range, newrange)) {
1541         wmem_free(wmem_epan_scope(), pref->stashed_val.range);
1542         pref->stashed_val.range = newrange;
1543     } else {
1544         wmem_free(wmem_epan_scope(), newrange);
1545     }
1546     return TRUE;
1547
1548 }
1549
1550 gboolean prefs_set_range_value(pref_t *pref, range_t *value, pref_source_t source)
1551 {
1552     gboolean changed = FALSE;
1553
1554     switch (source)
1555     {
1556     case pref_default:
1557         if (!ranges_are_equal(pref->default_val.range, value)) {
1558             wmem_free(wmem_epan_scope(), pref->default_val.range);
1559             pref->default_val.range = range_copy(wmem_epan_scope(), value);
1560             changed = TRUE;
1561         }
1562         break;
1563     case pref_stashed:
1564         if (!ranges_are_equal(pref->stashed_val.range, value)) {
1565             wmem_free(wmem_epan_scope(), pref->stashed_val.range);
1566             pref->stashed_val.range = range_copy(wmem_epan_scope(), value);
1567             changed = TRUE;
1568         }
1569         break;
1570     case pref_current:
1571         if (!ranges_are_equal(*pref->varp.range, value)) {
1572             wmem_free(wmem_epan_scope(), *pref->varp.range);
1573             *pref->varp.range = range_copy(wmem_epan_scope(), value);
1574             changed = TRUE;
1575         }
1576         break;
1577     default:
1578         g_assert_not_reached();
1579         break;
1580     }
1581
1582     return changed;
1583 }
1584
1585 range_t* prefs_get_range_value_real(pref_t *pref, pref_source_t source)
1586 {
1587     switch (source)
1588     {
1589     case pref_default:
1590         return pref->default_val.range;
1591     case pref_stashed:
1592         return pref->stashed_val.range;
1593         break;
1594     case pref_current:
1595         return *pref->varp.range;
1596         break;
1597     default:
1598         g_assert_not_reached();
1599         break;
1600     }
1601
1602     return NULL;
1603 }
1604
1605 range_t* prefs_get_range_value(const char *module_name, const char* pref_name)
1606 {
1607     return prefs_get_range_value_real(prefs_find_preference(prefs_find_module(module_name), pref_name), pref_current);
1608 }
1609
1610 void
1611 prefs_range_add_value(pref_t *pref, guint32 val)
1612 {
1613     range_add_value(wmem_epan_scope(), pref->varp.range, val);
1614 }
1615
1616 void
1617 prefs_range_remove_value(pref_t *pref, guint32 val)
1618 {
1619     range_remove_value(wmem_epan_scope(), pref->varp.range, val);
1620 }
1621
1622 /*
1623  * Register a static text 'preference'.  It can be used to add explanatory
1624  * text inline with other preferences in the GUI.
1625  * Note: Static preferences are not saved to the preferences file.
1626  */
1627 void
1628 prefs_register_static_text_preference(module_t *module, const char *name,
1629                                       const char *title,
1630                                       const char *description)
1631 {
1632     register_preference(module, name, title, description, PREF_STATIC_TEXT);
1633 }
1634
1635 /*
1636  * Register a uat 'preference'. It adds a button that opens the uat's window in the
1637  * preferences tab of the module.
1638  */
1639 extern void
1640 prefs_register_uat_preference(module_t *module, const char *name,
1641                               const char *title, const char *description,
1642                               uat_t* uat)
1643 {
1644
1645     pref_t* preference = register_preference(module, name, title, description, PREF_UAT);
1646
1647     preference->varp.uat = uat;
1648 }
1649
1650 /*
1651  * Register a uat 'preference' for QT only. It adds a button that opens the uat's window in the
1652  * preferences tab of the module.
1653  */
1654 extern void
1655 prefs_register_uat_preference_qt(module_t *module, const char *name,
1656                               const char *title, const char *description,
1657                               uat_t* uat)
1658 {
1659
1660     pref_t* preference = register_preference(module, name, title, description, PREF_UAT);
1661
1662     preference->varp.uat = uat;
1663
1664     preference->gui = GUI_QT;
1665 }
1666
1667 struct epan_uat* prefs_get_uat_value(pref_t *pref)
1668 {
1669     return pref->varp.uat;
1670 }
1671
1672 /*
1673  * Register a color preference.
1674  */
1675 void
1676 prefs_register_color_preference(module_t *module, const char *name,
1677                                 const char *title, const char *description,
1678                                 color_t *color)
1679 {
1680     pref_t* preference = register_preference(module, name, title, description, PREF_COLOR);
1681
1682     preference->varp.colorp = color;
1683     preference->default_val.color = *color;
1684 }
1685
1686 gboolean prefs_set_color_value(pref_t *pref, color_t value, pref_source_t source)
1687 {
1688     gboolean changed = FALSE;
1689
1690     switch (source)
1691     {
1692     case pref_default:
1693         if ((pref->default_val.color.red != value.red) &&
1694             (pref->default_val.color.green != value.green) &&
1695             (pref->default_val.color.blue != value.blue)) {
1696             changed = TRUE;
1697             pref->default_val.color = value;
1698         }
1699         break;
1700     case pref_stashed:
1701         if ((pref->stashed_val.color.red != value.red) &&
1702             (pref->stashed_val.color.green != value.green) &&
1703             (pref->stashed_val.color.blue != value.blue)) {
1704             changed = TRUE;
1705             pref->stashed_val.color = value;
1706         }
1707         break;
1708     case pref_current:
1709         if ((pref->varp.colorp->red != value.red) &&
1710             (pref->varp.colorp->green != value.green) &&
1711             (pref->varp.colorp->blue != value.blue)) {
1712             changed = TRUE;
1713             *pref->varp.colorp = value;
1714         }
1715         break;
1716     default:
1717         g_assert_not_reached();
1718         break;
1719     }
1720
1721     return changed;
1722 }
1723
1724 color_t* prefs_get_color_value(pref_t *pref, pref_source_t source)
1725 {
1726     switch (source)
1727     {
1728     case pref_default:
1729         return &pref->default_val.color;
1730     case pref_stashed:
1731         return &pref->stashed_val.color;
1732         break;
1733     case pref_current:
1734         return pref->varp.colorp;
1735         break;
1736     default:
1737         g_assert_not_reached();
1738         break;
1739     }
1740
1741     return NULL;
1742 }
1743
1744 /*
1745  * Register a "custom" preference with a list.
1746  * XXX - This should be temporary until we can find a better way
1747  * to do "custom" preferences
1748  */
1749 typedef void (*pref_custom_list_init_cb) (pref_t* pref, GList** value);
1750
1751 static void
1752 prefs_register_list_custom_preference(module_t *module, const char *name,
1753                                       const char *title, const char *description,
1754                                       struct pref_custom_cbs* custom_cbs,
1755                                       pref_custom_list_init_cb init_cb,
1756                                       GList** list)
1757 {
1758     pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM);
1759
1760     preference->custom_cbs = *custom_cbs;
1761     init_cb(preference, list);
1762 }
1763
1764 /*
1765  * Register a custom preference.
1766  */
1767 void
1768 prefs_register_custom_preference(module_t *module, const char *name,
1769                                  const char *title, const char *description,
1770                                  struct pref_custom_cbs* custom_cbs,
1771                                  void **custom_data _U_)
1772 {
1773     pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM);
1774
1775     preference->custom_cbs = *custom_cbs;
1776     /* XXX - wait until we can handle void** pointers
1777     preference->custom_cbs.init_cb(preference, custom_data);
1778     */
1779 }
1780
1781 /*
1782  * Register a (internal) "Decode As" preference with a ranged value.
1783  */
1784 void prefs_register_decode_as_range_preference(module_t *module, const char *name,
1785     const char *title, const char *description, range_t **var,
1786     guint32 max_value)
1787 {
1788     prefs_register_range_preference_common(module, name, title,
1789                 description, var, max_value, PREF_DECODE_AS_RANGE);
1790 }
1791
1792 /*
1793  * Register a (internal) "Decode As" preference with an unsigned integral value
1794  * for a dissector table.
1795  */
1796 void prefs_register_decode_as_preference(module_t *module, const char *name,
1797     const char *title, const char *description, guint *var)
1798 {
1799     pref_t *preference;
1800
1801     preference = register_preference(module, name, title, description,
1802                                      PREF_DECODE_AS_UINT);
1803     preference->varp.uint = var;
1804     preference->default_val.uint = *var;
1805     /* XXX - Presume base 10 for now */
1806     preference->info.base = 10;
1807 }
1808
1809 gboolean prefs_add_decode_as_value(pref_t *pref, guint value, gboolean replace)
1810 {
1811     switch(pref->type)
1812     {
1813     case PREF_DECODE_AS_UINT:
1814         /* This doesn't support multiple values for a dissector in Decode As because the
1815             preference only supports a single value. This leads to a "last port for
1816             dissector in Decode As wins" */
1817         *pref->varp.uint = value;
1818         break;
1819     case PREF_DECODE_AS_RANGE:
1820         if (replace)
1821         {
1822             /* If range has single value, replace it */
1823             if (((*pref->varp.range)->nranges == 1) &&
1824                 ((*pref->varp.range)->ranges[0].low == (*pref->varp.range)->ranges[0].high)) {
1825                 wmem_free(wmem_epan_scope(), *pref->varp.range);
1826                 *pref->varp.range = range_empty(wmem_epan_scope());
1827             }
1828         }
1829
1830         prefs_range_add_value(pref, value);
1831         break;
1832     default:
1833         /* XXX - Worth asserting over? */
1834         break;
1835     }
1836
1837     return TRUE;
1838 }
1839
1840 gboolean prefs_remove_decode_as_value(pref_t *pref, guint value, gboolean set_default)
1841 {
1842     switch(pref->type)
1843     {
1844     case PREF_DECODE_AS_UINT:
1845         if (set_default) {
1846             *pref->varp.uint = pref->default_val.uint;
1847         } else {
1848             *pref->varp.uint = 0;
1849         }
1850         break;
1851     case PREF_DECODE_AS_RANGE:
1852         prefs_range_remove_value(pref, value);
1853         break;
1854     default:
1855         break;
1856     }
1857
1858     return TRUE;
1859 }
1860
1861 /*
1862  * Register a preference that used to be supported but no longer is.
1863  */
1864 void
1865 prefs_register_obsolete_preference(module_t *module, const char *name)
1866 {
1867     register_preference(module, name, NULL, NULL, PREF_OBSOLETE);
1868 }
1869
1870 /*
1871  * Check to see if a preference is obsolete.
1872  */
1873 extern gboolean
1874 prefs_get_preference_obsolete(pref_t *pref)
1875 {
1876     if (pref)
1877         return (IS_PREF_OBSOLETE(pref->type) ? TRUE : FALSE);
1878
1879     return TRUE;
1880 }
1881
1882 /*
1883  * Make a preference obsolete.
1884  */
1885 extern prefs_set_pref_e
1886 prefs_set_preference_obsolete(pref_t *pref)
1887 {
1888     if (pref) {
1889         SET_PREF_OBSOLETE(pref->type);
1890         return PREFS_SET_OK;
1891     }
1892     return PREFS_SET_NO_SUCH_PREF;
1893 }
1894
1895 guint
1896 pref_stash(pref_t *pref, gpointer unused _U_)
1897 {
1898     switch (pref->type) {
1899
1900     case PREF_DECODE_AS_UINT:
1901         pref->stashed_val.uint = *pref->varp.uint;
1902         break;
1903
1904     case PREF_UINT:
1905         pref->stashed_val.uint = *pref->varp.uint;
1906         break;
1907
1908     case PREF_BOOL:
1909         pref->stashed_val.boolval = *pref->varp.boolp;
1910         break;
1911
1912     case PREF_ENUM:
1913         pref->stashed_val.enumval = *pref->varp.enump;
1914         break;
1915
1916     case PREF_STRING:
1917     case PREF_FILENAME:
1918     case PREF_DIRNAME:
1919         g_free(pref->stashed_val.string);
1920         pref->stashed_val.string = g_strdup(*pref->varp.string);
1921         break;
1922
1923     case PREF_DECODE_AS_RANGE:
1924     case PREF_RANGE:
1925         wmem_free(wmem_epan_scope(), pref->stashed_val.range);
1926         pref->stashed_val.range = range_copy(wmem_epan_scope(), *pref->varp.range);
1927         break;
1928
1929     case PREF_COLOR:
1930         pref->stashed_val.color = *pref->varp.colorp;
1931         break;
1932
1933     case PREF_STATIC_TEXT:
1934     case PREF_UAT:
1935     case PREF_CUSTOM:
1936         break;
1937
1938     case PREF_OBSOLETE:
1939         g_assert_not_reached();
1940         break;
1941     }
1942     return 0;
1943 }
1944
1945 guint
1946 pref_unstash(pref_t *pref, gpointer unstash_data_p)
1947 {
1948     pref_unstash_data_t *unstash_data = (pref_unstash_data_t *)unstash_data_p;
1949     dissector_table_t sub_dissectors = NULL;
1950     dissector_handle_t handle = NULL;
1951
1952     /* Revert the preference to its saved value. */
1953     switch (pref->type) {
1954
1955     case PREF_DECODE_AS_UINT:
1956         if (*pref->varp.uint != pref->stashed_val.uint) {
1957             unstash_data->module->prefs_changed = TRUE;
1958
1959             if (unstash_data->handle_decode_as) {
1960                 if (*pref->varp.uint != pref->default_val.uint) {
1961                     dissector_reset_uint(pref->name, *pref->varp.uint);
1962                 }
1963             }
1964
1965             *pref->varp.uint = pref->stashed_val.uint;
1966
1967             if (unstash_data->handle_decode_as) {
1968                 sub_dissectors = find_dissector_table(pref->name);
1969                 if (sub_dissectors != NULL) {
1970                     handle = dissector_table_get_dissector_handle(sub_dissectors, (gchar*)unstash_data->module->title);
1971                     if (handle != NULL) {
1972                         dissector_change_uint(pref->name, *pref->varp.uint, handle);
1973                     }
1974                 }
1975             }
1976         }
1977         break;
1978
1979     case PREF_UINT:
1980         if (*pref->varp.uint != pref->stashed_val.uint) {
1981             unstash_data->module->prefs_changed = TRUE;
1982             *pref->varp.uint = pref->stashed_val.uint;
1983         }
1984         break;
1985
1986     case PREF_BOOL:
1987         if (*pref->varp.boolp != pref->stashed_val.boolval) {
1988             unstash_data->module->prefs_changed = TRUE;
1989             *pref->varp.boolp = pref->stashed_val.boolval;
1990         }
1991         break;
1992
1993     case PREF_ENUM:
1994         if (*pref->varp.enump != pref->stashed_val.enumval) {
1995             unstash_data->module->prefs_changed = TRUE;
1996             *pref->varp.enump = pref->stashed_val.enumval;
1997         }
1998         break;
1999
2000     case PREF_STRING:
2001     case PREF_FILENAME:
2002     case PREF_DIRNAME:
2003         if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0) {
2004             unstash_data->module->prefs_changed = TRUE;
2005             g_free(*pref->varp.string);
2006             *pref->varp.string = g_strdup(pref->stashed_val.string);
2007         }
2008         break;
2009
2010     case PREF_DECODE_AS_RANGE:
2011         if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2012             guint32 i, j;
2013             unstash_data->module->prefs_changed = TRUE;
2014
2015             if (unstash_data->handle_decode_as) {
2016                 sub_dissectors = find_dissector_table(pref->name);
2017                 if (sub_dissectors != NULL) {
2018                     handle = dissector_table_get_dissector_handle(sub_dissectors, (gchar*)unstash_data->module->title);
2019                     if (handle != NULL) {
2020                         /* Delete all of the old values from the dissector table */
2021                         for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2022                             for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2023                                 dissector_delete_uint(pref->name, j, handle);
2024                                 decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j), NULL, NULL);
2025                             }
2026
2027                             dissector_delete_uint(pref->name, (*pref->varp.range)->ranges[i].high, handle);
2028                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high), NULL, NULL);
2029                         }
2030                     }
2031                 }
2032             }
2033
2034             wmem_free(wmem_epan_scope(), *pref->varp.range);
2035             *pref->varp.range = range_copy(wmem_epan_scope(), pref->stashed_val.range);
2036
2037             if (unstash_data->handle_decode_as) {
2038                 if ((sub_dissectors != NULL) && (handle != NULL)) {
2039
2040                     /* Add new values to the dissector table */
2041                     for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2042
2043                         for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2044                             dissector_change_uint(pref->name, j, handle);
2045                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j), NULL, NULL);
2046                         }
2047
2048                         dissector_change_uint(pref->name, (*pref->varp.range)->ranges[i].high, handle);
2049                         decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high), NULL, NULL);
2050                     }
2051                 }
2052             }
2053         }
2054         break;
2055
2056     case PREF_RANGE:
2057         if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2058             unstash_data->module->prefs_changed = TRUE;
2059             wmem_free(wmem_epan_scope(), *pref->varp.range);
2060             *pref->varp.range = range_copy(wmem_epan_scope(), pref->stashed_val.range);
2061         }
2062     break;
2063
2064     case PREF_COLOR:
2065         *pref->varp.colorp = pref->stashed_val.color;
2066         break;
2067
2068     case PREF_STATIC_TEXT:
2069     case PREF_UAT:
2070     case PREF_CUSTOM:
2071         break;
2072
2073     case PREF_OBSOLETE:
2074         g_assert_not_reached();
2075         break;
2076     }
2077     return 0;
2078 }
2079
2080 void
2081 reset_stashed_pref(pref_t *pref) {
2082     switch (pref->type) {
2083
2084     case PREF_DECODE_AS_UINT:
2085         pref->stashed_val.uint = pref->default_val.uint;
2086         break;
2087
2088     case PREF_UINT:
2089         pref->stashed_val.uint = pref->default_val.uint;
2090         break;
2091
2092     case PREF_BOOL:
2093         pref->stashed_val.boolval = pref->default_val.boolval;
2094         break;
2095
2096     case PREF_ENUM:
2097         pref->stashed_val.enumval = pref->default_val.enumval;
2098         break;
2099
2100     case PREF_STRING:
2101     case PREF_FILENAME:
2102     case PREF_DIRNAME:
2103         g_free(pref->stashed_val.string);
2104         pref->stashed_val.string = g_strdup(pref->default_val.string);
2105         break;
2106
2107     case PREF_DECODE_AS_RANGE:
2108     case PREF_RANGE:
2109         wmem_free(wmem_epan_scope(), pref->stashed_val.range);
2110         pref->stashed_val.range = range_copy(wmem_epan_scope(), pref->default_val.range);
2111         break;
2112
2113     case PREF_COLOR:
2114         memcpy(&pref->stashed_val.color, &pref->default_val.color, sizeof(color_t));
2115         break;
2116
2117     case PREF_STATIC_TEXT:
2118     case PREF_UAT:
2119     case PREF_CUSTOM:
2120         break;
2121
2122     case PREF_OBSOLETE:
2123         g_assert_not_reached();
2124         break;
2125     }
2126 }
2127
2128 guint
2129 pref_clean_stash(pref_t *pref, gpointer unused _U_)
2130 {
2131     switch (pref->type) {
2132
2133     case PREF_UINT:
2134     case PREF_DECODE_AS_UINT:
2135         break;
2136
2137     case PREF_BOOL:
2138         break;
2139
2140     case PREF_ENUM:
2141         break;
2142
2143     case PREF_STRING:
2144     case PREF_FILENAME:
2145     case PREF_DIRNAME:
2146         if (pref->stashed_val.string != NULL) {
2147             g_free(pref->stashed_val.string);
2148             pref->stashed_val.string = NULL;
2149         }
2150         break;
2151
2152     case PREF_DECODE_AS_RANGE:
2153     case PREF_RANGE:
2154         if (pref->stashed_val.range != NULL) {
2155             wmem_free(wmem_epan_scope(), pref->stashed_val.range);
2156             pref->stashed_val.range = NULL;
2157         }
2158         break;
2159
2160     case PREF_STATIC_TEXT:
2161     case PREF_UAT:
2162     case PREF_COLOR:
2163     case PREF_CUSTOM:
2164         break;
2165
2166     case PREF_OBSOLETE:
2167         g_assert_not_reached();
2168         break;
2169     }
2170     return 0;
2171 }
2172
2173 #if 0
2174 /* Return the value assigned to the given uint preference. */
2175 guint
2176 prefs_get_uint_preference(pref_t *pref)
2177 {
2178     if (pref && pref->type == PREF_UINT)
2179         return *pref->varp.uint;
2180     return 0;
2181 }
2182 #endif
2183
2184 /*
2185  * Call a callback function, with a specified argument, for each preference
2186  * in a given module.
2187  *
2188  * If any of the callbacks return a non-zero value, stop and return that
2189  * value, otherwise return 0.
2190  */
2191 guint
2192 prefs_pref_foreach(module_t *module, pref_cb callback, gpointer user_data)
2193 {
2194     GList *elem;
2195     pref_t *pref;
2196     guint ret;
2197
2198     for (elem = g_list_first(module->prefs); elem != NULL; elem = g_list_next(elem)) {
2199         pref = (pref_t *)elem->data;
2200         if (IS_PREF_OBSOLETE(pref->type)) {
2201             /*
2202              * This preference is no longer supported; it's
2203              * not a real preference, so we don't call the
2204              * callback for it (i.e., we treat it as if it
2205              * weren't found in the list of preferences,
2206              * and we weren't called in the first place).
2207              */
2208             continue;
2209         }
2210
2211         ret = (*callback)(pref, user_data);
2212         if (ret != 0)
2213             return ret;
2214     }
2215     return 0;
2216 }
2217
2218 static const enum_val_t print_format_vals[] = {
2219     { "text",       "Plain Text", PR_FMT_TEXT },
2220     { "postscript", "Postscript", PR_FMT_PS },
2221     { NULL,         NULL,         0 }
2222 };
2223
2224 static const enum_val_t print_dest_vals[] = {
2225 #ifdef _WIN32
2226     /* "PR_DEST_CMD" means "to printer" on Windows */
2227     { "command", "Printer", PR_DEST_CMD },
2228 #else
2229     { "command", "Command", PR_DEST_CMD },
2230 #endif
2231     { "file",    "File",    PR_DEST_FILE },
2232     { NULL,      NULL,      0 }
2233 };
2234
2235 static const enum_val_t st_sort_col_vals[] = {
2236     { "name",    "Node name (topic/item)", ST_SORT_COL_NAME },
2237     { "count",   "Item count", ST_SORT_COL_COUNT },
2238     { "average", "Average value of the node", ST_SORT_COL_AVG },
2239     { "min",     "Minimum value of the node", ST_SORT_COL_MIN },
2240     { "max",     "Maximum value of the node", ST_SORT_COL_MAX },
2241     { "burst",   "Burst rate of the node", ST_SORT_COL_BURSTRATE },
2242     { NULL,      NULL,         0 }
2243 };
2244
2245 static void
2246 stats_callback(void)
2247 {
2248     /* Test for a sane tap update interval */
2249     if (prefs.tap_update_interval < 100 || prefs.tap_update_interval > 10000)
2250         prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL;
2251
2252 #ifdef HAVE_LIBPORTAUDIO
2253     /* Test for a sane max channels entry */
2254     if (prefs.rtp_player_max_visible < 1 || prefs.rtp_player_max_visible > 10)
2255         prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE;
2256 #endif
2257
2258     /* burst resolution can't be less than 1 (ms) */
2259     if (prefs.st_burst_resolution < 1) {
2260         prefs.st_burst_resolution = 1;
2261     }
2262     else if (prefs.st_burst_resolution > ST_MAX_BURSTRES) {
2263         prefs.st_burst_resolution = ST_MAX_BURSTRES;
2264     }
2265     /* make sure burst window value makes sense */
2266     if (prefs.st_burst_windowlen < prefs.st_burst_resolution) {
2267         prefs.st_burst_windowlen = prefs.st_burst_resolution;
2268     }
2269     /* round burst window down to multiple of resolution */
2270     prefs.st_burst_windowlen -= prefs.st_burst_windowlen%prefs.st_burst_resolution;
2271     if ((prefs.st_burst_windowlen/prefs.st_burst_resolution) > ST_MAX_BURSTBUCKETS) {
2272         prefs.st_burst_windowlen = prefs.st_burst_resolution*ST_MAX_BURSTBUCKETS;
2273     }
2274 }
2275
2276 static void
2277 gui_callback(void)
2278 {
2279     /* Ensure there is at least one file count */
2280     if (prefs.gui_recent_files_count_max == 0)
2281       prefs.gui_recent_files_count_max = 10;
2282
2283     /* Ensure there is at least one display filter entry */
2284     if (prefs.gui_recent_df_entries_max == 0)
2285       prefs.gui_recent_df_entries_max = 10;
2286 }
2287
2288 static void
2289 gui_layout_callback(void)
2290 {
2291     if (prefs.gui_layout_type == layout_unused ||
2292         prefs.gui_layout_type >= layout_type_max) {
2293       /* XXX - report an error?  It's not a syntax error - we'd need to
2294          add a way of reporting a *semantic* error. */
2295       prefs.gui_layout_type = layout_type_5;
2296     }
2297 }
2298
2299 /******************************************************
2300  * All custom preference function callbacks
2301  ******************************************************/
2302 static void custom_pref_no_cb(pref_t* pref _U_) {}
2303
2304
2305 /*
2306  * Console log level custom preference functions
2307  */
2308 static void
2309 console_log_level_reset_cb(pref_t* pref)
2310 {
2311     *pref->varp.uint = pref->default_val.uint;
2312 }
2313
2314 static prefs_set_pref_e
2315 console_log_level_set_cb(pref_t* pref, const gchar* value, gboolean* changed)
2316 {
2317     guint    uval;
2318
2319     uval = (guint)strtoul(value, NULL, 10);
2320
2321     if (*pref->varp.uint != uval) {
2322         *changed = TRUE;
2323         *pref->varp.uint = uval;
2324     }
2325
2326     if (*pref->varp.uint & (G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG)) {
2327       /*
2328        * GLib >= 2.32 drops INFO and DEBUG messages by default. Tell
2329        * it not to do that.
2330        */
2331        g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
2332     }
2333
2334     return PREFS_SET_OK;
2335 }
2336
2337 static const char * console_log_level_type_name_cb(void) {
2338     return "Log level";
2339 }
2340
2341 static char * console_log_level_type_description_cb(void) {
2342     return g_strdup_printf(
2343         "Console log level (for debugging)\n"
2344         "A bitmask of log levels:\n"
2345         "ERROR    = 4\n"
2346         "CRITICAL = 8\n"
2347         "WARNING  = 16\n"
2348         "MESSAGE  = 32\n"
2349         "INFO     = 64\n"
2350         "DEBUG    = 128");
2351 }
2352
2353 static gboolean console_log_level_is_default_cb(pref_t* pref) {
2354     return *pref->varp.uint == pref->default_val.uint;
2355 }
2356
2357 static char * console_log_level_to_str_cb(pref_t* pref, gboolean default_val) {
2358     return g_strdup_printf("%u",  default_val ? pref->default_val.uint : *pref->varp.uint);
2359 }
2360
2361 /*
2362  * Column preference functions
2363  */
2364 #define PRS_COL_HIDDEN                   "column.hidden"
2365 #define PRS_COL_FMT                      "column.format"
2366 #define PRS_COL_NUM                      "column.number"
2367 static module_t *gui_column_module = NULL;
2368
2369 static prefs_set_pref_e
2370 column_hidden_set_cb(pref_t* pref, const gchar* value, gboolean* changed)
2371 {
2372     GList       *clp;
2373     fmt_data    *cfmt;
2374     pref_t  *format_pref;
2375
2376     (*changed) |= prefs_set_string_value(pref, value, pref_current);
2377
2378     /*
2379      * Set the "visible" flag for the existing columns; we need to
2380      * do this if we set PRS_COL_HIDDEN but don't set PRS_COL_FMT
2381      * after setting it (which might be the case if, for example, we
2382      * set PRS_COL_HIDDEN on the command line).
2383      */
2384     format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT);
2385     for (clp = *format_pref->varp.list; clp != NULL; clp = clp->next) {
2386       cfmt = (fmt_data *)clp->data;
2387       cfmt->visible = prefs_is_column_visible(*pref->varp.string, cfmt);
2388     }
2389
2390     return PREFS_SET_OK;
2391 }
2392
2393 static const char *
2394 column_hidden_type_name_cb(void)
2395 {
2396     return "Packet list hidden columns";
2397 }
2398
2399 static char *
2400 column_hidden_type_description_cb(void)
2401 {
2402     return g_strdup("List all columns to hide in the packet list.");
2403 }
2404
2405 static char *
2406 column_hidden_to_str_cb(pref_t* pref, gboolean default_val)
2407 {
2408     GString     *cols_hidden = g_string_new ("");
2409     GList       *clp;
2410     fmt_data    *cfmt;
2411     pref_t  *format_pref;
2412
2413     if (default_val)
2414         return g_strdup(pref->default_val.string);
2415
2416     format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT);
2417     clp = (format_pref) ? *format_pref->varp.list : NULL;
2418     while (clp) {
2419         gchar *prefs_fmt;
2420         cfmt = (fmt_data *) clp->data;
2421         if ((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) {
2422             prefs_fmt = g_strdup_printf("%s:%s:%d:%c",
2423                     col_format_to_string(cfmt->fmt),
2424                     cfmt->custom_fields,
2425                     cfmt->custom_occurrence,
2426                     cfmt->resolved ? 'R' : 'U');
2427         } else {
2428             prefs_fmt = g_strdup(col_format_to_string(cfmt->fmt));
2429         }
2430         if (!cfmt->visible) {
2431             if (cols_hidden->len)
2432                 g_string_append (cols_hidden, ",");
2433             g_string_append (cols_hidden, prefs_fmt);
2434         }
2435         g_free(prefs_fmt);
2436         clp = clp->next;
2437     }
2438
2439     return g_string_free (cols_hidden, FALSE);
2440 }
2441
2442 static gboolean
2443 column_hidden_is_default_cb(pref_t* pref)
2444 {
2445     char *cur_hidden_str = column_hidden_to_str_cb(pref, FALSE);
2446     gboolean is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2447
2448     g_free(cur_hidden_str);
2449     return is_default;
2450 }
2451
2452
2453 /* Number of columns "preference".  This is only used internally and is not written to the
2454  * preference file
2455  */
2456 static void
2457 column_num_reset_cb(pref_t* pref)
2458 {
2459     *pref->varp.uint = pref->default_val.uint;
2460 }
2461
2462 static prefs_set_pref_e
2463 column_num_set_cb(pref_t* pref _U_, const gchar* value _U_, gboolean* changed _U_)
2464 {
2465     /* Don't write this to the preferences file */
2466     return PREFS_SET_OK;
2467 }
2468
2469 static const char *
2470 column_num_type_name_cb(void)
2471 {
2472     return NULL;
2473 }
2474
2475 static char *
2476 column_num_type_description_cb(void)
2477 {
2478     return g_strdup("");
2479 }
2480
2481 static gboolean
2482 column_num_is_default_cb(pref_t* pref _U_)
2483 {
2484     return TRUE;
2485 }
2486
2487 static char *
2488 column_num_to_str_cb(pref_t* pref _U_, gboolean default_val _U_)
2489 {
2490     return g_strdup("");
2491 }
2492
2493 /*
2494  * Column format custom preference functions
2495  */
2496 static void
2497 column_format_init_cb(pref_t* pref, GList** value)
2498 {
2499     fmt_data *src_cfmt, *dest_cfmt;
2500     GList *entry;
2501
2502     pref->varp.list = value;
2503
2504     pref->default_val.list = NULL;
2505     for (entry = *pref->varp.list; entry != NULL; entry = g_list_next(entry)) {
2506         src_cfmt = (fmt_data *)entry->data;
2507         dest_cfmt = g_new(fmt_data,1);
2508         dest_cfmt->title = g_strdup(src_cfmt->title);
2509         dest_cfmt->fmt = src_cfmt->fmt;
2510         if (src_cfmt->custom_fields) {
2511             dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields);
2512             dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2513         } else {
2514             dest_cfmt->custom_fields = NULL;
2515             dest_cfmt->custom_occurrence = 0;
2516         }
2517         dest_cfmt->visible = src_cfmt->visible;
2518         dest_cfmt->resolved = src_cfmt->resolved;
2519         pref->default_val.list = g_list_append(pref->default_val.list, dest_cfmt);
2520     }
2521 }
2522
2523 static void
2524 column_format_free_cb(pref_t* pref)
2525 {
2526     free_col_info(*pref->varp.list);
2527     free_col_info(pref->default_val.list);
2528 }
2529
2530 static void
2531 column_format_reset_cb(pref_t* pref)
2532 {
2533     fmt_data *src_cfmt, *dest_cfmt;
2534     GList *entry;
2535     pref_t  *col_num_pref;
2536
2537     free_col_info(*pref->varp.list);
2538     *pref->varp.list = NULL;
2539
2540     for (entry = pref->default_val.list; entry != NULL; entry = g_list_next(entry)) {
2541         src_cfmt = (fmt_data *)entry->data;
2542         dest_cfmt = g_new(fmt_data,1);
2543         dest_cfmt->title = g_strdup(src_cfmt->title);
2544         dest_cfmt->fmt = src_cfmt->fmt;
2545         if (src_cfmt->custom_fields) {
2546             dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields);
2547             dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2548         } else {
2549             dest_cfmt->custom_fields = NULL;
2550             dest_cfmt->custom_occurrence = 0;
2551         }
2552         dest_cfmt->visible = src_cfmt->visible;
2553         dest_cfmt->resolved = src_cfmt->resolved;
2554         *pref->varp.list = g_list_append(*pref->varp.list, dest_cfmt);
2555     }
2556
2557     col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
2558     g_assert(col_num_pref != NULL); /* Should never happen */
2559     column_num_reset_cb(col_num_pref);
2560 }
2561
2562 static prefs_set_pref_e
2563 column_format_set_cb(pref_t* pref, const gchar* value, gboolean* changed _U_)
2564 {
2565     GList    *col_l, *col_l_elt;
2566     fmt_data *cfmt;
2567     gint     llen;
2568     pref_t   *hidden_pref, *col_num_pref;
2569
2570     col_l = prefs_get_string_list(value);
2571     if (col_l == NULL)
2572       return PREFS_SET_SYNTAX_ERR;
2573     if ((g_list_length(col_l) % 2) != 0) {
2574       /* A title didn't have a matching format.  */
2575       prefs_clear_string_list(col_l);
2576       return PREFS_SET_SYNTAX_ERR;
2577     }
2578     /* Check to make sure all column formats are valid.  */
2579     col_l_elt = g_list_first(col_l);
2580     while (col_l_elt) {
2581       fmt_data cfmt_check;
2582
2583       /* Go past the title.  */
2584       col_l_elt = col_l_elt->next;
2585
2586       /* Parse the format to see if it's valid.  */
2587       if (!parse_column_format(&cfmt_check, (char *)col_l_elt->data)) {
2588         /* It's not a valid column format.  */
2589         prefs_clear_string_list(col_l);
2590         return PREFS_SET_SYNTAX_ERR;
2591       }
2592       if (cfmt_check.fmt != COL_CUSTOM) {
2593         /* Some predefined columns have been migrated to use custom columns.
2594          * We'll convert these silently here */
2595         try_convert_to_custom_column(&col_l_elt->data);
2596       } else {
2597         /* We don't need the custom column field on this pass. */
2598         g_free(cfmt_check.custom_fields);
2599       }
2600
2601       /* Go past the format.  */
2602       col_l_elt = col_l_elt->next;
2603     }
2604
2605     /* They're all valid; process them. */
2606     free_col_info(*pref->varp.list);
2607     *pref->varp.list = NULL;
2608     hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN);
2609     g_assert(hidden_pref != NULL); /* Should never happen */
2610     col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
2611     g_assert(col_num_pref != NULL); /* Should never happen */
2612     llen             = g_list_length(col_l);
2613     *col_num_pref->varp.uint = llen / 2;
2614     col_l_elt = g_list_first(col_l);
2615     while (col_l_elt) {
2616       cfmt           = g_new(fmt_data,1);
2617       cfmt->title    = g_strdup((gchar *)col_l_elt->data);
2618       col_l_elt      = col_l_elt->next;
2619       parse_column_format(cfmt, (char *)col_l_elt->data);
2620       cfmt->visible   = prefs_is_column_visible(*hidden_pref->varp.string, cfmt);
2621       col_l_elt      = col_l_elt->next;
2622       *pref->varp.list = g_list_append(*pref->varp.list, cfmt);
2623     }
2624
2625     prefs_clear_string_list(col_l);
2626     free_string_like_preference(hidden_pref);
2627     return PREFS_SET_OK;
2628 }
2629
2630
2631 static const char *
2632 column_format_type_name_cb(void)
2633 {
2634     return "Packet list column format";
2635 }
2636
2637 static char *
2638 column_format_type_description_cb(void)
2639 {
2640     return g_strdup("Each pair of strings consists of a column title and its format");
2641 }
2642
2643 static gboolean
2644 column_format_is_default_cb(pref_t* pref)
2645 {
2646     GList       *clp = *pref->varp.list,
2647                 *pref_col = g_list_first(clp),
2648                 *def_col = g_list_first(pref->default_val.list);
2649     fmt_data    *cfmt, *def_cfmt;
2650     gboolean    is_default = TRUE;
2651     pref_t      *col_num_pref;
2652
2653     /* See if the column data has changed from the default */
2654     col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
2655     if (col_num_pref && *col_num_pref->varp.uint != col_num_pref->default_val.uint) {
2656         is_default = FALSE;
2657     } else {
2658         while (pref_col && def_col) {
2659             cfmt = (fmt_data *) pref_col->data;
2660             def_cfmt = (fmt_data *) def_col->data;
2661             if ((g_strcmp0(cfmt->title, def_cfmt->title) != 0) ||
2662                     (cfmt->fmt != def_cfmt->fmt) ||
2663                     (((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) &&
2664                      ((g_strcmp0(cfmt->custom_fields, def_cfmt->custom_fields) != 0) ||
2665                       (cfmt->resolved != def_cfmt->resolved)))) {
2666                 is_default = FALSE;
2667                 break;
2668             }
2669
2670             pref_col = pref_col->next;
2671             def_col = def_col->next;
2672         }
2673     }
2674
2675     return is_default;
2676 }
2677
2678 static char *
2679 column_format_to_str_cb(pref_t* pref, gboolean default_val)
2680 {
2681     GList       *pref_l = default_val ? pref->default_val.list : *pref->varp.list;
2682     GList       *clp = g_list_first(pref_l);
2683     GList       *col_l;
2684     fmt_data    *cfmt;
2685     gchar       *prefs_fmt;
2686     char        *column_format_str;
2687
2688     col_l = NULL;
2689     while (clp) {
2690         cfmt = (fmt_data *) clp->data;
2691         col_l = g_list_append(col_l, g_strdup(cfmt->title));
2692         if ((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) {
2693             prefs_fmt = g_strdup_printf("%s:%s:%d:%c",
2694                     col_format_to_string(cfmt->fmt),
2695                     cfmt->custom_fields,
2696                     cfmt->custom_occurrence,
2697                     cfmt->resolved ? 'R' : 'U');
2698         } else {
2699             prefs_fmt = g_strdup(col_format_to_string(cfmt->fmt));
2700         }
2701         col_l = g_list_append(col_l, prefs_fmt);
2702         clp = clp->next;
2703     }
2704
2705     column_format_str = join_string_list(col_l);
2706     prefs_clear_string_list(col_l);
2707     return column_format_str;
2708 }
2709
2710
2711 /******  Capture column custom preference functions  ******/
2712
2713 /* This routine is only called when Wireshark is started, NOT when another profile is selected.
2714    Copy the pref->capture_columns list (just loaded with the capture_cols[] struct values)
2715    to prefs->default_val.list.
2716 */
2717 static void
2718 capture_column_init_cb(pref_t* pref, GList** capture_cols_values)
2719 {
2720     GList   *ccv_list = *capture_cols_values,
2721             *dlist = NULL;
2722
2723     /*  */
2724     while (ccv_list) {
2725         dlist = g_list_append(dlist, g_strdup((gchar *)ccv_list->data));
2726         ccv_list = ccv_list->next;
2727     }
2728
2729     pref->default_val.list = dlist;
2730     pref->varp.list = &prefs.capture_columns;
2731     pref->stashed_val.boolval = FALSE;
2732 }
2733
2734 /* Free the prefs->capture_columns list strings and remove the list entries.
2735    Note that since pref->varp.list points to &prefs.capture_columns, it is
2736    also freed.
2737 */
2738 static void
2739 capture_column_free_cb(pref_t* pref)
2740 {
2741     prefs_clear_string_list(prefs.capture_columns);
2742     prefs.capture_columns = NULL;
2743
2744     if (pref->stashed_val.boolval == TRUE) {
2745       prefs_clear_string_list(pref->default_val.list);
2746       pref->default_val.list = NULL;
2747     }
2748 }
2749
2750 /* Copy pref->default_val.list to *pref->varp.list.
2751 */
2752 static void
2753 capture_column_reset_cb(pref_t* pref)
2754 {
2755     GList *vlist = NULL, *dlist;
2756
2757     /* Free the column name strings and remove the links from *pref->varp.list */
2758     prefs_clear_string_list(*pref->varp.list);
2759
2760     for (dlist = pref->default_val.list; dlist != NULL; dlist = g_list_next(dlist)) {
2761       vlist = g_list_append(vlist, g_strdup((gchar *)dlist->data));
2762     }
2763     *pref->varp.list = vlist;
2764 }
2765
2766 static prefs_set_pref_e
2767 capture_column_set_cb(pref_t* pref, const gchar* value, gboolean* changed _U_)
2768 {
2769     GList *col_l  = prefs_get_string_list(value);
2770     GList *col_l_elt;
2771     gchar *col_name;
2772     int i;
2773
2774     if (col_l == NULL)
2775       return PREFS_SET_SYNTAX_ERR;
2776
2777     capture_column_free_cb(pref);
2778
2779     /* If value (the list of capture.columns read from preferences) is empty, set capture.columns
2780        to the full list of valid capture column names. */
2781     col_l_elt = g_list_first(col_l);
2782     if (!(*(gchar *)col_l_elt->data)) {
2783         for (i = 0; i < num_capture_cols; i++) {
2784           col_name = g_strdup(capture_cols[i]);
2785           prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
2786         }
2787     }
2788
2789     /* Verify that all the column names are valid. If not, use the entire list of valid columns.
2790      */
2791     while (col_l_elt) {
2792       gboolean found_match = FALSE;
2793       col_name = (gchar *)col_l_elt->data;
2794
2795       for (i = 0; i < num_capture_cols; i++) {
2796         if (strcmp(col_name, capture_cols[i])==0) {
2797           found_match = TRUE;
2798           break;
2799         }
2800       }
2801       if (!found_match) {
2802         /* One or more cols are invalid so use the entire list of valid cols. */
2803         for (i = 0; i < num_capture_cols; i++) {
2804           col_name = g_strdup(capture_cols[i]);
2805           prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
2806         }
2807         pref->varp.list = &prefs.capture_columns;
2808         prefs_clear_string_list(col_l);
2809         return PREFS_SET_SYNTAX_ERR;
2810       }
2811       col_l_elt = col_l_elt->next;
2812     }
2813
2814     col_l_elt = g_list_first(col_l);
2815     while (col_l_elt) {
2816       col_name = (gchar *)col_l_elt->data;
2817       prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
2818       col_l_elt = col_l_elt->next;
2819     }
2820     pref->varp.list = &prefs.capture_columns;
2821     g_list_free(col_l);
2822     return PREFS_SET_OK;
2823 }
2824
2825
2826 static const char *
2827 capture_column_type_name_cb(void)
2828 {
2829     return "Column list";
2830 }
2831
2832 static char *
2833 capture_column_type_description_cb(void)
2834 {
2835     return g_strdup(
2836         "List of columns to be displayed in the capture options dialog.\n"
2837         CAPTURE_COL_TYPE_DESCRIPTION);
2838 }
2839
2840 static gboolean
2841 capture_column_is_default_cb(pref_t* pref)
2842 {
2843     GList   *pref_col = g_list_first(prefs.capture_columns),
2844             *def_col = g_list_first(pref->default_val.list);
2845     gboolean is_default = TRUE;
2846
2847     /* See if the column data has changed from the default */
2848     while (pref_col && def_col) {
2849         if (strcmp((gchar *)pref_col->data, (gchar *)def_col->data) != 0) {
2850             is_default = FALSE;
2851             break;
2852         }
2853         pref_col = pref_col->next;
2854         def_col = def_col->next;
2855     }
2856
2857     /* Ensure the same column count */
2858     if (((pref_col == NULL) && (def_col != NULL)) ||
2859         ((pref_col != NULL) && (def_col == NULL)))
2860         is_default = FALSE;
2861
2862     return is_default;
2863 }
2864
2865 static char *
2866 capture_column_to_str_cb(pref_t* pref, gboolean default_val)
2867 {
2868
2869     GList       *pref_l = default_val ? pref->default_val.list : prefs.capture_columns;
2870     GList       *clp = g_list_first(pref_l);
2871     GList       *col_l = NULL;
2872     gchar       *col;
2873     char        *capture_column_str;
2874
2875     while (clp) {
2876         col = (gchar *) clp->data;
2877         col_l = g_list_append(col_l, g_strdup(col));
2878         clp = clp->next;
2879     }
2880
2881     capture_column_str = join_string_list(col_l);
2882     prefs_clear_string_list(col_l);
2883     return capture_column_str;
2884 }
2885
2886 static prefs_set_pref_e
2887 colorized_frame_set_cb(pref_t* pref, const gchar* value, gboolean* changed)
2888 {
2889     (*changed) |= prefs_set_string_value(pref, value, pref_current);
2890     return PREFS_SET_OK;
2891 }
2892
2893 static const char *
2894 colorized_frame_type_name_cb(void)
2895 {
2896    /* Don't write the colors of the 10 easy-access-colorfilters to the preferences
2897     * file until the colors can be changed in the GUI. Currently this is not really
2898     * possible since the STOCK-icons for these colors are hardcoded.
2899     *
2900     * XXX Find a way to change the colors of the STOCK-icons on the fly and then
2901     *     add these 10 colors to the list of colors that can be changed through
2902     *     the preferences.
2903     *
2904     */
2905     return NULL;
2906 }
2907
2908 static char *
2909 colorized_frame_type_description_cb(void)
2910 {
2911     return g_strdup("");
2912 }
2913
2914 static gboolean
2915 colorized_frame_is_default_cb(pref_t* pref _U_)
2916 {
2917     return TRUE;
2918 }
2919
2920 static char *
2921 colorized_frame_to_str_cb(pref_t* pref _U_, gboolean default_val _U_)
2922 {
2923     return g_strdup("");
2924 }
2925
2926 /*
2927  * Register all non-dissector modules' preferences.
2928  */
2929 static module_t *gui_module = NULL;
2930 static module_t *gui_color_module = NULL;
2931 static module_t *nameres_module = NULL;
2932
2933 static void
2934 prefs_register_modules(void)
2935 {
2936     module_t *printing, *capture_module, *console_module,
2937         *gui_layout_module, *gui_font_module;
2938 #ifdef HAVE_EXTCAP
2939     module_t *extcap_module;
2940 #endif
2941
2942     struct pref_custom_cbs custom_cbs;
2943
2944     if (protocols_module != NULL) {
2945         /* Already setup preferences */
2946         return;
2947     }
2948
2949 #ifdef HAVE_EXTCAP
2950     /* GUI
2951      * These are "simple" GUI preferences that can be read/written using the
2952      * preference module API.  These preferences still use their own
2953      * configuration screens for access, but this cuts down on the
2954      * preference "string compare list" in set_pref()
2955      */
2956     extcap_module = prefs_register_module(NULL, "extcap", "Extcap Utilities",
2957         "Extcap Utilities", NULL, FALSE);
2958
2959     /* Setting default value to true */
2960     prefs.extcap_save_on_start = TRUE;
2961     prefs_register_bool_preference(extcap_module, "gui_save_on_start",
2962                                    "Save arguments on start of capture",
2963                                    "Save arguments on start of capture",
2964                                    &prefs.extcap_save_on_start);
2965 #endif
2966
2967     /* GUI
2968      * These are "simple" GUI preferences that can be read/written using the
2969      * preference module API.  These preferences still use their own
2970      * configuration screens for access, but this cuts down on the
2971      * preference "string compare list" in set_pref()
2972      */
2973     gui_module = prefs_register_module(NULL, "gui", "User Interface",
2974         "User Interface", &gui_callback, FALSE);
2975
2976     /* gui.console_open is placed first in the list so that any problems encountered
2977      *  in the following prefs can be displayed in the console window.
2978      */
2979     prefs_register_enum_preference(gui_module, "console_open",
2980                        "Open a console window",
2981                        "Open a console window (Windows only)",
2982                        (gint*)(void*)(&prefs.gui_console_open), gui_console_open_type, FALSE);
2983
2984     prefs_register_obsolete_preference(gui_module, "scrollbar_on_right");
2985     prefs_register_obsolete_preference(gui_module, "packet_list_sel_browse");
2986     prefs_register_obsolete_preference(gui_module, "protocol_tree_sel_browse");
2987
2988     prefs_register_bool_preference(gui_module, "tree_view_altern_colors",
2989                                    "Alternating colors in TreeViews",
2990                                    "Alternating colors in TreeViews?",
2991                                    &prefs.gui_altern_colors);
2992
2993     prefs_register_bool_preference(gui_module, "expert_composite_eyecandy",
2994                                    "Display Icons on Expert Composite Dialog Tabs",
2995                                    "Display Icons on Expert Composite Dialog Tabs?",
2996                                    &prefs.gui_expert_composite_eyecandy);
2997
2998     prefs_register_bool_preference(gui_module, "filter_toolbar_show_in_statusbar",
2999                                    "Place filter toolbar inside the statusbar",
3000                                    "Place filter toolbar inside the statusbar?",
3001                                    &prefs.filter_toolbar_show_in_statusbar);
3002
3003     prefs_register_enum_preference(gui_module, "protocol_tree_line_style",
3004                        "Protocol-tree line style",
3005                        "Protocol-tree line style",
3006                        &prefs.gui_ptree_line_style, gui_ptree_line_style, FALSE);
3007
3008     prefs_register_enum_preference(gui_module, "protocol_tree_expander_style",
3009                        "Protocol-tree expander style",
3010                        "Protocol-tree expander style",
3011                        &prefs.gui_ptree_expander_style, gui_ptree_expander_style, FALSE);
3012
3013     prefs_register_enum_preference(gui_module, "hex_dump_highlight_style",
3014                        "Hex dump highlight style",
3015                        "Hex dump highlight style",
3016                        &prefs.gui_hex_dump_highlight_style, gui_hex_dump_highlight_style, FALSE);
3017
3018     gui_column_module = prefs_register_subtree(gui_module, "Columns", "Columns", NULL);
3019
3020     custom_cbs.free_cb = free_string_like_preference;
3021     custom_cbs.reset_cb = reset_string_like_preference;
3022     custom_cbs.set_cb = column_hidden_set_cb;
3023     custom_cbs.type_name_cb = column_hidden_type_name_cb;
3024     custom_cbs.type_description_cb = column_hidden_type_description_cb;
3025     custom_cbs.is_default_cb = column_hidden_is_default_cb;
3026     custom_cbs.to_str_cb = column_hidden_to_str_cb;
3027     register_string_like_preference(gui_column_module, PRS_COL_HIDDEN, "Packet list hidden columns",
3028         "List all columns to hide in the packet list",
3029         &cols_hidden_list, PREF_CUSTOM, &custom_cbs, FALSE);
3030
3031     custom_cbs.free_cb = column_format_free_cb;
3032     custom_cbs.reset_cb = column_format_reset_cb;
3033     custom_cbs.set_cb = column_format_set_cb;
3034     custom_cbs.type_name_cb = column_format_type_name_cb;
3035     custom_cbs.type_description_cb = column_format_type_description_cb;
3036     custom_cbs.is_default_cb = column_format_is_default_cb;
3037     custom_cbs.to_str_cb = column_format_to_str_cb;
3038
3039     prefs_register_list_custom_preference(gui_column_module, PRS_COL_FMT, "Packet list column format",
3040         "Each pair of strings consists of a column title and its format", &custom_cbs,
3041         column_format_init_cb, &prefs.col_list);
3042
3043     /* Number of columns.  This is only used internally and is not written to the
3044      * preference file
3045      */
3046     custom_cbs.free_cb = custom_pref_no_cb;
3047     custom_cbs.reset_cb = column_num_reset_cb;
3048     custom_cbs.set_cb = column_num_set_cb;
3049     custom_cbs.type_name_cb = column_num_type_name_cb;
3050     custom_cbs.type_description_cb = column_num_type_description_cb;
3051     custom_cbs.is_default_cb = column_num_is_default_cb;
3052     custom_cbs.to_str_cb = column_num_to_str_cb;
3053     prefs_register_uint_custom_preference(gui_column_module, PRS_COL_NUM, "Number of columns",
3054         "Number of columns in col_list", &custom_cbs, &prefs.num_cols);
3055
3056     /* User Interface : Font */
3057     gui_font_module = prefs_register_subtree(gui_module, "Font", "Font", NULL);
3058
3059     prefs_register_obsolete_preference(gui_font_module, "font_name");
3060
3061     register_string_like_preference(gui_font_module, "gtk2.font_name", "Font name",
3062         "Font name for packet list, protocol tree, and hex dump panes. (GTK+)",
3063         &prefs.gui_gtk2_font_name, PREF_STRING, NULL, TRUE);
3064
3065     register_string_like_preference(gui_font_module, "qt.font_name", "Font name",
3066         "Font name for packet list, protocol tree, and hex dump panes. (Qt)",
3067         &prefs.gui_qt_font_name, PREF_STRING, NULL, TRUE);
3068
3069     /* User Interface : Colors */
3070     gui_color_module = prefs_register_subtree(gui_module, "Colors", "Colors", NULL);
3071
3072     prefs_register_color_preference(gui_color_module, "marked_frame.fg", "Color preferences for a marked frame",
3073         "Color preferences for a marked frame", &prefs.gui_marked_fg);
3074
3075     prefs_register_color_preference(gui_color_module, "marked_frame.bg", "Color preferences for a marked frame",
3076         "Color preferences for a marked frame", &prefs.gui_marked_bg);
3077
3078     prefs_register_color_preference(gui_color_module, "ignored_frame.fg", "Color preferences for a ignored frame",
3079         "Color preferences for a ignored frame", &prefs.gui_ignored_fg);
3080
3081     prefs_register_color_preference(gui_color_module, "ignored_frame.bg", "Color preferences for a ignored frame",
3082         "Color preferences for a ignored frame", &prefs.gui_ignored_bg);
3083
3084     prefs_register_color_preference(gui_color_module, "stream.client.fg", "TCP stream window color preference",
3085         "TCP stream window color preference", &prefs.st_client_fg);
3086
3087     prefs_register_color_preference(gui_color_module, "stream.client.bg", "TCP stream window color preference",
3088         "TCP stream window color preference", &prefs.st_client_bg);
3089
3090     prefs_register_color_preference(gui_color_module, "stream.server.fg", "TCP stream window color preference",
3091         "TCP stream window color preference", &prefs.st_server_fg);
3092
3093     prefs_register_color_preference(gui_color_module, "stream.server.bg", "TCP stream window color preference",
3094         "TCP stream window color preference", &prefs.st_server_bg);
3095
3096     custom_cbs.free_cb = free_string_like_preference;
3097     custom_cbs.reset_cb = reset_string_like_preference;
3098     custom_cbs.set_cb = colorized_frame_set_cb;
3099     custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3100     custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3101     custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3102     custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3103     register_string_like_preference(gui_column_module, "colorized_frame.fg", "Colorized Foreground",
3104         "Filter Colorized Foreground",
3105         &prefs.gui_colorized_fg, PREF_CUSTOM, &custom_cbs, TRUE);
3106
3107     custom_cbs.free_cb = free_string_like_preference;
3108     custom_cbs.reset_cb = reset_string_like_preference;
3109     custom_cbs.set_cb = colorized_frame_set_cb;
3110     custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3111     custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3112     custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3113     custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3114     register_string_like_preference(gui_column_module, "colorized_frame.bg", "Colorized Background",
3115         "Filter Colorized Background",
3116         &prefs.gui_colorized_bg, PREF_CUSTOM, &custom_cbs, TRUE);
3117
3118     prefs_register_color_preference(gui_color_module, "color_filter_bg.valid", "Valid color filter background",
3119         "Valid color filter background", &prefs.gui_text_valid);
3120
3121     prefs_register_color_preference(gui_color_module, "color_filter_bg.invalid", "Invalid color filter background",
3122         "Invalid color filter background", &prefs.gui_text_invalid);
3123
3124     prefs_register_color_preference(gui_color_module, "color_filter_bg.deprecated", "Deprecated color filter background",
3125         "Deprecated color filter background", &prefs.gui_text_deprecated);
3126
3127     prefs_register_enum_preference(gui_module, "fileopen.style",
3128                        "Where to start the File Open dialog box",
3129                        "Where to start the File Open dialog box",
3130                        &prefs.gui_fileopen_style, gui_fileopen_style, FALSE);
3131
3132     prefs_register_uint_preference(gui_module, "recent_files_count.max",
3133                                    "The max. number of items in the open recent files list",
3134                                    "The max. number of items in the open recent files list",
3135                                    10,
3136                                    &prefs.gui_recent_files_count_max);
3137
3138     prefs_register_uint_preference(gui_module, "recent_display_filter_entries.max",
3139                                    "The max. number of entries in the display filter list",
3140                                    "The max. number of entries in the display filter list",
3141                                    10,
3142                                    &prefs.gui_recent_df_entries_max);
3143
3144     register_string_like_preference(gui_module, "fileopen.dir", "Start Directory",
3145         "Directory to start in when opening File Open dialog.",
3146         &prefs.gui_fileopen_dir, PREF_DIRNAME, NULL, TRUE);
3147
3148     prefs_register_obsolete_preference(gui_module, "fileopen.remembered_dir");
3149
3150     prefs_register_uint_preference(gui_module, "fileopen.preview",
3151                                    "The preview timeout in the File Open dialog",
3152                                    "The preview timeout in the File Open dialog",
3153                                    10,
3154                                    &prefs.gui_fileopen_preview);
3155
3156     prefs_register_bool_preference(gui_module, "ask_unsaved",
3157                                    "Ask to save unsaved capture files",
3158                                    "Ask to save unsaved capture files?",
3159                                    &prefs.gui_ask_unsaved);
3160
3161     prefs_register_bool_preference(gui_module, "find_wrap",
3162                                    "Wrap to beginning/end of file during search",
3163                                    "Wrap to beginning/end of file during search?",
3164                                    &prefs.gui_find_wrap);
3165
3166     prefs_register_bool_preference(gui_module, "use_pref_save",
3167                                    "Settings dialogs use a save button",
3168                                    "Settings dialogs use a save button?",
3169                                    &prefs.gui_use_pref_save);
3170
3171     prefs_register_bool_preference(gui_module, "geometry.save.position",
3172                                    "Save window position at exit",
3173                                    "Save window position at exit?",
3174                                    &prefs.gui_geometry_save_position);
3175
3176     prefs_register_bool_preference(gui_module, "geometry.save.size",
3177                                    "Save window size at exit",
3178                                    "Save window size at exit?",
3179                                    &prefs.gui_geometry_save_size);
3180
3181     prefs_register_bool_preference(gui_module, "geometry.save.maximized",
3182                                    "Save window maximized state at exit",
3183                                    "Save window maximized state at exit?",
3184                                    &prefs.gui_geometry_save_maximized);
3185
3186     /* GTK+ only */
3187     prefs_register_bool_preference(gui_module, "macosx_style",
3188                                    "Use macOS style",
3189                                    "Use macOS style (macOS with native GTK only)?",
3190                                    &prefs.gui_macosx_style);
3191
3192     prefs_register_obsolete_preference(gui_module, "geometry.main.x");
3193     prefs_register_obsolete_preference(gui_module, "geometry.main.y");
3194     prefs_register_obsolete_preference(gui_module, "geometry.main.width");
3195     prefs_register_obsolete_preference(gui_module, "geometry.main.height");
3196     prefs_register_obsolete_preference(gui_module, "toolbar_main_show");
3197
3198     prefs_register_enum_preference(gui_module, "toolbar_main_style",
3199                        "Main Toolbar style",
3200                        "Main Toolbar style",
3201                        &prefs.gui_toolbar_main_style, gui_toolbar_style, FALSE);
3202
3203     prefs_register_enum_preference(gui_module, "toolbar_filter_style",
3204                        "Filter Toolbar style",
3205                        "Filter Toolbar style",
3206                        &prefs.gui_toolbar_filter_style, gui_toolbar_style, FALSE);
3207
3208     register_string_like_preference(gui_module, "webbrowser", "The path to the webbrowser",
3209         "The path to the webbrowser (Ex: mozilla)",
3210         &prefs.gui_webbrowser, PREF_STRING, NULL, TRUE);
3211
3212     prefs_register_bool_preference(gui_module, "update.enabled",
3213                                    "Check for updates",
3214                                    "Check for updates (Windows only)",
3215                                    &prefs.gui_update_enabled);
3216
3217     prefs_register_enum_preference(gui_module, "update.channel",
3218                        "Update channel",
3219                        "The type of update to fetch. You should probably leave this set to UPDATE_CHANNEL_STABLE.",
3220                        (gint*)(void*)(&prefs.gui_update_channel), gui_update_channel, FALSE);
3221
3222     prefs_register_uint_preference(gui_module, "update.interval",
3223                                    "How often to check for software updates",
3224                                    "How often to check for software updates in seconds",
3225                                    10,
3226                                    &prefs.gui_update_interval);
3227
3228     register_string_like_preference(gui_module, "window_title", "Custom window title",
3229         "Custom window title to be appended to the existing title\n%P = profile name\n%V = version info",
3230         &prefs.gui_window_title, PREF_STRING, NULL, TRUE);
3231
3232     register_string_like_preference(gui_module, "prepend_window_title", "Custom window title prefix",
3233         "Custom window title to be prepended to the existing title\n%P = profile name\n%V = version info",
3234         &prefs.gui_prepend_window_title, PREF_STRING, NULL, TRUE);
3235
3236     register_string_like_preference(gui_module, "start_title", "Custom start page title",
3237         "Custom start page title",
3238         &prefs.gui_start_title, PREF_STRING, NULL, TRUE);
3239
3240     prefs_register_enum_preference(gui_module, "version_placement",
3241                        "Show version in the start page and/or main screen's title bar",
3242                        "Show version in the start page and/or main screen's title bar",
3243                        (gint*)(void*)(&prefs.gui_version_placement), gui_version_placement_type, FALSE);
3244
3245     prefs_register_bool_preference(gui_module, "auto_scroll_on_expand",
3246                                    "Automatically scroll packet details",
3247                                    "When selecting a new packet, automatically scroll"
3248                                    "to the packet detail item that matches the most"
3249                                    "recently selected item",
3250                                    &prefs.gui_auto_scroll_on_expand);
3251
3252     prefs_register_uint_preference(gui_module, "auto_scroll_percentage",
3253                                    "Packet detail scroll percentage",
3254                                    "The percentage down the view the recently expanded detail item should be scrolled",
3255                                    10,
3256                                    &prefs.gui_auto_scroll_percentage);
3257
3258     /* User Interface : Layout */
3259     gui_layout_module = prefs_register_subtree(gui_module, "Layout", "Layout", gui_layout_callback);
3260
3261     prefs_register_uint_preference(gui_layout_module, "layout_type",
3262                                    "Layout type",
3263                                    "Layout type (1-6)",
3264                                    10,
3265                                    (guint*)(void*)(&prefs.gui_layout_type));
3266
3267     prefs_register_enum_preference(gui_layout_module, "layout_content_1",
3268                        "Layout content of the pane 1",
3269                        "Layout content of the pane 1",
3270                        (gint*)(void*)(&prefs.gui_layout_content_1), gui_layout_content, FALSE);
3271
3272     prefs_register_enum_preference(gui_layout_module, "layout_content_2",
3273                        "Layout content of the pane 2",
3274                        "Layout content of the pane 2",
3275                        (gint*)(void*)(&prefs.gui_layout_content_2), gui_layout_content, FALSE);
3276
3277     prefs_register_enum_preference(gui_layout_module, "layout_content_3",
3278                        "Layout content of the pane 3",
3279                        "Layout content of the pane 3",
3280                        (gint*)(void*)(&prefs.gui_layout_content_3), gui_layout_content, FALSE);
3281
3282     prefs_register_bool_preference(gui_layout_module, "packet_list_separator.enabled",
3283                                    "Enable Packet List Separator",
3284                                    "Enable Packet List Separator",
3285                                    &prefs.gui_qt_packet_list_separator);
3286
3287     prefs_register_bool_preference(gui_module, "packet_editor.enabled",
3288                                    "Enable Packet Editor",
3289                                    "Enable Packet Editor (Experimental)",
3290                                    &prefs.gui_packet_editor);
3291
3292     prefs_register_enum_preference(gui_module, "packet_list_elide_mode",
3293                        "Elide mode",
3294                        "The position of \"...\" in packet list text.",
3295                        (gint*)(void*)(&prefs.gui_packet_list_elide_mode), gui_packet_list_elide_mode, FALSE);
3296
3297     prefs_register_bool_preference(gui_layout_module, "packet_list_show_related",
3298                                    "Show Related Packets",
3299                                    "Show related packet indicators in the first column",
3300                                    &prefs.gui_packet_list_show_related);
3301
3302     prefs_register_bool_preference(gui_layout_module, "packet_list_show_minimap",
3303                                    "Enable Intelligent Scroll Bar",
3304                                    "Show the intelligent scroll bar (a minimap of packet list colors in the scrollbar)",
3305                                    &prefs.gui_packet_list_show_minimap);
3306
3307
3308     prefs_register_bool_preference(gui_module, "interfaces_show_hidden",
3309                                    "Show hidden interfaces",
3310                                    "Show all interfaces, including interfaces marked as hidden",
3311                                    &prefs.gui_interfaces_show_hidden);
3312
3313 #ifdef HAVE_PCAP_REMOTE
3314     prefs_register_bool_preference(gui_module, "interfaces_remote_display",
3315                                    "Show Remote interfaces",
3316                                    "Show remote interfaces in the interface selection",
3317                                    &prefs.gui_interfaces_remote_display);
3318 #endif
3319
3320     register_string_like_preference(gui_module, "interfaces_hidden_types", "Hide interface types in list",
3321         "Hide the given interface types in the startup list",
3322         &prefs.gui_interfaces_hide_types, PREF_STRING, NULL, TRUE);
3323
3324     /* Console
3325      * These are preferences that can be read/written using the
3326      * preference module API.  These preferences still use their own
3327      * configuration screens for access, but this cuts down on the
3328      * preference "string compare list" in set_pref()
3329      */
3330     console_module = prefs_register_module(NULL, "console", "Console",
3331         "Console logging and debugging output", NULL, FALSE);
3332
3333     custom_cbs.free_cb = custom_pref_no_cb;
3334     custom_cbs.reset_cb = console_log_level_reset_cb;
3335     custom_cbs.set_cb = console_log_level_set_cb;
3336     custom_cbs.type_name_cb = console_log_level_type_name_cb;
3337     custom_cbs.type_description_cb = console_log_level_type_description_cb;
3338     custom_cbs.is_default_cb = console_log_level_is_default_cb;
3339     custom_cbs.to_str_cb = console_log_level_to_str_cb;
3340     prefs_register_uint_custom_preference(console_module, "log.level", "logging level",
3341         "A bitmask of GLib log levels", &custom_cbs, &prefs.console_log_level);
3342
3343     prefs_register_bool_preference(console_module, "incomplete_dissectors_check_debug",
3344                                    "Print debug line for incomplete dissectors",
3345                                    "Look for dissectors that left some bytes undecoded (debug)",
3346                                    &prefs.incomplete_dissectors_check_debug);
3347
3348     /* Capture
3349      * These are preferences that can be read/written using the
3350      * preference module API.  These preferences still use their own
3351      * configuration screens for access, but this cuts down on the
3352      * preference "string compare list" in set_pref()
3353      */
3354     capture_module = prefs_register_module(NULL, "capture", "Capture",
3355         "Capture preferences", NULL, FALSE);
3356
3357     register_string_like_preference(capture_module, "device", "Default capture device",
3358         "Default capture device",
3359         &prefs.capture_device, PREF_STRING, NULL, FALSE);
3360
3361     register_string_like_preference(capture_module, "devices_linktypes", "Interface link-layer header type",
3362         "Interface link-layer header types (Ex: en0(1),en1(143),...)",
3363         &prefs.capture_devices_linktypes, PREF_STRING, NULL, FALSE);
3364
3365     register_string_like_preference(capture_module, "devices_descr", "Interface descriptions",
3366         "Interface descriptions (Ex: eth0(eth0 descr),eth1(eth1 descr),...)",
3367         &prefs.capture_devices_descr, PREF_STRING, NULL, FALSE);
3368
3369     register_string_like_preference(capture_module, "devices_hide", "Hide interface",
3370         "Hide interface? (Ex: eth0,eth3,...)",
3371         &prefs.capture_devices_hide, PREF_STRING, NULL, FALSE);
3372
3373     register_string_like_preference(capture_module, "devices_monitor_mode", "Capture in monitor mode",
3374         "By default, capture in monitor mode on interface? (Ex: eth0,eth3,...)",
3375         &prefs.capture_devices_monitor_mode, PREF_STRING, NULL, FALSE);
3376
3377 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
3378     register_string_like_preference(capture_module, "devices_buffersize", "Interface buffer size",
3379         "Interface buffer size (Ex: en0(1),en1(143),...)",
3380         &prefs.capture_devices_buffersize, PREF_STRING, NULL, FALSE);
3381 #endif
3382
3383     register_string_like_preference(capture_module, "devices_snaplen", "Interface snap length",
3384         "Interface snap length (Ex: en0(65535),en1(1430),...)",
3385         &prefs.capture_devices_snaplen, PREF_STRING, NULL, FALSE);
3386
3387     register_string_like_preference(capture_module, "devices_pmode", "Interface promiscuous mode",
3388         "Interface promiscuous mode (Ex: en0(0),en1(1),...)",
3389         &prefs.capture_devices_pmode, PREF_STRING, NULL, FALSE);
3390
3391     prefs_register_bool_preference(capture_module, "prom_mode", "Capture in promiscuous mode",
3392         "Capture in promiscuous mode?", &prefs.capture_prom_mode);
3393
3394     register_string_like_preference(capture_module, "devices_filter", "Interface capture filter",
3395         "Interface capture filter (Ex: en0(tcp),en1(udp),...)",
3396         &prefs.capture_devices_filter, PREF_STRING, NULL, FALSE);
3397
3398     prefs_register_bool_preference(capture_module, "pcap_ng", "Capture in Pcap-NG format",
3399         "Capture in Pcap-NG format?", &prefs.capture_pcap_ng);
3400
3401     prefs_register_bool_preference(capture_module, "real_time_update", "Update packet list in real time during capture",
3402         "Update packet list in real time during capture?", &prefs.capture_real_time);
3403
3404     /* We might want to make this a "recent" setting. */
3405     prefs_register_bool_preference(capture_module, "auto_scroll", "Scroll packet list during capture",
3406         "Scroll packet list during capture?", &prefs.capture_auto_scroll);
3407
3408     /* GTK+ only */
3409     prefs_register_bool_preference(capture_module, "show_info", "Show capture info dialog while capturing",
3410         "Show capture info dialog while capturing?", &prefs.capture_show_info);
3411
3412     prefs_register_obsolete_preference(capture_module, "syntax_check_filter");
3413
3414     custom_cbs.free_cb = capture_column_free_cb;
3415     custom_cbs.reset_cb = capture_column_reset_cb;
3416     custom_cbs.set_cb = capture_column_set_cb;
3417     custom_cbs.type_name_cb = capture_column_type_name_cb;
3418     custom_cbs.type_description_cb = capture_column_type_description_cb;
3419     custom_cbs.is_default_cb = capture_column_is_default_cb;
3420     custom_cbs.to_str_cb = capture_column_to_str_cb;
3421     prefs_register_list_custom_preference(capture_module, "columns", "Capture options dialog column list",
3422         "List of columns to be displayed", &custom_cbs, capture_column_init_cb, &prefs.capture_columns);
3423
3424     /* Name Resolution */
3425     nameres_module = prefs_register_module(NULL, "nameres", "Name Resolution",
3426         "Name Resolution", NULL, TRUE);
3427     addr_resolve_pref_init(nameres_module);
3428     oid_pref_init(nameres_module);
3429 #ifdef HAVE_GEOIP
3430     geoip_db_pref_init(nameres_module);
3431 #endif
3432
3433     /* Printing */
3434     printing = prefs_register_module(NULL, "print", "Printing",
3435         "Printing", NULL, TRUE);
3436
3437     prefs_register_enum_preference(printing, "format",
3438                                    "Format", "Can be one of \"text\" or \"postscript\"",
3439                                    &prefs.pr_format, print_format_vals, TRUE);
3440
3441     prefs_register_enum_preference(printing, "destination",
3442                                    "Print to", "Can be one of \"command\" or \"file\"",
3443                                    &prefs.pr_dest, print_dest_vals, TRUE);
3444
3445 #ifndef _WIN32
3446     register_string_like_preference(printing, "command", "Command",
3447         "Output gets piped to this command when the destination is set to \"command\"",
3448         &prefs.pr_cmd, PREF_STRING, NULL, TRUE);
3449 #endif
3450
3451     register_string_like_preference(printing, "file", "File",
3452         "This is the file that gets written to when the destination is set to \"file\"",
3453         &prefs.pr_file, PREF_FILENAME, NULL, TRUE);
3454
3455     /* Statistics */
3456     stats_module = prefs_register_module(NULL, "statistics", "Statistics",
3457         "Statistics", &stats_callback, TRUE);
3458
3459     prefs_register_uint_preference(stats_module, "update_interval",
3460                                    "Tap update interval in ms",
3461                                    "Determines time between tap updates",
3462                                    10,
3463                                    &prefs.tap_update_interval);
3464
3465 #ifdef HAVE_LIBPORTAUDIO
3466     prefs_register_uint_preference(stats_module, "rtp_player_max_visible",
3467                                    "Max visible channels in RTP Player",
3468                                    "Determines maximum height of RTP Player window",
3469                                    10,
3470                                    &prefs.rtp_player_max_visible);
3471 #endif
3472
3473     prefs_register_bool_preference(stats_module, "st_enable_burstinfo",
3474             "Enable the calculation of burst information",
3475             "If enabled burst rates will be calcuted for statistics that use the stats_tree system. "
3476             "Burst rates are calculated over a much shorter time interval than the rate column.",
3477             &prefs.st_enable_burstinfo);
3478
3479     prefs_register_bool_preference(stats_module, "st_burst_showcount",
3480             "Show burst count for item rather than rate",
3481             "If selected the stats_tree statistics nodes will show the count of events "
3482             "within the burst window instead of a burst rate. Burst rate is calculated "
3483             "as number of events within burst window divided by the burst windown length.",
3484             &prefs.st_burst_showcount);
3485
3486     prefs_register_uint_preference(stats_module, "st_burst_resolution",
3487             "Burst rate resolution (ms)",
3488             "Sets the duration of the time interval into which events are grouped when calculating "
3489             "the burst rate. Higher resolution (smaller number) increases processing overhead.",
3490             10,&prefs.st_burst_resolution);
3491
3492     prefs_register_uint_preference(stats_module, "st_burst_windowlen",
3493             "Burst rate window size (ms)",
3494             "Sets the duration of the sliding window during which the burst rate is "
3495             "measured. Longer window relative to burst rate resolution increases "
3496             "processing overhead. Will be truncated to a multiple of burst resolution.",
3497             10,&prefs.st_burst_windowlen);
3498
3499     prefs_register_enum_preference(stats_module, "st_sort_defcolflag",
3500             "Default sort column for stats_tree stats",
3501             "Sets the default column by which stats based on the stats_tree "
3502             "system is sorted.",
3503             &prefs.st_sort_defcolflag, st_sort_col_vals, FALSE);
3504
3505      prefs_register_bool_preference(stats_module, "st_sort_defdescending",
3506             "Default stats_tree sort order is descending",
3507             "When selected, statistics based on the stats_tree system will by default "
3508             "be sorted in descending order.",
3509             &prefs.st_sort_defdescending);
3510
3511      prefs_register_bool_preference(stats_module, "st_sort_casesensitve",
3512             "Case sensitive sort of stats_tree item names",
3513             "When selected, the item/node names of statistics based on the stats_tree "
3514             "system will be sorted taking case into account. Else the case of the name "
3515             "will be ignored.",
3516             &prefs.st_sort_casesensitve);
3517
3518      prefs_register_bool_preference(stats_module, "st_sort_rng_nameonly",
3519             "Always sort 'range' nodes by name",
3520             "When selected, the stats_tree nodes representing a range of values "
3521             "(0-49, 50-100, etc.) will always be sorted by name (the range of the "
3522             "node). Else range nodes are sorted by the same column as the rest of "
3523             " the tree.",
3524             &prefs.st_sort_rng_nameonly);
3525
3526      prefs_register_bool_preference(stats_module, "st_sort_rng_fixorder",
3527             "Always sort 'range' nodes in ascending order",
3528             "When selected, the stats_tree nodes representing a range of values "
3529             "(0-49, 50-100, etc.) will always be sorted ascending; else it follows "
3530             "the sort direction of the tree. Only effective if \"Always sort "
3531             "'range' nodes by name\" is also selected.",
3532             &prefs.st_sort_rng_fixorder);
3533
3534      prefs_register_bool_preference(stats_module, "st_sort_showfullname",
3535             "Display the full stats_tree plug-in name",
3536             "When selected, the full name (including menu path) of the stats_tree "
3537             "plug-in is show in windows. If cleared the plug-in name is shown "
3538             "without menu path (only the part of the name after last '/' character.)",
3539             &prefs.st_sort_showfullname);
3540
3541     /* Protocols */
3542     protocols_module = prefs_register_module(NULL, "protocols", "Protocols",
3543                                              "Protocols", NULL, TRUE);
3544
3545     prefs_register_bool_preference(protocols_module, "display_hidden_proto_items",
3546                                    "Display hidden protocol items",
3547                                    "Display all hidden protocol items in the packet list.",
3548                                    &prefs.display_hidden_proto_items);
3549
3550     prefs_register_bool_preference(protocols_module, "display_byte_fields_with_spaces",
3551                                    "Display byte fields with a space character between bytes",
3552                                    "Display all byte fields with a space character between each byte in the packet list.",
3553                                    &prefs.display_byte_fields_with_spaces);
3554
3555     prefs_register_bool_preference(protocols_module, "enable_incomplete_dissectors_check",
3556                                    "Look for incomplete dissectors",
3557                                    "Look for dissectors that left some bytes undecoded.",
3558                                    &prefs.enable_incomplete_dissectors_check);
3559
3560     /* Obsolete preferences
3561      * These "modules" were reorganized/renamed to correspond to their GUI
3562      * configuration screen within the preferences dialog
3563      */
3564
3565     /* taps is now part of the stats module */
3566     prefs_register_module(NULL, "taps", "TAPS", "TAPS", NULL, FALSE);
3567     /* packet_list is now part of the protocol (parent) module */
3568     prefs_register_module(NULL, "packet_list", "PACKET_LIST", "PACKET_LIST", NULL, FALSE);
3569     /* stream is now part of the gui module */
3570     prefs_register_module(NULL, "stream", "STREAM", "STREAM", NULL, FALSE);
3571
3572 }
3573
3574 /* Parse through a list of comma-separated, possibly quoted strings.
3575    Return a list of the string data. */
3576 GList *
3577 prefs_get_string_list(const gchar *str)
3578 {
3579     enum { PRE_STRING, IN_QUOT, NOT_IN_QUOT };
3580
3581     gint      state = PRE_STRING, i = 0, j = 0;
3582     gboolean  backslash = FALSE;
3583     guchar    cur_c;
3584     gchar    *slstr = NULL;
3585     GList    *sl = NULL;
3586
3587     /* Allocate a buffer for the first string.   */
3588     slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
3589     j = 0;
3590
3591     for (;;) {
3592         cur_c = str[i];
3593         if (cur_c == '\0') {
3594             /* It's the end of the input, so it's the end of the string we
3595                were working on, and there's no more input. */
3596             if (state == IN_QUOT || backslash) {
3597                 /* We were in the middle of a quoted string or backslash escape,
3598                    and ran out of characters; that's an error.  */
3599                 g_free(slstr);
3600                 prefs_clear_string_list(sl);
3601                 return NULL;
3602             }
3603             slstr[j] = '\0';
3604             sl = g_list_append(sl, slstr);
3605             break;
3606         }
3607         if (cur_c == '"' && ! backslash) {
3608             switch (state) {
3609             case PRE_STRING:
3610                 /* We hadn't yet started processing a string; this starts the
3611                    string, and we're now quoting.  */
3612                 state = IN_QUOT;
3613                 break;
3614             case IN_QUOT:
3615                 /* We're in the middle of a quoted string, and we saw a quotation
3616                    mark; we're no longer quoting.   */
3617                 state = NOT_IN_QUOT;
3618                 break;
3619             case NOT_IN_QUOT:
3620                 /* We're working on a string, but haven't seen a quote; we're
3621                    now quoting.  */
3622                 state = IN_QUOT;
3623                 break;
3624             default:
3625                 break;
3626             }
3627         } else if (cur_c == '\\' && ! backslash) {
3628             /* We saw a backslash, and the previous character wasn't a
3629                backslash; escape the next character.
3630
3631                This also means we've started a new string. */
3632             backslash = TRUE;
3633             if (state == PRE_STRING)
3634                 state = NOT_IN_QUOT;
3635         } else if (cur_c == ',' && state != IN_QUOT && ! backslash) {
3636             /* We saw a comma, and we're not in the middle of a quoted string
3637                and it wasn't preceded by a backslash; it's the end of
3638                the string we were working on...  */
3639             slstr[j] = '\0';
3640             sl = g_list_append(sl, slstr);
3641
3642             /* ...and the beginning of a new string.  */
3643             state = PRE_STRING;
3644             slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
3645             j = 0;
3646         } else if (!g_ascii_isspace(cur_c) || state != PRE_STRING) {
3647             /* Either this isn't a white-space character, or we've started a
3648                string (i.e., already seen a non-white-space character for that
3649                string and put it into the string).
3650
3651                The character is to be put into the string; do so if there's
3652                room.  */
3653             if (j < COL_MAX_LEN) {
3654                 slstr[j] = cur_c;
3655                 j++;
3656             }
3657
3658             /* If it was backslash-escaped, we're done with the backslash escape.  */
3659             backslash = FALSE;
3660         }
3661         i++;
3662     }
3663     return(sl);
3664 }
3665
3666 char *join_string_list(GList *sl)
3667 {
3668     GString      *joined_str = g_string_new("");
3669     GList        *cur, *first;
3670     gchar        *str;
3671     guint         item_count = 0;
3672
3673     cur = first = g_list_first(sl);
3674     while (cur) {
3675         item_count++;
3676         str = (gchar *)cur->data;
3677
3678         if (cur != first)
3679             g_string_append_c(joined_str, ',');
3680
3681         if (item_count % 2) {
3682             /* Wrap the line.  */
3683             g_string_append(joined_str, "\n\t");
3684         } else
3685             g_string_append_c(joined_str, ' ');
3686
3687         g_string_append_c(joined_str, '"');
3688         while (*str) {
3689             gunichar uc = g_utf8_get_char (str);
3690
3691             if (uc == '"' || uc == '\\')
3692                 g_string_append_c(joined_str, '\\');
3693
3694             if (g_unichar_isprint(uc))
3695                 g_string_append_unichar (joined_str, uc);
3696
3697             str = g_utf8_next_char (str);
3698         }
3699
3700         g_string_append_c(joined_str, '"');
3701
3702         cur = cur->next;
3703     }
3704     return g_string_free(joined_str, FALSE);
3705 }
3706
3707 void
3708 prefs_clear_string_list(GList *sl)
3709 {
3710     /* g_list_free_full() only exists since 2.28. */
3711     g_list_foreach(sl, (GFunc)g_free, NULL);
3712     g_list_free(sl);
3713 }
3714
3715 /*
3716  * Takes a string, a pointer to an array of "enum_val_t"s, and a default gint
3717  * value.
3718  * The array must be terminated by an entry with a null "name" string.
3719  *
3720  * If the string matches a "name" string in an entry, the value from that
3721  * entry is returned.
3722  *
3723  * Otherwise, if a string matches a "description" string in an entry, the
3724  * value from that entry is returned; we do that for backwards compatibility,
3725  * as we used to have only a "name" string that was used both for command-line
3726  * and configuration-file values and in the GUI (which meant either that
3727  * the GUI had what might be somewhat cryptic values to select from or that
3728  * the "-o" flag took long strings, often with spaces in them).
3729  *
3730  * Otherwise, the default value that was passed as the third argument is
3731  * returned.
3732  */
3733 static gint
3734 find_val_for_string(const char *needle, const enum_val_t *haystack,
3735                     gint default_value)
3736 {
3737     int i;
3738
3739     for (i = 0; haystack[i].name != NULL; i++) {
3740         if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) {
3741             return haystack[i].value;
3742         }
3743     }
3744     for (i = 0; haystack[i].name != NULL; i++) {
3745         if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) {
3746             return haystack[i].value;
3747         }
3748     }
3749     return default_value;
3750 }
3751
3752
3753 /* Array of columns that have been migrated to custom columns */
3754 struct deprecated_columns {
3755     const gchar *col_fmt;
3756     const gchar *col_expr;
3757 };
3758 static struct deprecated_columns migrated_columns[] = {
3759     { /* COL_COS_VALUE */ "%U", "vlan.priority" },
3760     { /* COL_CIRCUIT_ID */ "%c", "iax2.call" },
3761     { /* COL_BSSGP_TLLI */ "%l", "bssgp.tlli" },
3762     { /* COL_HPUX_SUBSYS */ "%H", "nettl.subsys" },
3763     { /* COL_HPUX_DEVID */ "%P", "nettl.devid" },
3764     { /* COL_FR_DLCI */ "%C", "fr.dlci" },
3765     { /* COL_REL_CONV_TIME */ "%rct", "tcp.time_relative" },
3766     { /* COL_DELTA_CONV_TIME */ "%dct", "tcp.time_delta" },
3767     { /* COL_OXID */ "%XO", "fc.ox_id" },
3768     { /* COL_RXID */ "%XR", "fc.rx_id" },
3769     { /* COL_SRCIDX */ "%Xd", "mdshdr.srcidx" },
3770     { /* COL_DSTIDX */ "%Xs", "mdshdr.dstidx" },
3771     { /* COL_DCE_CTX */ "%z", "dcerpc.cn_ctx_id" }
3772 };
3773
3774 static gboolean
3775 is_deprecated_column_format(const gchar* fmt)
3776 {
3777     guint haystack_idx;
3778
3779     for (haystack_idx = 0;
3780          haystack_idx < G_N_ELEMENTS(migrated_columns);
3781          ++haystack_idx) {
3782
3783         if (strcmp(migrated_columns[haystack_idx].col_fmt, fmt) == 0) {
3784             return TRUE;
3785         }
3786     }
3787
3788     return FALSE;
3789 }
3790
3791 /* Preferences file format:
3792  * - Configuration directives start at the beginning of the line, and
3793  *   are terminated with a colon.
3794  * - Directives can be continued on the next line by preceding them with
3795  *   whitespace.
3796  *
3797  * Example:
3798
3799 # This is a comment line
3800 print.command: lpr
3801 print.file: /a/very/long/path/
3802             to/wireshark-out.ps
3803  *
3804  */
3805
3806 #define DEF_NUM_COLS    7
3807
3808 /*
3809  * Parse a column format, filling in the relevant fields of a fmt_data.
3810  */
3811 static gboolean
3812 parse_column_format(fmt_data *cfmt, const char *fmt)
3813 {
3814     const gchar *cust_format = col_format_to_string(COL_CUSTOM);
3815     size_t cust_format_len = strlen(cust_format);
3816     gchar **cust_format_info;
3817     char *p;
3818     int col_fmt;
3819     gchar *col_custom_fields = NULL;
3820     long col_custom_occurrence = 0;
3821     gboolean col_resolved = TRUE;
3822
3823     /*
3824      * Is this a custom column?
3825      */
3826     if ((strlen(fmt) > cust_format_len) && (fmt[cust_format_len] == ':') &&
3827         strncmp(fmt, cust_format, cust_format_len) == 0) {
3828         /* Yes. */
3829         col_fmt = COL_CUSTOM;
3830         cust_format_info = g_strsplit(&fmt[cust_format_len+1],":",3); /* add 1 for ':' */
3831         col_custom_fields = g_strdup(cust_format_info[0]);
3832         if (col_custom_fields && cust_format_info[1]) {
3833             col_custom_occurrence = strtol(cust_format_info[1], &p, 10);
3834             if (p == cust_format_info[1] || *p != '\0') {
3835                 /* Not a valid number. */
3836                 g_free(col_custom_fields);
3837                 g_strfreev(cust_format_info);
3838                 return FALSE;
3839             }
3840         }
3841         if (col_custom_fields && cust_format_info[1] && cust_format_info[2]) {
3842             col_resolved = (cust_format_info[2][0] == 'U') ? FALSE : TRUE;
3843         }
3844         g_strfreev(cust_format_info);
3845     } else {
3846         col_fmt = get_column_format_from_str(fmt);
3847         if ((col_fmt == -1) && (!is_deprecated_column_format(fmt)))
3848             return FALSE;
3849     }
3850
3851     cfmt->fmt = col_fmt;
3852     cfmt->custom_fields = col_custom_fields;
3853     cfmt->custom_occurrence = (int)col_custom_occurrence;
3854     cfmt->resolved = col_resolved;
3855     return TRUE;
3856 }
3857
3858 /* Initialize non-dissector preferences to wired-in default values Called
3859  * at program startup and any time the profile changes. (The dissector
3860  * preferences are assumed to be set to those values by the dissectors.)
3861  * They may be overridden by the global preferences file or the user's
3862  * preferences file.
3863  */
3864 static void
3865 init_prefs(void)
3866 {
3867     if (prefs_initialized)
3868         return;
3869
3870     uat_load_all();
3871
3872     /*
3873      * Ensure the "global" preferences have been initialized so the
3874      * preference API has the proper default values to work from
3875      */
3876     pre_init_prefs();
3877
3878     prefs_register_modules();
3879
3880     filter_expression_init();
3881
3882     prefs_initialized = TRUE;
3883 }
3884
3885 /*
3886  * Initialize non-dissector preferences used by the "register preference" API
3887  * to default values so the default values can be used when registered.
3888  *
3889  * String, filename, and directory preferences will be g_freed so they must
3890  * be g_mallocated.
3891  */
3892 static void
3893 pre_init_prefs(void)
3894 {
3895     int         i;
3896     gchar       *col_name;
3897     fmt_data    *cfmt;
3898     static const gchar *col_fmt[DEF_NUM_COLS*2] = {
3899         "No.",      "%m", "Time",        "%t",
3900         "Source",   "%s", "Destination", "%d",
3901         "Protocol", "%p", "Length",      "%L",
3902         "Info",     "%i"};
3903
3904     prefs.pr_format  = PR_FMT_TEXT;
3905     prefs.pr_dest    = PR_DEST_CMD;
3906     if (prefs.pr_file) g_free(prefs.pr_file);
3907     prefs.pr_file    = g_strdup("wireshark.out");
3908     if (prefs.pr_cmd) g_free(prefs.pr_cmd);
3909     prefs.pr_cmd     = g_strdup("lpr");
3910
3911     prefs.gui_altern_colors = FALSE;
3912     prefs.gui_expert_composite_eyecandy = FALSE;
3913     prefs.gui_ptree_line_style = 0;
3914     prefs.gui_ptree_expander_style = 1;
3915     prefs.gui_hex_dump_highlight_style = 1;
3916     prefs.filter_toolbar_show_in_statusbar = FALSE;
3917     prefs.gui_toolbar_main_style = TB_STYLE_ICONS;
3918     prefs.gui_toolbar_filter_style = TB_STYLE_TEXT;
3919     /* These will be g_freed, so they must be g_mallocated. */
3920     if (prefs.gui_gtk2_font_name) g_free(prefs.gui_gtk2_font_name);
3921 #ifdef _WIN32
3922     prefs.gui_gtk2_font_name         = g_strdup("Lucida Console 10");
3923 #else
3924     prefs.gui_gtk2_font_name         = g_strdup("Monospace 10");
3925 #endif
3926     /* We try to find the best font in the Qt code */
3927     if (prefs.gui_qt_font_name) g_free(prefs.gui_qt_font_name);
3928     prefs.gui_qt_font_name           = g_strdup("");
3929     prefs.gui_marked_fg.red          =     65535;
3930     prefs.gui_marked_fg.green        =     65535;
3931     prefs.gui_marked_fg.blue         =     65535;
3932     prefs.gui_marked_bg.red          =         0;
3933     prefs.gui_marked_bg.green        =      8224;
3934     prefs.gui_marked_bg.blue         =     10794;
3935     prefs.gui_ignored_fg.red         =     32767;
3936     prefs.gui_ignored_fg.green       =     32767;
3937     prefs.gui_ignored_fg.blue        =     32767;
3938     prefs.gui_ignored_bg.red         =     65535;
3939     prefs.gui_ignored_bg.green       =     65535;
3940     prefs.gui_ignored_bg.blue        =     65535;
3941     if (prefs.gui_colorized_fg) g_free(prefs.gui_colorized_fg);
3942     prefs.gui_colorized_fg           = g_strdup("000000,000000,000000,000000,000000,000000,000000,000000,000000,000000");
3943     if (prefs.gui_colorized_bg) g_free(prefs.gui_colorized_bg);
3944     prefs.gui_colorized_bg           = g_strdup("ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0");
3945     prefs.st_client_fg.red           = 32767;
3946     prefs.st_client_fg.green         =     0;
3947     prefs.st_client_fg.blue          =     0;
3948     prefs.st_client_bg.red           = 64507;
3949     prefs.st_client_bg.green         = 60909;
3950     prefs.st_client_bg.blue          = 60909;
3951     prefs.st_server_fg.red           =     0;
3952     prefs.st_server_fg.green         =     0;
3953     prefs.st_server_fg.blue          = 32767;
3954     prefs.st_server_bg.red           = 60909;
3955     prefs.st_server_bg.green         = 60909;
3956     prefs.st_server_bg.blue          = 64507;
3957     prefs.gui_text_valid.red         = 0xAFFF; /* light green */
3958     prefs.gui_text_valid.green       = 0xFFFF;
3959     prefs.gui_text_valid.blue        = 0xAFFF;
3960     prefs.gui_text_invalid.red       = 0xFFFF; /* light red */
3961     prefs.gui_text_invalid.green     = 0xAFFF;
3962     prefs.gui_text_invalid.blue      = 0xAFFF;
3963     prefs.gui_text_deprecated.red    = 0xFFFF; /* light yellow */
3964     prefs.gui_text_deprecated.green  = 0xFFFF;
3965     prefs.gui_text_deprecated.blue   = 0xAFFF;
3966     prefs.gui_geometry_save_position = TRUE;
3967     prefs.gui_geometry_save_size     = TRUE;
3968     prefs.gui_geometry_save_maximized= TRUE;
3969     prefs.gui_macosx_style           = TRUE;
3970     prefs.gui_console_open           = console_open_never;
3971     prefs.gui_fileopen_style         = FO_STYLE_LAST_OPENED;
3972     prefs.gui_recent_df_entries_max  = 10;
3973     prefs.gui_recent_files_count_max = 10;
3974     if (prefs.gui_fileopen_dir) g_free(prefs.gui_fileopen_dir);
3975     prefs.gui_fileopen_dir           = g_strdup(get_persdatafile_dir());
3976     prefs.gui_fileopen_preview       = 3;
3977     prefs.gui_ask_unsaved            = TRUE;
3978     prefs.gui_find_wrap              = TRUE;
3979     prefs.gui_use_pref_save          = FALSE;
3980     prefs.gui_update_enabled         = TRUE;
3981     prefs.gui_update_channel         = UPDATE_CHANNEL_STABLE;
3982     prefs.gui_update_interval        = 60*60*24; /* Seconds */
3983     if (prefs.gui_webbrowser) g_free(prefs.gui_webbrowser);
3984     prefs.gui_webbrowser             = g_strdup("");
3985     if (prefs.gui_window_title) g_free(prefs.gui_window_title);
3986     prefs.gui_window_title           = g_strdup("");
3987     if (prefs.gui_prepend_window_title) g_free(prefs.gui_prepend_window_title);
3988     prefs.gui_prepend_window_title   = g_strdup("");
3989     if (prefs.gui_start_title) g_free(prefs.gui_start_title);
3990     prefs.gui_start_title            = g_strdup("The World's Most Popular Network Protocol Analyzer");
3991     prefs.gui_version_placement      = version_both;
3992     prefs.gui_auto_scroll_on_expand  = FALSE;
3993     prefs.gui_auto_scroll_percentage = 0;
3994     prefs.gui_layout_type            = layout_type_5;
3995     prefs.gui_layout_content_1       = layout_pane_content_plist;
3996     prefs.gui_layout_content_2       = layout_pane_content_pdetails;
3997     prefs.gui_layout_content_3       = layout_pane_content_pbytes;
3998     prefs.gui_packet_editor          = FALSE;
3999     prefs.gui_packet_list_elide_mode = ELIDE_RIGHT;
4000     prefs.gui_packet_list_show_related = TRUE;
4001     prefs.gui_packet_list_show_minimap = TRUE;
4002     if (prefs.gui_interfaces_hide_types) g_free (prefs.gui_interfaces_hide_types);
4003     prefs.gui_interfaces_hide_types = g_strdup("");
4004     prefs.gui_interfaces_show_hidden = FALSE;
4005 #ifdef HAVE_PCAP_REMOTE
4006     prefs.gui_interfaces_remote_display = TRUE;
4007 #endif
4008
4009     prefs.gui_qt_packet_list_separator = FALSE;
4010
4011     if (prefs.col_list) {
4012         free_col_info(prefs.col_list);
4013         prefs.col_list = NULL;
4014     }
4015     for (i = 0; i < DEF_NUM_COLS; i++) {
4016         cfmt = g_new(fmt_data,1);
4017         cfmt->title = g_strdup(col_fmt[i * 2]);
4018         parse_column_format(cfmt, col_fmt[(i * 2) + 1]);
4019         cfmt->visible = TRUE;
4020         cfmt->resolved = TRUE;
4021         cfmt->custom_fields = NULL;
4022         cfmt->custom_occurrence = 0;
4023         prefs.col_list = g_list_append(prefs.col_list, cfmt);
4024     }
4025     prefs.num_cols  = DEF_NUM_COLS;
4026
4027 /* set the default values for the capture dialog box */
4028     prefs.capture_prom_mode             = TRUE;
4029 #ifdef PCAP_NG_DEFAULT
4030     prefs.capture_pcap_ng               = TRUE;
4031 #else
4032     prefs.capture_pcap_ng               = FALSE;
4033 #endif
4034     prefs.capture_real_time             = TRUE;
4035     prefs.capture_auto_scroll           = TRUE;
4036     prefs.capture_show_info             = FALSE;
4037
4038     if (!prefs.capture_columns) {
4039         /* First time through */
4040         for (i = 0; i < num_capture_cols; i++) {
4041             col_name = g_strdup(capture_cols[i]);
4042             prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
4043         }
4044     }
4045
4046     prefs.console_log_level          =
4047         G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR;
4048
4049 /* set the default values for the tap/statistics dialog box */
4050     prefs.tap_update_interval    = TAP_UPDATE_DEFAULT_INTERVAL;
4051     prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE;
4052     prefs.st_enable_burstinfo = TRUE;
4053     prefs.st_burst_showcount = FALSE;
4054     prefs.st_burst_resolution = ST_DEF_BURSTRES;
4055     prefs.st_burst_windowlen = ST_DEF_BURSTLEN;
4056     prefs.st_sort_casesensitve = TRUE;
4057     prefs.st_sort_rng_fixorder = TRUE;
4058     prefs.st_sort_rng_nameonly = TRUE;
4059     prefs.st_sort_defcolflag = ST_SORT_COL_COUNT;
4060     prefs.st_sort_defdescending = TRUE;
4061     prefs.st_sort_showfullname = FALSE;
4062     prefs.display_hidden_proto_items = FALSE;
4063     prefs.display_byte_fields_with_spaces = FALSE;
4064 }
4065
4066 /*
4067  * Reset a single dissector preference.
4068  */
4069 void
4070 reset_pref(pref_t *pref)
4071 {
4072     int type;
4073     if (!pref) return;
4074
4075     type = pref->type;
4076
4077     /*
4078      * This preference is no longer supported; it's not a
4079      * real preference, so we don't reset it (i.e., we
4080      * treat it as if it weren't found in the list of
4081      * preferences, and we weren't called in the first place).
4082      */
4083     if (IS_PREF_OBSOLETE(type))
4084         return;
4085     else
4086         RESET_PREF_OBSOLETE(type);
4087
4088     switch (type) {
4089
4090     case PREF_UINT:
4091     case PREF_DECODE_AS_UINT:
4092         *pref->varp.uint = pref->default_val.uint;
4093         break;
4094
4095     case PREF_BOOL:
4096         *pref->varp.boolp = pref->default_val.boolval;
4097         break;
4098
4099     case PREF_ENUM:
4100         /*
4101          * For now, we save the "description" value, so that if we
4102          * save the preferences older versions of Wireshark can at
4103          * least read preferences that they supported; we support
4104          * either the short name or the description when reading
4105          * the preferences file or a "-o" option.
4106          */
4107         *pref->varp.enump = pref->default_val.enumval;
4108         break;
4109
4110     case PREF_STRING:
4111     case PREF_FILENAME:
4112     case PREF_DIRNAME:
4113         reset_string_like_preference(pref);
4114         break;
4115
4116     case PREF_RANGE:
4117     case PREF_DECODE_AS_RANGE:
4118         wmem_free(wmem_epan_scope(), *pref->varp.range);
4119         *pref->varp.range = range_copy(wmem_epan_scope(), pref->default_val.range);
4120         break;
4121
4122     case PREF_STATIC_TEXT:
4123     case PREF_UAT:
4124         /* Nothing to do */
4125         break;
4126
4127     case PREF_COLOR:
4128         *pref->varp.colorp = pref->default_val.color;
4129         break;
4130
4131     case PREF_CUSTOM:
4132         pref->custom_cbs.reset_cb(pref);
4133         break;
4134     }
4135 }
4136
4137 static void
4138 reset_pref_cb(gpointer data, gpointer user_data _U_)
4139 {
4140     pref_t *pref = (pref_t *) data;
4141     reset_pref(pref);
4142 }
4143
4144 typedef struct {
4145     module_t *module;
4146 } reset_pref_arg_t;
4147
4148 /*
4149  * Reset all preferences for a module.
4150  */
4151 static gboolean
4152 reset_module_prefs(const void *key _U_, void *value, void *data _U_)
4153 {
4154     reset_pref_arg_t arg;
4155
4156     arg.module = (module_t *)value;
4157     g_list_foreach(arg.module->prefs, reset_pref_cb, &arg);
4158     return FALSE;
4159 }
4160
4161 /* Reset preferences */
4162 void
4163 prefs_reset(void)
4164 {
4165     prefs_initialized = FALSE;
4166     g_free(prefs.saved_at_version);
4167     prefs.saved_at_version = NULL;
4168
4169     /*
4170      * Unload all UAT preferences.
4171      */
4172     uat_unload_all();
4173
4174     /*
4175      * Unload any loaded MIBs.
4176      */
4177     oids_cleanup();
4178
4179     /*
4180      * Free the filter expression list.
4181      */
4182     filter_expression_free(*pfilter_expression_head);
4183     *pfilter_expression_head = NULL;
4184
4185     /*
4186      * Reset the non-dissector preferences.
4187      */
4188     init_prefs();
4189
4190     /*
4191      * Reset the non-UAT dissector preferences.
4192      */
4193     wmem_tree_foreach(prefs_modules, reset_module_prefs, NULL);
4194 }
4195
4196 /* Read the preferences file, fill in "prefs", and return a pointer to it.
4197
4198    If we got an error (other than "it doesn't exist") we report it through
4199    the UI. */
4200 e_prefs *
4201 read_prefs(void)
4202 {
4203     int         err;
4204     char        *pf_path;
4205     FILE        *pf;
4206
4207     /* clean up libsmi structures before reading prefs */
4208     oids_cleanup();
4209
4210     init_prefs();
4211
4212     /*
4213      * If we don't already have the pathname of the global preferences
4214      * file, construct it.  Then, in either case, try to open the file.
4215      */
4216     if (gpf_path == NULL) {
4217         /*
4218          * We don't have the path; try the new path first, and, if that
4219          * file doesn't exist, try the old path.
4220          */
4221         gpf_path = get_datafile_path(PF_NAME);
4222         if ((pf = ws_fopen(gpf_path, "r")) == NULL && errno == ENOENT) {
4223             /*
4224              * It doesn't exist by the new name; try the old name.
4225              */
4226             g_free(gpf_path);
4227             gpf_path = get_datafile_path(OLD_GPF_NAME);
4228             pf = ws_fopen(gpf_path, "r");
4229         }
4230     } else {
4231         /*
4232          * We have the path; try it.
4233          */
4234         pf = ws_fopen(gpf_path, "r");
4235     }
4236
4237     /*
4238      * If we were able to open the file, read it.
4239      * XXX - if it failed for a reason other than "it doesn't exist",
4240      * report the error.
4241      */
4242     if (pf != NULL) {
4243         /*
4244          * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
4245          * seen.
4246          */
4247         mgcp_tcp_port_count = 0;
4248         mgcp_udp_port_count = 0;
4249
4250         /* We succeeded in opening it; read it. */
4251         err = read_prefs_file(gpf_path, pf, set_pref, NULL);
4252         if (err != 0) {
4253             /* We had an error reading the file; report it. */
4254             report_warning("Error reading global preferences file \"%s\": %s.",
4255                            gpf_path, g_strerror(err));
4256         }
4257         fclose(pf);
4258     } else {
4259         /* We failed to open it.  If we failed for some reason other than
4260            "it doesn't exist", report the error. */
4261         if (errno != ENOENT) {
4262             if (errno != 0) {
4263                 report_warning("Can't open global preferen