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