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