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