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