sq AD TYPE
[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/report_message.h>
36
37 #include <epan/prefs-int.h>
38 #include <epan/uat-int.h>
39
40 #include "epan/filter_expressions.h"
41
42 #include "epan/wmem/wmem.h"
43 #include <epan/stats_tree.h>
44
45 /*
46  * Module alias.
47  */
48 typedef struct pref_module_alias {
49     const char *name;           /**< name of module alias */
50     module_t *module;           /**< module for which it's an alias */
51 } module_alias_t;
52
53 /* Internal functions */
54 static module_t *find_subtree(module_t *parent, const char *tilte);
55 static module_t *prefs_register_module_or_subtree(module_t *parent,
56     const char *name, const char *title, const char *description, gboolean is_subtree,
57     void (*apply_cb)(void), gboolean use_gui);
58 static void prefs_register_modules(void);
59 static module_t *prefs_find_module_alias(const char *name);
60 static prefs_set_pref_e set_pref(gchar*, const gchar*, void *, gboolean);
61 static void free_col_info(GList *);
62 static void pre_init_prefs(void);
63 static gboolean prefs_is_column_visible(const gchar *cols_hidden, fmt_data *cfmt);
64 static gboolean parse_column_format(fmt_data *cfmt, const char *fmt);
65 static void try_convert_to_custom_column(gpointer *el_data);
66 static guint prefs_module_list_foreach(wmem_tree_t *module_list, module_cb callback,
67                           gpointer user_data, gboolean skip_obsolete);
68
69 #define IS_PREF_OBSOLETE(p) ((p) & PREF_OBSOLETE)
70 #define SET_PREF_OBSOLETE(p) ((p) |= PREF_OBSOLETE)
71 #define RESET_PREF_OBSOLETE(p) ((p) &= ~PREF_OBSOLETE)
72
73 #define PF_NAME         "preferences"
74 #define OLD_GPF_NAME    "wireshark.conf" /* old name for global preferences file */
75
76 static gboolean prefs_initialized = FALSE;
77 static gchar *gpf_path = NULL;
78 static gchar *cols_hidden_list = NULL;
79 static gboolean gui_theme_is_dark = FALSE;
80
81 /*
82  * XXX - variables to allow us to attempt to interpret the first
83  * "mgcp.{tcp,udp}.port" in a preferences file as
84  * "mgcp.{tcp,udp}.gateway_port" and the second as
85  * "mgcp.{tcp,udp}.callagent_port".
86  */
87 static int mgcp_tcp_port_count;
88 static int mgcp_udp_port_count;
89
90 e_prefs prefs;
91
92 static const enum_val_t gui_console_open_type[] = {
93     {"NEVER", "NEVER", console_open_never},
94     {"AUTOMATIC", "AUTOMATIC", console_open_auto},
95     {"ALWAYS", "ALWAYS", console_open_always},
96     {NULL, NULL, -1}
97 };
98
99 static const enum_val_t gui_version_placement_type[] = {
100     {"WELCOME", "WELCOME", version_welcome_only},
101     {"TITLE", "TITLE", version_title_only},
102     {"BOTH", "BOTH", version_both},
103     {"NEITHER", "NEITHER", version_neither},
104     {NULL, NULL, -1}
105 };
106
107 static const enum_val_t gui_fileopen_style[] = {
108     {"LAST_OPENED", "LAST_OPENED", 0},
109     {"SPECIFIED", "SPECIFIED", 1},
110     {NULL, NULL, -1}
111 };
112
113 static const enum_val_t gui_toolbar_style[] = {
114     {"ICONS", "ICONS", 0},
115     {"TEXT", "TEXT", 1},
116     {"BOTH", "BOTH", 2},
117     {NULL, NULL, -1}
118 };
119
120 static const enum_val_t gui_layout_content[] = {
121     {"NONE", "NONE", 0},
122     {"PLIST", "PLIST", 1},
123     {"PDETAILS", "PDETAILS", 2},
124     {"PBYTES", "PBYTES", 3},
125     {NULL, NULL, -1}
126 };
127
128 static const enum_val_t gui_update_channel[] = {
129     {"DEVELOPMENT", "DEVELOPMENT", UPDATE_CHANNEL_DEVELOPMENT},
130     {"STABLE", "STABLE", UPDATE_CHANNEL_STABLE},
131     {NULL, NULL, -1}
132 };
133
134 static const enum_val_t gui_selection_style[] = {
135     {"DEFAULT", "DEFAULT",   COLOR_STYLE_DEFAULT},
136     {"FLAT",    "FLAT",      COLOR_STYLE_FLAT},
137     {"GRADIENT", "GRADIENT", COLOR_STYLE_GRADIENT},
138     {NULL, NULL, -1}
139 };
140
141 #if defined(HAVE_PCAP_CREATE)
142 /* Can set monitor mode and buffer size. */
143 static gint num_capture_cols = 7;
144 static const gchar *capture_cols[7] = {
145     "INTERFACE",
146     "LINK",
147     "PMODE",
148     "SNAPLEN",
149     "MONITOR",
150     "BUFFER",
151     "FILTER"
152 };
153 #define CAPTURE_COL_TYPE_DESCRIPTION \
154     "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n"
155 #elif defined(CAN_SET_CAPTURE_BUFFER_SIZE)
156 /* Can set buffer size but not monitor mode. */
157 static gint num_capture_cols = 6;
158 static const gchar *capture_cols[6] = {
159     "INTERFACE",
160     "LINK",
161     "PMODE",
162     "SNAPLEN",
163     "BUFFER",
164     "FILTER"
165 };
166 #define CAPTURE_COL_TYPE_DESCRIPTION \
167     "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, BUFFER, FILTER\n"
168 #else
169 /* Can neither set buffer size nor monitor mode. */
170 static gint num_capture_cols = 5;
171 static const gchar *capture_cols[5] = {
172     "INTERFACE",
173     "LINK",
174     "PMODE",
175     "SNAPLEN",
176     "FILTER"
177 };
178 #define CAPTURE_COL_TYPE_DESCRIPTION \
179     "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, FILTER\n"
180 #endif
181
182 static const enum_val_t gui_packet_list_elide_mode[] = {
183     {"LEFT", "LEFT", ELIDE_LEFT},
184     {"RIGHT", "RIGHT", ELIDE_RIGHT},
185     {"MIDDLE", "MIDDLE", ELIDE_MIDDLE},
186     {"NONE", "NONE", ELIDE_NONE},
187     {NULL, NULL, -1}
188 };
189
190 /** Struct to hold preference data */
191 struct preference {
192     const char *name;                /**< name of preference */
193     const char *title;               /**< title to use in GUI */
194     const char *description;         /**< human-readable description of preference */
195     int ordinal;                     /**< ordinal number of this preference */
196     int type;                        /**< type of that preference */
197     unsigned int effect_flags;       /**< Flags of types effected by preference (PREF_TYPE_DISSECTION, PREF_EFFECT_CAPTURE, etc).
198                                           Flags must be non-zero to ensure saving to disk */
199     gui_type_t gui;                  /**< type of the GUI (QT, GTK or both) the preference is registered for */
200     union {                          /* The Qt preference code assumes that these will all be pointers (and unique) */
201         guint *uint;
202         gboolean *boolp;
203         gint *enump;
204         char **string;
205         range_t **range;
206         struct epan_uat* uat;
207         color_t *colorp;
208         GList** list;
209     } varp;                          /**< pointer to variable storing the value */
210     union {
211         guint uint;
212         gboolean boolval;
213         gint enumval;
214         char *string;
215         range_t *range;
216         color_t color;
217         GList* list;
218     } stashed_val;                     /**< original value, when editing from the GUI */
219     union {
220         guint uint;
221         gboolean boolval;
222         gint enumval;
223         char *string;
224         range_t *range;
225         color_t color;
226         GList* list;
227     } default_val;                   /**< the default value of the preference */
228     union {
229       guint base;                    /**< input/output base, for PREF_UINT */
230       guint32 max_value;             /**< maximum value of a range */
231       struct {
232         const enum_val_t *enumvals;  /**< list of name & values */
233         gboolean radio_buttons;      /**< TRUE if it should be shown as
234                                           radio buttons rather than as an
235                                           option menu or combo box in
236                                           the preferences tab */
237       } enum_info;                   /**< for PREF_ENUM */
238     } info;                          /**< display/text file information */
239     struct pref_custom_cbs custom_cbs;   /**< for PREF_CUSTOM */
240 };
241
242 const char* prefs_get_description(pref_t *pref)
243 {
244     return pref->description;
245 }
246
247 const char* prefs_get_title(pref_t *pref)
248 {
249     return pref->title;
250 }
251
252 int prefs_get_type(pref_t *pref)
253 {
254     return pref->type;
255 }
256
257 gui_type_t prefs_get_gui_type(pref_t *pref)
258 {
259     return pref->gui;
260 }
261
262 const char* prefs_get_name(pref_t *pref)
263 {
264     return pref->name;
265 }
266
267 guint32 prefs_get_max_value(pref_t *pref)
268 {
269     return pref->info.max_value;
270 }
271
272 /*
273  * List of all modules with preference settings.
274  */
275 static wmem_tree_t *prefs_modules = NULL;
276
277 /*
278  * List of all modules that should show up at the top level of the
279  * tree in the preference dialog box.
280  */
281 static wmem_tree_t *prefs_top_level_modules = NULL;
282
283 /*
284  * List of aliases for modules.
285  */
286 static wmem_tree_t *prefs_module_aliases = NULL;
287
288 /** Sets up memory used by proto routines. Called at program startup */
289 void
290 prefs_init(void)
291 {
292     memset(&prefs, 0, sizeof(prefs));
293     prefs_modules = wmem_tree_new(wmem_epan_scope());
294     prefs_top_level_modules = wmem_tree_new(wmem_epan_scope());
295     prefs_module_aliases = wmem_tree_new(wmem_epan_scope());
296 }
297
298 /*
299  * Free the strings for a string-like preference.
300  */
301 static void
302 free_string_like_preference(pref_t *pref)
303 {
304     g_free(*pref->varp.string);
305     *pref->varp.string = NULL;
306     g_free(pref->default_val.string);
307     pref->default_val.string = NULL;
308 }
309
310 static void
311 free_pref(gpointer data, gpointer user_data _U_)
312 {
313     pref_t *pref = (pref_t *)data;
314     int type = pref->type;
315
316     /* we reset the PREF_OBSOLETE bit in order to allow the original preference to be freed */
317     RESET_PREF_OBSOLETE(type);
318
319     switch (type) {
320     case PREF_BOOL:
321     case PREF_ENUM:
322     case PREF_UINT:
323     case PREF_DECODE_AS_UINT:
324     case PREF_STATIC_TEXT:
325     case PREF_UAT:
326     case PREF_COLOR:
327         break;
328     case PREF_STRING:
329     case PREF_SAVE_FILENAME:
330     case PREF_OPEN_FILENAME:
331     case PREF_DIRNAME:
332         free_string_like_preference(pref);
333         break;
334     case PREF_RANGE:
335     case PREF_DECODE_AS_RANGE:
336         wmem_free(wmem_epan_scope(), *pref->varp.range);
337         *pref->varp.range = NULL;
338         wmem_free(wmem_epan_scope(), pref->default_val.range);
339         pref->default_val.range = NULL;
340         break;
341     case PREF_CUSTOM:
342         if (strcmp(pref->name, "columns") == 0)
343           pref->stashed_val.boolval = TRUE;
344         pref->custom_cbs.free_cb(pref);
345         break;
346     }
347
348     g_free(pref);
349 }
350
351 static guint
352 free_module_prefs(module_t *module, gpointer data _U_)
353 {
354     if (module->prefs) {
355         g_list_foreach(module->prefs, free_pref, NULL);
356         g_list_free(module->prefs);
357     }
358     module->prefs = NULL;
359     module->numprefs = 0;
360     if (module->submodules) {
361         prefs_module_list_foreach(module->submodules, free_module_prefs, NULL, FALSE);
362     }
363     /*  We don't free the actual module: its submodules pointer points to
364         a wmem_tree and the module itself is stored in a wmem_tree
365      */
366
367     return 0;
368 }
369
370 /** Frees memory used by proto routines. Called at program shutdown */
371 void
372 prefs_cleanup(void)
373 {
374     /*  This isn't strictly necessary since we're exiting anyway, but let's
375      *  do what clean up we can.
376      */
377     prefs_module_list_foreach(prefs_modules, free_module_prefs, NULL, FALSE);
378
379     /* Clean the uats */
380     uat_cleanup();
381
382     /* Shut down mmdbresolve */
383     maxmind_db_pref_cleanup();
384
385     g_free(prefs.saved_at_version);
386     g_free(gpf_path);
387     gpf_path = NULL;
388 }
389
390 void prefs_set_gui_theme_is_dark(gboolean is_dark)
391 {
392     gui_theme_is_dark = is_dark;
393 }
394
395 /*
396  * Register a module that will have preferences.
397  * Specify the module under which to register it or NULL to register it
398  * at the top level, the name used for the module in the preferences file,
399  * the title used in the tab for it in a preferences dialog box, and a
400  * routine to call back when we apply the preferences.
401  */
402 static module_t *
403 prefs_register_module(module_t *parent, const char *name, const char *title,
404                       const char *description, void (*apply_cb)(void),
405                       const gboolean use_gui)
406 {
407     return prefs_register_module_or_subtree(parent, name, title, description,
408                                             FALSE, apply_cb, use_gui);
409 }
410
411 static void
412 prefs_deregister_module(module_t *parent, const char *name, const char *title)
413 {
414     /* Remove this module from the list of all modules */
415     module_t *module = (module_t *)wmem_tree_remove_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE);
416
417     if (!module)
418         return;
419
420     if (parent == NULL) {
421         /* Remove from top */
422         wmem_tree_remove_string(prefs_top_level_modules, title, WMEM_TREE_STRING_NOCASE);
423     } else if (parent->submodules) {
424         /* Remove from parent */
425         wmem_tree_remove_string(parent->submodules, title, WMEM_TREE_STRING_NOCASE);
426     }
427
428     free_module_prefs(module, NULL);
429     wmem_free(wmem_epan_scope(), module);
430 }
431
432 /*
433  * Register a subtree that will have modules under it.
434  * Specify the module under which to register it or NULL to register it
435  * at the top level and the title used in the tab for it in a preferences
436  * dialog box.
437  */
438 static module_t *
439 prefs_register_subtree(module_t *parent, const char *title, const char *description,
440                        void (*apply_cb)(void))
441 {
442     return prefs_register_module_or_subtree(parent, NULL, title, description,
443                                             TRUE, apply_cb,
444                                             parent ? parent->use_gui : FALSE);
445 }
446
447 static module_t *
448 prefs_register_module_or_subtree(module_t *parent, const char *name,
449                                  const char *title, const char *description,
450                                  gboolean is_subtree, void (*apply_cb)(void),
451                                  gboolean use_gui)
452 {
453     module_t *module;
454     const char *p;
455     guchar c;
456
457     /* this module may have been created as a subtree item previously */
458     if ((module = find_subtree(parent, title))) {
459         /* the module is currently a subtree */
460         module->name = name;
461         module->apply_cb = apply_cb;
462         module->description = description;
463
464         if (prefs_find_module(name) == NULL) {
465             wmem_tree_insert_string(prefs_modules, name, module,
466                                   WMEM_TREE_STRING_NOCASE);
467         }
468
469         return module;
470     }
471
472     module = wmem_new(wmem_epan_scope(), module_t);
473     module->name = name;
474     module->title = title;
475     module->description = description;
476     module->apply_cb = apply_cb;
477     module->prefs = NULL;    /* no preferences, to start */
478     module->parent = parent;
479     module->submodules = NULL;    /* no submodules, to start */
480     module->numprefs = 0;
481     module->prefs_changed_flags = 0;
482     module->obsolete = FALSE;
483     module->use_gui = use_gui;
484     /* A module's preferences affects dissection unless otherwise told */
485     module->effect_flags = PREF_EFFECT_DISSECTION;
486
487     /*
488      * Do we have a module name?
489      */
490     if (name != NULL) {
491         /*
492          * Yes.
493          * Make sure that only lower-case ASCII letters, numbers,
494          * underscores, hyphens, and dots appear in the name.
495          *
496          * Crash if there is, as that's an error in the code;
497          * you can make the title a nice string with capitalization,
498          * white space, punctuation, etc., but the name can be used
499          * on the command line, and shouldn't require quoting,
500          * shifting, etc.
501          */
502         for (p = name; (c = *p) != '\0'; p++) {
503             if (!(g_ascii_islower(c) || g_ascii_isdigit(c) || c == '_' ||
504                   c == '-' || c == '.'))
505                 g_error("Preference module \"%s\" contains invalid characters", name);
506         }
507
508         /*
509          * Make sure there's not already a module with that
510          * name.  Crash if there is, as that's an error in the
511          * code, and the code has to be fixed not to register
512          * more than one module with the same name.
513          *
514          * We search the list of all modules; the subtree stuff
515          * doesn't require preferences in subtrees to have names
516          * that reflect the subtree they're in (that would require
517          * protocol preferences to have a bogus "protocol.", or
518          * something such as that, to be added to all their names).
519          */
520         g_assert(prefs_find_module(name) == NULL);
521
522         /*
523          * Insert this module in the list of all modules.
524          */
525         wmem_tree_insert_string(prefs_modules, name, module, WMEM_TREE_STRING_NOCASE);
526     } else {
527         /*
528          * This has no name, just a title; check to make sure it's a
529          * subtree, and crash if it's not.
530          */
531         g_assert(is_subtree);
532     }
533
534     /*
535      * Insert this module into the appropriate place in the display
536      * tree.
537      */
538     if (parent == NULL) {
539         /*
540          * It goes at the top.
541          */
542         wmem_tree_insert_string(prefs_top_level_modules, title, module, WMEM_TREE_STRING_NOCASE);
543     } else {
544         /*
545          * It goes into the list for this module.
546          */
547
548         if (parent->submodules == NULL)
549             parent->submodules = wmem_tree_new(wmem_epan_scope());
550
551         wmem_tree_insert_string(parent->submodules, title, module, WMEM_TREE_STRING_NOCASE);
552     }
553
554     return module;
555 }
556
557 void
558 prefs_register_module_alias(const char *name, module_t *module)
559 {
560     module_alias_t *alias;
561     const char *p;
562     guchar c;
563
564     /*
565      * Yes.
566      * Make sure that only ASCII letters, numbers, underscores, hyphens,
567      * and dots appear in the name.  We allow upper-case letters, to
568      * handle the Diameter dissector having used "Diameter" rather
569      * than "diameter" as its preference module name in the past.
570      *
571      * Crash if there is, as that's an error in the code, but the name
572      * can be used on the command line, and shouldn't require quoting,
573      * etc.
574      */
575     for (p = name; (c = *p) != '\0'; p++) {
576         if (!(g_ascii_isalpha(c) || g_ascii_isdigit(c) || c == '_' ||
577               c == '-' || c == '.'))
578             g_error("Preference module alias \"%s\" contains invalid characters", name);
579     }
580
581     /*
582      * Make sure there's not already an alias with that
583      * name.  Crash if there is, as that's an error in the
584      * code, and the code has to be fixed not to register
585      * more than one alias with the same name.
586      *
587      * We search the list of all aliases.
588      */
589     g_assert(prefs_find_module_alias(name) == NULL);
590
591     alias = wmem_new(wmem_epan_scope(), module_alias_t);
592     alias->name = name;
593     alias->module = module;
594
595     /*
596      * Insert this module in the list of all modules.
597      */
598     wmem_tree_insert_string(prefs_module_aliases, name, alias, WMEM_TREE_STRING_NOCASE);
599 }
600
601 /*
602  * Register that a protocol has preferences.
603  */
604 module_t *protocols_module = NULL;
605
606 module_t *
607 prefs_register_protocol(int id, void (*apply_cb)(void))
608 {
609     protocol_t *protocol;
610
611     /*
612      * Have we yet created the "Protocols" subtree?
613      */
614     if (protocols_module == NULL) {
615         /*
616          * No.  Register Protocols subtree as well as any preferences
617          * for non-dissector modules.
618          */
619         pre_init_prefs();
620         prefs_register_modules();
621     }
622     protocol = find_protocol_by_id(id);
623     if (protocol == NULL)
624         g_error("Protocol preferences being registered with an invalid protocol ID");
625     return prefs_register_module(protocols_module,
626                                  proto_get_protocol_filter_name(id),
627                                  proto_get_protocol_short_name(protocol),
628                                  proto_get_protocol_name(id), apply_cb, TRUE);
629 }
630
631 void
632 prefs_deregister_protocol (int id)
633 {
634     protocol_t *protocol = find_protocol_by_id(id);
635     if (protocol == NULL)
636         g_error("Protocol preferences being de-registered with an invalid protocol ID");
637     prefs_deregister_module (protocols_module,
638                              proto_get_protocol_filter_name(id),
639                              proto_get_protocol_short_name(protocol));
640 }
641
642 module_t *
643 prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(void))
644 {
645     protocol_t *protocol;
646     module_t   *subtree_module;
647     module_t   *new_module;
648     char       *sep = NULL, *ptr = NULL, *orig = NULL;
649
650     /*
651      * Have we yet created the "Protocols" subtree?
652      * XXX - can we just do this by registering Protocols/{subtree}?
653      * If not, why not?
654      */
655     if (protocols_module == NULL) {
656         /*
657          * No.  Register Protocols subtree as well as any preferences
658          * for non-dissector modules.
659          */
660         pre_init_prefs();
661         prefs_register_modules();
662     }
663
664     subtree_module = protocols_module;
665
666     if (subtree) {
667         /* take a copy of the buffer, orig keeps a base pointer while ptr
668          * walks through the string */
669         orig = ptr = g_strdup(subtree);
670
671         while (ptr && *ptr) {
672
673             if ((sep = strchr(ptr, '/')))
674                 *sep++ = '\0';
675
676             if (!(new_module = find_subtree(subtree_module, ptr))) {
677                 /*
678                  * There's no such module; create it, with the description
679                  * being the name (if it's later registered explicitly
680                  * with a description, that will override it).
681                  */
682                 ptr = wmem_strdup(wmem_epan_scope(), ptr);
683                 new_module = prefs_register_subtree(subtree_module, ptr, ptr, NULL);
684             }
685
686             subtree_module = new_module;
687             ptr = sep;
688
689         }
690
691         g_free(orig);
692     }
693
694     protocol = find_protocol_by_id(id);
695     if (protocol == NULL)
696         g_error("Protocol subtree being registered with an invalid protocol ID");
697     return prefs_register_module(subtree_module,
698                                  proto_get_protocol_filter_name(id),
699                                  proto_get_protocol_short_name(protocol),
700                                  proto_get_protocol_name(id), apply_cb, TRUE);
701 }
702
703
704 /*
705  * Register that a protocol used to have preferences but no longer does,
706  * by creating an "obsolete" module for it.
707  */
708 module_t *
709 prefs_register_protocol_obsolete(int id)
710 {
711     module_t *module;
712     protocol_t *protocol;
713
714     /*
715      * Have we yet created the "Protocols" subtree?
716      */
717     if (protocols_module == NULL) {
718         /*
719          * No.  Register Protocols subtree as well as any preferences
720          * for non-dissector modules.
721          */
722         pre_init_prefs();
723         prefs_register_modules();
724     }
725     protocol = find_protocol_by_id(id);
726     if (protocol == NULL)
727         g_error("Protocol being registered with an invalid protocol ID");
728     module = prefs_register_module(protocols_module,
729                                    proto_get_protocol_filter_name(id),
730                                    proto_get_protocol_short_name(protocol),
731                                    proto_get_protocol_name(id), NULL, TRUE);
732     module->obsolete = TRUE;
733     return module;
734 }
735
736 /*
737  * Register that a statistical tap has preferences.
738  *
739  * "name" is a name for the tap to use on the command line with "-o"
740  * and in preference files.
741  *
742  * "title" is a short human-readable name for the tap.
743  *
744  * "description" is a longer human-readable description of the tap.
745  */
746 module_t *stats_module = NULL;
747
748 module_t *
749 prefs_register_stat(const char *name, const char *title,
750                     const char *description, void (*apply_cb)(void))
751 {
752     /*
753      * Have we yet created the "Statistics" subtree?
754      */
755     if (stats_module == NULL) {
756         /*
757          * No.  Register Statistics subtree as well as any preferences
758          * for non-dissector modules.
759          */
760         pre_init_prefs();
761         prefs_register_modules();
762     }
763
764     return prefs_register_module(stats_module, name, title, description,
765                                  apply_cb, TRUE);
766 }
767
768 /*
769  * Register that a codec has preferences.
770  *
771  * "name" is a name for the codec to use on the command line with "-o"
772  * and in preference files.
773  *
774  * "title" is a short human-readable name for the codec.
775  *
776  * "description" is a longer human-readable description of the codec.
777  */
778 module_t *codecs_module = NULL;
779
780 module_t *
781 prefs_register_codec(const char *name, const char *title,
782                      const char *description, void (*apply_cb)(void))
783 {
784     /*
785      * Have we yet created the "Codecs" subtree?
786      */
787     if (codecs_module == NULL) {
788         /*
789          * No.  Register Codecs subtree as well as any preferences
790          * for non-dissector modules.
791          */
792         pre_init_prefs();
793         prefs_register_modules();
794     }
795
796     return prefs_register_module(codecs_module, name, title, description,
797                                  apply_cb, TRUE);
798 }
799
800 module_t *
801 prefs_find_module(const char *name)
802 {
803     return (module_t *)wmem_tree_lookup_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE);
804 }
805
806 static module_t *
807 find_subtree(module_t *parent, const char *name)
808 {
809     return (module_t *)wmem_tree_lookup_string(parent ? parent->submodules : prefs_top_level_modules, name, WMEM_TREE_STRING_NOCASE);
810 }
811
812 /*
813  * Call a callback function, with a specified argument, for each module
814  * in a list of modules.  If the list is NULL, searches the top-level
815  * list in the display tree of modules.  If any callback returns a
816  * non-zero value, we stop and return that value, otherwise we
817  * return 0.
818  *
819  * Normally "obsolete" modules are ignored; their sole purpose is to allow old
820  * preferences for dissectors that no longer have preferences to be
821  * silently ignored in preference files.  Does not ignore subtrees,
822  * as this can be used when walking the display tree of modules.
823  */
824
825 typedef struct {
826     module_cb callback;
827     gpointer user_data;
828     guint ret;
829     gboolean skip_obsolete;
830 } call_foreach_t;
831
832 static gboolean
833 call_foreach_cb(const void *key _U_, void *value, void *data)
834 {
835     module_t *module = (module_t*)value;
836     call_foreach_t *call_data = (call_foreach_t*)data;
837
838     if (!call_data->skip_obsolete || !module->obsolete)
839         call_data->ret = (*call_data->callback)(module, call_data->user_data);
840
841     return (call_data->ret != 0);
842 }
843
844 static guint
845 prefs_module_list_foreach(wmem_tree_t *module_list, module_cb callback,
846                           gpointer user_data, gboolean skip_obsolete)
847 {
848     call_foreach_t call_data;
849
850     if (module_list == NULL)
851         module_list = prefs_top_level_modules;
852
853     call_data.callback = callback;
854     call_data.user_data = user_data;
855     call_data.ret = 0;
856     call_data.skip_obsolete = skip_obsolete;
857     wmem_tree_foreach(module_list, call_foreach_cb, &call_data);
858     return call_data.ret;
859 }
860
861 /*
862  * Returns TRUE if module has any submodules
863  */
864 gboolean
865 prefs_module_has_submodules(module_t *module)
866 {
867     if (module->submodules == NULL) {
868         return FALSE;
869     }
870
871     if (wmem_tree_is_empty(module->submodules)) {
872         return FALSE;
873     }
874
875     return TRUE;
876 }
877
878 /*
879  * Call a callback function, with a specified argument, for each module
880  * in the list of all modules.  (This list does not include subtrees.)
881  *
882  * Ignores "obsolete" modules; their sole purpose is to allow old
883  * preferences for dissectors that no longer have preferences to be
884  * silently ignored in preference files.
885  */
886 guint
887 prefs_modules_foreach(module_cb callback, gpointer user_data)
888 {
889     return prefs_module_list_foreach(prefs_modules, callback, user_data, TRUE);
890 }
891
892 /*
893  * Call a callback function, with a specified argument, for each submodule
894  * of specified modules.  If the module is NULL, goes through the top-level
895  * list in the display tree of modules.
896  *
897  * Ignores "obsolete" modules; their sole purpose is to allow old
898  * preferences for dissectors that no longer have preferences to be
899  * silently ignored in preference files.  Does not ignore subtrees,
900  * as this can be used when walking the display tree of modules.
901  */
902 guint
903 prefs_modules_foreach_submodules(module_t *module, module_cb callback,
904                                  gpointer user_data)
905 {
906     return prefs_module_list_foreach((module)?module->submodules:prefs_top_level_modules, callback, user_data, TRUE);
907 }
908
909 static gboolean
910 call_apply_cb(const void *key _U_, void *value, void *data _U_)
911 {
912     module_t *module = (module_t *)value;
913
914     if (module->obsolete)
915         return FALSE;
916     if (module->prefs_changed_flags) {
917         if (module->apply_cb != NULL)
918             (*module->apply_cb)();
919         module->prefs_changed_flags = 0;
920     }
921     if (module->submodules)
922         wmem_tree_foreach(module->submodules, call_apply_cb, NULL);
923     return FALSE;
924 }
925
926 /*
927  * Call the "apply" callback function for each module if any of its
928  * preferences have changed, and then clear the flag saying its
929  * preferences have changed, as the module has been notified of that
930  * fact.
931  */
932 void
933 prefs_apply_all(void)
934 {
935     wmem_tree_foreach(prefs_modules, call_apply_cb, NULL);
936 }
937
938 /*
939  * Call the "apply" callback function for a specific module if any of
940  * its preferences have changed, and then clear the flag saying its
941  * preferences have changed, as the module has been notified of that
942  * fact.
943  */
944 void
945 prefs_apply(module_t *module)
946 {
947     if (module && module->prefs_changed_flags)
948         call_apply_cb(NULL, module, NULL);
949 }
950
951 static module_t *
952 prefs_find_module_alias(const char *name)
953 {
954     module_alias_t *alias;
955
956     alias = (module_alias_t *)wmem_tree_lookup_string(prefs_module_aliases, name, WMEM_TREE_STRING_NOCASE);
957     if (alias == NULL)
958         return NULL;
959     return alias->module;
960 }
961
962 /*
963  * Register a preference in a module's list of preferences.
964  * If it has a title, give it an ordinal number; otherwise, it's a
965  * preference that won't show up in the UI, so it shouldn't get an
966  * ordinal number (the ordinal should be the ordinal in the set of
967  * *visible* preferences).
968  */
969 static pref_t *
970 register_preference(module_t *module, const char *name, const char *title,
971                     const char *description, int type)
972 {
973     pref_t *preference;
974     const gchar *p;
975     const char *name_prefix = (module->name != NULL) ? module->name : module->parent->name;
976
977     preference = g_new(pref_t,1);
978     preference->name = name;
979     preference->title = title;
980     preference->description = description;
981     preference->type = type;
982     /* Default to module's preference effects */
983     preference->effect_flags = module->effect_flags;
984
985     preference->gui = GUI_ALL;  /* default */
986     if (title != NULL)
987         preference->ordinal = module->numprefs;
988     else
989         preference->ordinal = -1;    /* no ordinal for you */
990
991     /*
992      * Make sure that only lower-case ASCII letters, numbers,
993      * underscores, and dots appear in the preference name.
994      *
995      * Crash if there is, as that's an error in the code;
996      * you can make the title and description nice strings
997      * with capitalization, white space, punctuation, etc.,
998      * but the name can be used on the command line,
999      * and shouldn't require quoting, shifting, etc.
1000      */
1001     for (p = name; *p != '\0'; p++)
1002         if (!(g_ascii_islower(*p) || g_ascii_isdigit(*p) || *p == '_' || *p == '.'))
1003             g_error("Preference \"%s.%s\" contains invalid characters", module->name, name);
1004
1005     /*
1006      * Make sure there's not already a preference with that
1007      * name.  Crash if there is, as that's an error in the
1008      * code, and the code has to be fixed not to register
1009      * more than one preference with the same name.
1010      */
1011     if (prefs_find_preference(module, name) != NULL)
1012         g_error("Preference %s has already been registered", name);
1013
1014     if ((!IS_PREF_OBSOLETE(type)) &&
1015         /* Don't compare if it's a subtree */
1016         (module->name != NULL)) {
1017         /*
1018          * Make sure the preference name doesn't begin with the
1019          * module name, as that's redundant and Just Silly.
1020          */
1021         if (!((strncmp(name, module->name, strlen(module->name)) != 0) ||
1022             (((name[strlen(module->name)]) != '.') && ((name[strlen(module->name)]) != '_'))))
1023             g_error("Preference %s begins with the module name", name);
1024     }
1025
1026     /* The title shows up in the preferences dialog. Make sure it's UI-friendly. */
1027     if (preference->title) {
1028         const char *cur_char;
1029         if (preference->type != PREF_STATIC_TEXT && g_utf8_strlen(preference->title, -1) > 80) { // Arbitrary.
1030             g_error("Title for preference %s.%s is too long: %s", name_prefix, preference->name, preference->title);
1031         }
1032
1033         if (!g_utf8_validate(preference->title, -1, NULL)) {
1034             g_error("Title for preference %s.%s isn't valid UTF-8.", name_prefix, preference->name);
1035         }
1036
1037         for (cur_char = preference->title; *cur_char; cur_char = g_utf8_next_char(cur_char)) {
1038             if (!g_unichar_isprint(g_utf8_get_char(cur_char))) {
1039                 g_error("Title for preference %s.%s isn't printable UTF-8.", name_prefix, preference->name);
1040             }
1041         }
1042     }
1043
1044     if (preference->description) {
1045         if (!g_utf8_validate(preference->description, -1, NULL)) {
1046             g_error("Description for preference %s.%s isn't valid UTF-8.", name_prefix, preference->name);
1047         }
1048     }
1049
1050     /*
1051      * We passed all of our checks. Add the preference.
1052      */
1053     module->prefs = g_list_append(module->prefs, preference);
1054     if (title != NULL)
1055         module->numprefs++;
1056
1057     return preference;
1058 }
1059
1060 /*
1061  * Find a preference in a module's list of preferences, given the module
1062  * and the preference's name.
1063  */
1064 typedef struct {
1065     GList *list_entry;
1066     const char *name;
1067     module_t *submodule;
1068 } find_pref_arg_t;
1069
1070 static gint
1071 preference_match(gconstpointer a, gconstpointer b)
1072 {
1073     const pref_t *pref = (const pref_t *)a;
1074     const char *name = (const char *)b;
1075
1076     return strcmp(name, pref->name);
1077 }
1078
1079 static gboolean
1080 module_find_pref_cb(const void *key _U_, void *value, void *data)
1081 {
1082     find_pref_arg_t* arg = (find_pref_arg_t*)data;
1083     GList *list_entry;
1084     module_t *module = (module_t *)value;
1085
1086     if (module == NULL)
1087         return FALSE;
1088
1089     list_entry = g_list_find_custom(module->prefs, arg->name,
1090         preference_match);
1091
1092     if (list_entry == NULL)
1093         return FALSE;
1094
1095     arg->list_entry = list_entry;
1096     arg->submodule = module;
1097     return TRUE;
1098 }
1099
1100 /* Tries to find a preference, setting containing_module to the (sub)module
1101  * holding this preference. */
1102 static struct preference *
1103 prefs_find_preference_with_submodule(module_t *module, const char *name,
1104         module_t **containing_module)
1105 {
1106     find_pref_arg_t arg;
1107     GList *list_entry;
1108
1109     if (module == NULL)
1110         return NULL;    /* invalid parameters */
1111
1112     list_entry = g_list_find_custom(module->prefs, name,
1113         preference_match);
1114     arg.submodule = NULL;
1115
1116     if (list_entry == NULL)
1117     {
1118         arg.list_entry = NULL;
1119         if (module->submodules != NULL)
1120         {
1121             arg.name = name;
1122             wmem_tree_foreach(module->submodules, module_find_pref_cb, &arg);
1123         }
1124
1125         list_entry = arg.list_entry;
1126     }
1127
1128     if (list_entry == NULL)
1129         return NULL;    /* no such preference */
1130
1131     if (containing_module)
1132         *containing_module = arg.submodule ? arg.submodule : module;
1133
1134     return (struct preference *) list_entry->data;
1135 }
1136
1137 struct preference *
1138 prefs_find_preference(module_t *module, const char *name)
1139 {
1140     return prefs_find_preference_with_submodule(module, name, NULL);
1141 }
1142
1143 /*
1144  * Returns TRUE if the given protocol has registered preferences
1145  */
1146 gboolean
1147 prefs_is_registered_protocol(const char *name)
1148 {
1149     module_t *m = prefs_find_module(name);
1150
1151     return (m != NULL && !m->obsolete);
1152 }
1153
1154 /*
1155  * Returns the module title of a registered protocol
1156  */
1157 const char *
1158 prefs_get_title_by_name(const char *name)
1159 {
1160     module_t *m = prefs_find_module(name);
1161
1162     return (m != NULL && !m->obsolete) ? m->title : NULL;
1163 }
1164
1165 /*
1166  * Register a preference with an unsigned integral value.
1167  */
1168 void
1169 prefs_register_uint_preference(module_t *module, const char *name,
1170                                const char *title, const char *description,
1171                                guint base, guint *var)
1172 {
1173     pref_t *preference;
1174
1175     preference = register_preference(module, name, title, description,
1176                                      PREF_UINT);
1177     preference->varp.uint = var;
1178     preference->default_val.uint = *var;
1179     g_assert(base > 0 && base != 1 && base < 37);
1180     preference->info.base = base;
1181 }
1182
1183 /*
1184  * XXX Add a prefs_register_{uint16|port}_preference which sets max_value?
1185  */
1186
1187
1188 /*
1189  * Register a "custom" preference with a unsigned integral value.
1190  * XXX - This should be temporary until we can find a better way
1191  * to do "custom" preferences
1192  */
1193 static void
1194 prefs_register_uint_custom_preference(module_t *module, const char *name,
1195                                       const char *title, const char *description,
1196                                       struct pref_custom_cbs* custom_cbs, guint *var)
1197 {
1198     pref_t *preference;
1199
1200     preference = register_preference(module, name, title, description,
1201                                      PREF_CUSTOM);
1202
1203     preference->custom_cbs = *custom_cbs;
1204     preference->varp.uint = var;
1205     preference->default_val.uint = *var;
1206 }
1207
1208 /*
1209  * Register a preference with an Boolean value.
1210  */
1211 void
1212 prefs_register_bool_preference(module_t *module, const char *name,
1213                                const char *title, const char *description,
1214                                gboolean *var)
1215 {
1216     pref_t *preference;
1217
1218     preference = register_preference(module, name, title, description,
1219                                      PREF_BOOL);
1220     preference->varp.boolp = var;
1221     preference->default_val.boolval = *var;
1222 }
1223
1224 unsigned int prefs_set_bool_value(pref_t *pref, gboolean value, pref_source_t source)
1225 {
1226     unsigned int changed = 0;
1227
1228     switch (source)
1229     {
1230     case pref_default:
1231         if (pref->default_val.boolval != value) {
1232             pref->default_val.boolval = value;
1233             changed = prefs_get_effect_flags(pref);
1234         }
1235         break;
1236     case pref_stashed:
1237         if (pref->stashed_val.boolval != value) {
1238             pref->stashed_val.boolval = value;
1239             changed = prefs_get_effect_flags(pref);
1240         }
1241         break;
1242     case pref_current:
1243         if (*pref->varp.boolp != value) {
1244             *pref->varp.boolp = value;
1245             changed = prefs_get_effect_flags(pref);
1246         }
1247         break;
1248     default:
1249         g_assert_not_reached();
1250         break;
1251     }
1252
1253     return changed;
1254 }
1255
1256 void prefs_invert_bool_value(pref_t *pref, pref_source_t source)
1257 {
1258     switch (source)
1259     {
1260     case pref_default:
1261         pref->default_val.boolval = !pref->default_val.boolval;
1262         break;
1263     case pref_stashed:
1264         pref->stashed_val.boolval = !pref->stashed_val.boolval;
1265         break;
1266     case pref_current:
1267         *pref->varp.boolp = !(*pref->varp.boolp);
1268         break;
1269     default:
1270         g_assert_not_reached();
1271         break;
1272     }
1273 }
1274
1275 gboolean prefs_get_bool_value(pref_t *pref, pref_source_t source)
1276 {
1277     switch (source)
1278     {
1279     case pref_default:
1280         return pref->default_val.boolval;
1281         break;
1282     case pref_stashed:
1283         return pref->stashed_val.boolval;
1284         break;
1285     case pref_current:
1286         return *pref->varp.boolp;
1287         break;
1288     default:
1289         g_assert_not_reached();
1290         break;
1291     }
1292
1293     return FALSE;
1294 }
1295
1296 /*
1297  * Register a preference with an enumerated value.
1298  */
1299 /*
1300  * XXX Should we get rid of the radio_buttons parameter and make that
1301  * behavior automatic depending on the number of items?
1302  */
1303 void
1304 prefs_register_enum_preference(module_t *module, const char *name,
1305                                const char *title, const char *description,
1306                                gint *var, const enum_val_t *enumvals,
1307                                gboolean radio_buttons)
1308 {
1309     pref_t *preference;
1310
1311     preference = register_preference(module, name, title, description,
1312                                      PREF_ENUM);
1313     preference->varp.enump = var;
1314     preference->default_val.enumval = *var;
1315     preference->info.enum_info.enumvals = enumvals;
1316     preference->info.enum_info.radio_buttons = radio_buttons;
1317 }
1318
1319 unsigned int prefs_set_enum_value(pref_t *pref, gint value, pref_source_t source)
1320 {
1321     unsigned int changed = 0;
1322
1323     switch (source)
1324     {
1325     case pref_default:
1326         if (pref->default_val.enumval != value) {
1327             pref->default_val.enumval = value;
1328             changed = prefs_get_effect_flags(pref);
1329         }
1330         break;
1331     case pref_stashed:
1332         if (pref->stashed_val.enumval != value) {
1333             pref->stashed_val.enumval = value;
1334             changed = prefs_get_effect_flags(pref);
1335         }
1336         break;
1337     case pref_current:
1338         if (*pref->varp.enump != value) {
1339             *pref->varp.enump = value;
1340             changed = prefs_get_effect_flags(pref);
1341         }
1342         break;
1343     default:
1344         g_assert_not_reached();
1345         break;
1346     }
1347
1348     return changed;
1349 }
1350
1351 gint prefs_get_enum_value(pref_t *pref, pref_source_t source)
1352 {
1353     switch (source)
1354     {
1355     case pref_default:
1356         return pref->default_val.enumval;
1357         break;
1358     case pref_stashed:
1359         return pref->stashed_val.enumval;
1360         break;
1361     case pref_current:
1362         return *pref->varp.enump;
1363         break;
1364     default:
1365         g_assert_not_reached();
1366         break;
1367     }
1368
1369     return 0;
1370 }
1371
1372 const enum_val_t* prefs_get_enumvals(pref_t *pref)
1373 {
1374     return pref->info.enum_info.enumvals;
1375 }
1376
1377 gboolean prefs_get_enum_radiobuttons(pref_t *pref)
1378 {
1379     return pref->info.enum_info.radio_buttons;
1380 }
1381
1382 static void
1383 register_string_like_preference(module_t *module, const char *name,
1384                                 const char *title, const char *description,
1385                                 char **var, int type,
1386                                 struct pref_custom_cbs* custom_cbs,
1387                                 gboolean free_tmp)
1388 {
1389     pref_t *pref;
1390     gchar *tmp;
1391
1392     pref = register_preference(module, name, title, description, type);
1393
1394     /*
1395      * String preference values should be non-null (as you can't
1396      * keep them null after using the preferences GUI, you can at best
1397      * have them be null strings) and freeable (as we free them
1398      * if we change them).
1399      *
1400      * If the value is a null pointer, make it a copy of a null
1401      * string, otherwise make it a copy of the value.
1402      */
1403     tmp = *var;
1404     if (*var == NULL) {
1405         *var = g_strdup("");
1406     } else {
1407         *var = g_strdup(*var);
1408     }
1409     if (free_tmp) {
1410         g_free(tmp);
1411     }
1412     pref->varp.string = var;
1413     pref->default_val.string = g_strdup(*var);
1414     pref->stashed_val.string = NULL;
1415     if (type == PREF_CUSTOM) {
1416         g_assert(custom_cbs);
1417         pref->custom_cbs = *custom_cbs;
1418     }
1419 }
1420
1421 /*
1422  * Assign to a string preference.
1423  */
1424 static void
1425 pref_set_string_like_pref_value(pref_t *pref, const gchar *value)
1426 {
1427 DIAG_OFF(cast-qual)
1428     g_free((void *)*pref->varp.string);
1429 DIAG_ON(cast-qual)
1430     *pref->varp.string = g_strdup(value);
1431 }
1432
1433 /*
1434  * For use by UI code that sets preferences.
1435  */
1436 unsigned int
1437 prefs_set_string_value(pref_t *pref, const char* value, pref_source_t source)
1438 {
1439     unsigned int changed = 0;
1440
1441     switch (source)
1442     {
1443     case pref_default:
1444         if (*pref->default_val.string) {
1445             if (strcmp(pref->default_val.string, value) != 0) {
1446                 changed = prefs_get_effect_flags(pref);
1447                 g_free(pref->default_val.string);
1448                 pref->default_val.string = g_strdup(value);
1449             }
1450         } else if (value) {
1451             pref->default_val.string = g_strdup(value);
1452         }
1453         break;
1454     case pref_stashed:
1455         if (pref->stashed_val.string) {
1456             if (strcmp(pref->stashed_val.string, value) != 0) {
1457                 changed = prefs_get_effect_flags(pref);
1458                 g_free(pref->stashed_val.string);
1459                 pref->stashed_val.string = g_strdup(value);
1460             }
1461         } else if (value) {
1462             pref->stashed_val.string = g_strdup(value);
1463         }
1464         break;
1465     case pref_current:
1466         if (*pref->varp.string) {
1467             if (strcmp(*pref->varp.string, value) != 0) {
1468                 changed = prefs_get_effect_flags(pref);
1469                 pref_set_string_like_pref_value(pref, value);
1470             }
1471         } else if (value) {
1472             pref_set_string_like_pref_value(pref, value);
1473         }
1474         break;
1475     default:
1476         g_assert_not_reached();
1477         break;
1478     }
1479
1480     return changed;
1481 }
1482
1483 char* prefs_get_string_value(pref_t *pref, pref_source_t source)
1484 {
1485     switch (source)
1486     {
1487     case pref_default:
1488         return pref->default_val.string;
1489     case pref_stashed:
1490         return pref->stashed_val.string;
1491     case pref_current:
1492         return *pref->varp.string;
1493     default:
1494         g_assert_not_reached();
1495         break;
1496     }
1497
1498     return NULL;
1499 }
1500
1501 /*
1502  * Reset the value of a string-like preference.
1503  */
1504 static void
1505 reset_string_like_preference(pref_t *pref)
1506 {
1507     g_free(*pref->varp.string);
1508     *pref->varp.string = g_strdup(pref->default_val.string);
1509 }
1510
1511 /*
1512  * Register a preference with a character-string value.
1513  */
1514 void
1515 prefs_register_string_preference(module_t *module, const char *name,
1516                                  const char *title, const char *description,
1517                                  const char **var)
1518 {
1519 DIAG_OFF(cast-qual)
1520     register_string_like_preference(module, name, title, description,
1521                                     (char **)var, PREF_STRING, NULL, FALSE);
1522 DIAG_ON(cast-qual)
1523 }
1524
1525 /*
1526  * Register a preference with a file name (string) value.
1527  */
1528 void
1529 prefs_register_filename_preference(module_t *module, const char *name,
1530                                    const char *title, const char *description,
1531                                    const char **var, gboolean for_writing)
1532 {
1533 DIAG_OFF(cast-qual)
1534     register_string_like_preference(module, name, title, description, (char **)var,
1535                                     for_writing ? PREF_SAVE_FILENAME : PREF_OPEN_FILENAME, NULL, FALSE);
1536 DIAG_ON(cast-qual)
1537 }
1538
1539 /*
1540  * Register a preference with a directory name (string) value.
1541  */
1542 void
1543 prefs_register_directory_preference(module_t *module, const char *name,
1544                                    const char *title, const char *description,
1545                                    const char **var)
1546 {
1547 DIAG_OFF(cast-qual)
1548     register_string_like_preference(module, name, title, description,
1549                                     (char **)var, PREF_DIRNAME, NULL, FALSE);
1550 DIAG_ON(cast-qual)
1551 }
1552
1553 /* Refactoring to handle both PREF_RANGE and PREF_DECODE_AS_RANGE */
1554 static void
1555 prefs_register_range_preference_common(module_t *module, const char *name,
1556                                 const char *title, const char *description,
1557                                 range_t **var, guint32 max_value, int type)
1558 {
1559     pref_t *preference;
1560
1561     preference = register_preference(module, name, title, description, type);
1562     preference->info.max_value = max_value;
1563
1564     /*
1565      * Range preference values should be non-null (as you can't
1566      * keep them null after using the preferences GUI, you can at best
1567      * have them be empty ranges) and freeable (as we free them
1568      * if we change them).
1569      *
1570      * If the value is a null pointer, make it an empty range.
1571      */
1572     if (*var == NULL)
1573         *var = range_empty(wmem_epan_scope());
1574     preference->varp.range = var;
1575     preference->default_val.range = range_copy(wmem_epan_scope(), *var);
1576     preference->stashed_val.range = NULL;
1577 }
1578
1579 /*
1580  * Register a preference with a ranged value.
1581  */
1582 void
1583 prefs_register_range_preference(module_t *module, const char *name,
1584                                 const char *title, const char *description,
1585                                 range_t **var, guint32 max_value)
1586 {
1587     prefs_register_range_preference_common(module, name, title,
1588                 description, var, max_value, PREF_RANGE);
1589 }
1590
1591 gboolean
1592 prefs_set_range_value_work(pref_t *pref, const gchar *value,
1593                            gboolean return_range_errors, unsigned int *changed_flags)
1594 {
1595     range_t *newrange;
1596
1597     if (range_convert_str_work(wmem_epan_scope(), &newrange, value, pref->info.max_value,
1598                                return_range_errors) != CVT_NO_ERROR) {
1599         return FALSE;        /* number was bad */
1600     }
1601
1602     if (!ranges_are_equal(*pref->varp.range, newrange)) {
1603         *changed_flags |= prefs_get_effect_flags(pref);
1604         wmem_free(wmem_epan_scope(), *pref->varp.range);
1605         *pref->varp.range = newrange;
1606     } else {
1607         wmem_free(wmem_epan_scope(), newrange);
1608     }
1609     return TRUE;
1610 }
1611
1612 /*
1613  * For use by UI code that sets preferences.
1614  */
1615 unsigned int
1616 prefs_set_stashed_range_value(pref_t *pref, const gchar *value)
1617 {
1618     range_t *newrange;
1619
1620     if (range_convert_str_work(wmem_epan_scope(), &newrange, value, pref->info.max_value,
1621                                TRUE) != CVT_NO_ERROR) {
1622         return 0;        /* number was bad */
1623     }
1624
1625     if (!ranges_are_equal(pref->stashed_val.range, newrange)) {
1626         wmem_free(wmem_epan_scope(), pref->stashed_val.range);
1627         pref->stashed_val.range = newrange;
1628     } else {
1629         wmem_free(wmem_epan_scope(), newrange);
1630     }
1631     return prefs_get_effect_flags(pref);
1632
1633 }
1634
1635 gboolean prefs_set_range_value(pref_t *pref, range_t *value, pref_source_t source)
1636 {
1637     gboolean changed = FALSE;
1638
1639     switch (source)
1640     {
1641     case pref_default:
1642         if (!ranges_are_equal(pref->default_val.range, value)) {
1643             wmem_free(wmem_epan_scope(), pref->default_val.range);
1644             pref->default_val.range = range_copy(wmem_epan_scope(), value);
1645             changed = TRUE;
1646         }
1647         break;
1648     case pref_stashed:
1649         if (!ranges_are_equal(pref->stashed_val.range, value)) {
1650             wmem_free(wmem_epan_scope(), pref->stashed_val.range);
1651             pref->stashed_val.range = range_copy(wmem_epan_scope(), value);
1652             changed = TRUE;
1653         }
1654         break;
1655     case pref_current:
1656         if (!ranges_are_equal(*pref->varp.range, value)) {
1657             wmem_free(wmem_epan_scope(), *pref->varp.range);
1658             *pref->varp.range = range_copy(wmem_epan_scope(), value);
1659             changed = TRUE;
1660         }
1661         break;
1662     default:
1663         g_assert_not_reached();
1664         break;
1665     }
1666
1667     return changed;
1668 }
1669
1670 range_t* prefs_get_range_value_real(pref_t *pref, pref_source_t source)
1671 {
1672     switch (source)
1673     {
1674     case pref_default:
1675         return pref->default_val.range;
1676     case pref_stashed:
1677         return pref->stashed_val.range;
1678         break;
1679     case pref_current:
1680         return *pref->varp.range;
1681         break;
1682     default:
1683         g_assert_not_reached();
1684         break;
1685     }
1686
1687     return NULL;
1688 }
1689
1690 range_t* prefs_get_range_value(const char *module_name, const char* pref_name)
1691 {
1692     return prefs_get_range_value_real(prefs_find_preference(prefs_find_module(module_name), pref_name), pref_current);
1693 }
1694
1695 void
1696 prefs_range_add_value(pref_t *pref, guint32 val)
1697 {
1698     range_add_value(wmem_epan_scope(), pref->varp.range, val);
1699 }
1700
1701 void
1702 prefs_range_remove_value(pref_t *pref, guint32 val)
1703 {
1704     range_remove_value(wmem_epan_scope(), pref->varp.range, val);
1705 }
1706
1707 /*
1708  * Register a static text 'preference'.  It can be used to add explanatory
1709  * text inline with other preferences in the GUI.
1710  * Note: Static preferences are not saved to the preferences file.
1711  */
1712 void
1713 prefs_register_static_text_preference(module_t *module, const char *name,
1714                                       const char *title,
1715                                       const char *description)
1716 {
1717     register_preference(module, name, title, description, PREF_STATIC_TEXT);
1718 }
1719
1720 /*
1721  * Register a uat 'preference'. It adds a button that opens the uat's window in the
1722  * preferences tab of the module.
1723  */
1724 extern void
1725 prefs_register_uat_preference(module_t *module, const char *name,
1726                               const char *title, const char *description,
1727                               uat_t* uat)
1728 {
1729
1730     pref_t* preference = register_preference(module, name, title, description, PREF_UAT);
1731
1732     preference->varp.uat = uat;
1733 }
1734
1735 /*
1736  * Register a uat 'preference' for QT only. It adds a button that opens the uat's window in the
1737  * preferences tab of the module.
1738  */
1739 extern void
1740 prefs_register_uat_preference_qt(module_t *module, const char *name,
1741                               const char *title, const char *description,
1742                               uat_t* uat)
1743 {
1744
1745     pref_t* preference = register_preference(module, name, title, description, PREF_UAT);
1746
1747     preference->varp.uat = uat;
1748
1749     preference->gui = GUI_QT;
1750 }
1751
1752 struct epan_uat* prefs_get_uat_value(pref_t *pref)
1753 {
1754     return pref->varp.uat;
1755 }
1756
1757 /*
1758  * Register a color preference.
1759  */
1760 void
1761 prefs_register_color_preference(module_t *module, const char *name,
1762                                 const char *title, const char *description,
1763                                 color_t *color)
1764 {
1765     pref_t* preference = register_preference(module, name, title, description, PREF_COLOR);
1766
1767     preference->varp.colorp = color;
1768     preference->default_val.color = *color;
1769 }
1770
1771 gboolean prefs_set_color_value(pref_t *pref, color_t value, pref_source_t source)
1772 {
1773     gboolean changed = FALSE;
1774
1775     switch (source)
1776     {
1777     case pref_default:
1778         if ((pref->default_val.color.red != value.red) ||
1779             (pref->default_val.color.green != value.green) ||
1780             (pref->default_val.color.blue != value.blue)) {
1781             changed = TRUE;
1782             pref->default_val.color = value;
1783         }
1784         break;
1785     case pref_stashed:
1786         if ((pref->stashed_val.color.red != value.red) ||
1787             (pref->stashed_val.color.green != value.green) ||
1788             (pref->stashed_val.color.blue != value.blue)) {
1789             changed = TRUE;
1790             pref->stashed_val.color = value;
1791         }
1792         break;
1793     case pref_current:
1794         if ((pref->varp.colorp->red != value.red) ||
1795             (pref->varp.colorp->green != value.green) ||
1796             (pref->varp.colorp->blue != value.blue)) {
1797             changed = TRUE;
1798             *pref->varp.colorp = value;
1799         }
1800         break;
1801     default:
1802         g_assert_not_reached();
1803         break;
1804     }
1805
1806     return changed;
1807 }
1808
1809 color_t* prefs_get_color_value(pref_t *pref, pref_source_t source)
1810 {
1811     switch (source)
1812     {
1813     case pref_default:
1814         return &pref->default_val.color;
1815     case pref_stashed:
1816         return &pref->stashed_val.color;
1817         break;
1818     case pref_current:
1819         return pref->varp.colorp;
1820         break;
1821     default:
1822         g_assert_not_reached();
1823         break;
1824     }
1825
1826     return NULL;
1827 }
1828
1829 /*
1830  * Register a "custom" preference with a list.
1831  * XXX - This should be temporary until we can find a better way
1832  * to do "custom" preferences
1833  */
1834 typedef void (*pref_custom_list_init_cb) (pref_t* pref, GList** value);
1835
1836 static void
1837 prefs_register_list_custom_preference(module_t *module, const char *name,
1838                                       const char *title, const char *description,
1839                                       struct pref_custom_cbs* custom_cbs,
1840                                       pref_custom_list_init_cb init_cb,
1841                                       GList** list)
1842 {
1843     pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM);
1844
1845     preference->custom_cbs = *custom_cbs;
1846     init_cb(preference, list);
1847 }
1848
1849 /*
1850  * Register a custom preference.
1851  */
1852 void
1853 prefs_register_custom_preference(module_t *module, const char *name,
1854                                  const char *title, const char *description,
1855                                  struct pref_custom_cbs* custom_cbs,
1856                                  void **custom_data _U_)
1857 {
1858     pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM);
1859
1860     preference->custom_cbs = *custom_cbs;
1861     /* XXX - wait until we can handle void** pointers
1862     preference->custom_cbs.init_cb(preference, custom_data);
1863     */
1864 }
1865
1866 /*
1867  * Register a (internal) "Decode As" preference with a ranged value.
1868  */
1869 void prefs_register_decode_as_range_preference(module_t *module, const char *name,
1870     const char *title, const char *description, range_t **var,
1871     guint32 max_value)
1872 {
1873     prefs_register_range_preference_common(module, name, title,
1874                 description, var, max_value, PREF_DECODE_AS_RANGE);
1875 }
1876
1877 /*
1878  * Register a (internal) "Decode As" preference with an unsigned integral value
1879  * for a dissector table.
1880  */
1881 void prefs_register_decode_as_preference(module_t *module, const char *name,
1882     const char *title, const char *description, guint *var)
1883 {
1884     pref_t *preference;
1885
1886     preference = register_preference(module, name, title, description,
1887                                      PREF_DECODE_AS_UINT);
1888     preference->varp.uint = var;
1889     preference->default_val.uint = *var;
1890     /* XXX - Presume base 10 for now */
1891     preference->info.base = 10;
1892 }
1893
1894 gboolean prefs_add_decode_as_value(pref_t *pref, guint value, gboolean replace)
1895 {
1896     switch(pref->type)
1897     {
1898     case PREF_DECODE_AS_UINT:
1899         /* This doesn't support multiple values for a dissector in Decode As because the
1900             preference only supports a single value. This leads to a "last port for
1901             dissector in Decode As wins" */
1902         *pref->varp.uint = value;
1903         break;
1904     case PREF_DECODE_AS_RANGE:
1905         if (replace)
1906         {
1907             /* If range has single value, replace it */
1908             if (((*pref->varp.range)->nranges == 1) &&
1909                 ((*pref->varp.range)->ranges[0].low == (*pref->varp.range)->ranges[0].high)) {
1910                 wmem_free(wmem_epan_scope(), *pref->varp.range);
1911                 *pref->varp.range = range_empty(wmem_epan_scope());
1912             }
1913         }
1914
1915         prefs_range_add_value(pref, value);
1916         break;
1917     default:
1918         /* XXX - Worth asserting over? */
1919         break;
1920     }
1921
1922     return TRUE;
1923 }
1924
1925 gboolean prefs_remove_decode_as_value(pref_t *pref, guint value, gboolean set_default)
1926 {
1927     switch(pref->type)
1928     {
1929     case PREF_DECODE_AS_UINT:
1930         if (set_default) {
1931             *pref->varp.uint = pref->default_val.uint;
1932         } else {
1933             *pref->varp.uint = 0;
1934         }
1935         break;
1936     case PREF_DECODE_AS_RANGE:
1937         prefs_range_remove_value(pref, value);
1938         break;
1939     default:
1940         break;
1941     }
1942
1943     return TRUE;
1944 }
1945
1946 /*
1947  * Register a preference that used to be supported but no longer is.
1948  */
1949 void
1950 prefs_register_obsolete_preference(module_t *module, const char *name)
1951 {
1952     register_preference(module, name, NULL, NULL, PREF_OBSOLETE);
1953 }
1954
1955 /*
1956  * Check to see if a preference is obsolete.
1957  */
1958 extern gboolean
1959 prefs_get_preference_obsolete(pref_t *pref)
1960 {
1961     if (pref)
1962         return (IS_PREF_OBSOLETE(pref->type) ? TRUE : FALSE);
1963
1964     return TRUE;
1965 }
1966
1967 /*
1968  * Make a preference obsolete.
1969  */
1970 extern prefs_set_pref_e
1971 prefs_set_preference_obsolete(pref_t *pref)
1972 {
1973     if (pref) {
1974         SET_PREF_OBSOLETE(pref->type);
1975         return PREFS_SET_OK;
1976     }
1977     return PREFS_SET_NO_SUCH_PREF;
1978 }
1979
1980 guint
1981 pref_stash(pref_t *pref, gpointer unused _U_)
1982 {
1983     switch (pref->type) {
1984
1985     case PREF_DECODE_AS_UINT:
1986         pref->stashed_val.uint = *pref->varp.uint;
1987         break;
1988
1989     case PREF_UINT:
1990         pref->stashed_val.uint = *pref->varp.uint;
1991         break;
1992
1993     case PREF_BOOL:
1994         pref->stashed_val.boolval = *pref->varp.boolp;
1995         break;
1996
1997     case PREF_ENUM:
1998         pref->stashed_val.enumval = *pref->varp.enump;
1999         break;
2000
2001     case PREF_STRING:
2002     case PREF_SAVE_FILENAME:
2003     case PREF_OPEN_FILENAME:
2004     case PREF_DIRNAME:
2005         g_free(pref->stashed_val.string);
2006         pref->stashed_val.string = g_strdup(*pref->varp.string);
2007         break;
2008
2009     case PREF_DECODE_AS_RANGE:
2010     case PREF_RANGE:
2011         wmem_free(wmem_epan_scope(), pref->stashed_val.range);
2012         pref->stashed_val.range = range_copy(wmem_epan_scope(), *pref->varp.range);
2013         break;
2014
2015     case PREF_COLOR:
2016         pref->stashed_val.color = *pref->varp.colorp;
2017         break;
2018
2019     case PREF_STATIC_TEXT:
2020     case PREF_UAT:
2021     case PREF_CUSTOM:
2022         break;
2023
2024     case PREF_OBSOLETE:
2025         g_assert_not_reached();
2026         break;
2027     }
2028     return 0;
2029 }
2030
2031 guint
2032 pref_unstash(pref_t *pref, gpointer unstash_data_p)
2033 {
2034     pref_unstash_data_t *unstash_data = (pref_unstash_data_t *)unstash_data_p;
2035     dissector_table_t sub_dissectors = NULL;
2036     dissector_handle_t handle = NULL;
2037
2038     /* Revert the preference to its saved value. */
2039     switch (pref->type) {
2040
2041     case PREF_DECODE_AS_UINT:
2042         if (*pref->varp.uint != pref->stashed_val.uint) {
2043             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2044
2045             if (unstash_data->handle_decode_as) {
2046                 if (*pref->varp.uint != pref->default_val.uint) {
2047                     dissector_reset_uint(pref->name, *pref->varp.uint);
2048                 }
2049             }
2050
2051             *pref->varp.uint = pref->stashed_val.uint;
2052
2053             if (unstash_data->handle_decode_as) {
2054                 sub_dissectors = find_dissector_table(pref->name);
2055                 if (sub_dissectors != NULL) {
2056                     handle = dissector_table_get_dissector_handle(sub_dissectors, unstash_data->module->title);
2057                     if (handle != NULL) {
2058                         dissector_change_uint(pref->name, *pref->varp.uint, handle);
2059                     }
2060                 }
2061             }
2062         }
2063         break;
2064
2065     case PREF_UINT:
2066         if (*pref->varp.uint != pref->stashed_val.uint) {
2067             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2068             *pref->varp.uint = pref->stashed_val.uint;
2069         }
2070         break;
2071
2072     case PREF_BOOL:
2073         if (*pref->varp.boolp != pref->stashed_val.boolval) {
2074             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2075             *pref->varp.boolp = pref->stashed_val.boolval;
2076         }
2077         break;
2078
2079     case PREF_ENUM:
2080         if (*pref->varp.enump != pref->stashed_val.enumval) {
2081             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2082             *pref->varp.enump = pref->stashed_val.enumval;
2083         }
2084         break;
2085
2086     case PREF_STRING:
2087     case PREF_SAVE_FILENAME:
2088     case PREF_OPEN_FILENAME:
2089     case PREF_DIRNAME:
2090         if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0) {
2091             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2092             g_free(*pref->varp.string);
2093             *pref->varp.string = g_strdup(pref->stashed_val.string);
2094         }
2095         break;
2096
2097     case PREF_DECODE_AS_RANGE:
2098         if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2099             guint32 i, j;
2100             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2101
2102             if (unstash_data->handle_decode_as) {
2103                 sub_dissectors = find_dissector_table(pref->name);
2104                 if (sub_dissectors != NULL) {
2105                     handle = dissector_table_get_dissector_handle(sub_dissectors, unstash_data->module->title);
2106                     if (handle != NULL) {
2107                         /* Delete all of the old values from the dissector table */
2108                         for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2109                             for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2110                                 dissector_delete_uint(pref->name, j, handle);
2111                                 decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j), NULL, NULL);
2112                             }
2113
2114                             dissector_delete_uint(pref->name, (*pref->varp.range)->ranges[i].high, handle);
2115                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high), NULL, NULL);
2116                         }
2117                     }
2118                 }
2119             }
2120
2121             wmem_free(wmem_epan_scope(), *pref->varp.range);
2122             *pref->varp.range = range_copy(wmem_epan_scope(), pref->stashed_val.range);
2123
2124             if (unstash_data->handle_decode_as) {
2125                 if ((sub_dissectors != NULL) && (handle != NULL)) {
2126
2127                     /* Add new values to the dissector table */
2128                     for (i = 0; i < (*pref->varp.range)->nranges; i++) {
2129
2130                         for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
2131                             dissector_change_uint(pref->name, j, handle);
2132                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j), NULL, NULL);
2133                         }
2134
2135                         dissector_change_uint(pref->name, (*pref->varp.range)->ranges[i].high, handle);
2136                         decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high), NULL, NULL);
2137                     }
2138                 }
2139             }
2140         }
2141         break;
2142
2143     case PREF_RANGE:
2144         if (!ranges_are_equal(*pref->varp.range, pref->stashed_val.range)) {
2145             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2146             wmem_free(wmem_epan_scope(), *pref->varp.range);
2147             *pref->varp.range = range_copy(wmem_epan_scope(), pref->stashed_val.range);
2148         }
2149     break;
2150
2151     case PREF_COLOR:
2152         if ((pref->varp.colorp->blue != pref->stashed_val.color.blue) ||
2153             (pref->varp.colorp->red != pref->stashed_val.color.red) ||
2154             (pref->varp.colorp->green != pref->stashed_val.color.green)) {
2155             unstash_data->module->prefs_changed_flags |= prefs_get_effect_flags(pref);
2156             *pref->varp.colorp = pref->stashed_val.color;
2157         }
2158         break;
2159
2160     case PREF_STATIC_TEXT:
2161     case PREF_UAT:
2162     case PREF_CUSTOM:
2163         break;
2164
2165     case PREF_OBSOLETE:
2166         g_assert_not_reached();
2167         break;
2168     }
2169     return 0;
2170 }
2171
2172 void
2173 reset_stashed_pref(pref_t *pref) {
2174     switch (pref->type) {
2175
2176     case PREF_DECODE_AS_UINT:
2177         pref->stashed_val.uint = pref->default_val.uint;
2178         break;
2179
2180     case PREF_UINT:
2181         pref->stashed_val.uint = pref->default_val.uint;
2182         break;
2183
2184     case PREF_BOOL:
2185         pref->stashed_val.boolval = pref->default_val.boolval;
2186         break;
2187
2188     case PREF_ENUM:
2189         pref->stashed_val.enumval = pref->default_val.enumval;
2190         break;
2191
2192     case PREF_STRING:
2193     case PREF_SAVE_FILENAME:
2194     case PREF_OPEN_FILENAME:
2195     case PREF_DIRNAME:
2196         g_free(pref->stashed_val.string);
2197         pref->stashed_val.string = g_strdup(pref->default_val.string);
2198         break;
2199
2200     case PREF_DECODE_AS_RANGE:
2201     case PREF_RANGE:
2202         wmem_free(wmem_epan_scope(), pref->stashed_val.range);
2203         pref->stashed_val.range = range_copy(wmem_epan_scope(), pref->default_val.range);
2204         break;
2205
2206     case PREF_COLOR:
2207         memcpy(&pref->stashed_val.color, &pref->default_val.color, sizeof(color_t));
2208         break;
2209
2210     case PREF_STATIC_TEXT:
2211     case PREF_UAT:
2212     case PREF_CUSTOM:
2213         break;
2214
2215     case PREF_OBSOLETE:
2216         g_assert_not_reached();
2217         break;
2218     }
2219 }
2220
2221 guint
2222 pref_clean_stash(pref_t *pref, gpointer unused _U_)
2223 {
2224     switch (pref->type) {
2225
2226     case PREF_UINT:
2227     case PREF_DECODE_AS_UINT:
2228         break;
2229
2230     case PREF_BOOL:
2231         break;
2232
2233     case PREF_ENUM:
2234         break;
2235
2236     case PREF_STRING:
2237     case PREF_SAVE_FILENAME:
2238     case PREF_OPEN_FILENAME:
2239     case PREF_DIRNAME:
2240         if (pref->stashed_val.string != NULL) {
2241             g_free(pref->stashed_val.string);
2242             pref->stashed_val.string = NULL;
2243         }
2244         break;
2245
2246     case PREF_DECODE_AS_RANGE:
2247     case PREF_RANGE:
2248         if (pref->stashed_val.range != NULL) {
2249             wmem_free(wmem_epan_scope(), pref->stashed_val.range);
2250             pref->stashed_val.range = NULL;
2251         }
2252         break;
2253
2254     case PREF_STATIC_TEXT:
2255     case PREF_UAT:
2256     case PREF_COLOR:
2257     case PREF_CUSTOM:
2258         break;
2259
2260     case PREF_OBSOLETE:
2261         g_assert_not_reached();
2262         break;
2263     }
2264     return 0;
2265 }
2266
2267 #if 0
2268 /* Return the value assigned to the given uint preference. */
2269 guint
2270 prefs_get_uint_preference(pref_t *pref)
2271 {
2272     if (pref && pref->type == PREF_UINT)
2273         return *pref->varp.uint;
2274     return 0;
2275 }
2276 #endif
2277
2278 /*
2279  * Call a callback function, with a specified argument, for each preference
2280  * in a given module.
2281  *
2282  * If any of the callbacks return a non-zero value, stop and return that
2283  * value, otherwise return 0.
2284  */
2285 guint
2286 prefs_pref_foreach(module_t *module, pref_cb callback, gpointer user_data)
2287 {
2288     GList *elem;
2289     pref_t *pref;
2290     guint ret;
2291
2292     for (elem = g_list_first(module->prefs); elem != NULL; elem = g_list_next(elem)) {
2293         pref = (pref_t *)elem->data;
2294         if (IS_PREF_OBSOLETE(pref->type)) {
2295             /*
2296              * This preference is no longer supported; it's
2297              * not a real preference, so we don't call the
2298              * callback for it (i.e., we treat it as if it
2299              * weren't found in the list of preferences,
2300              * and we weren't called in the first place).
2301              */
2302             continue;
2303         }
2304
2305         ret = (*callback)(pref, user_data);
2306         if (ret != 0)
2307             return ret;
2308     }
2309     return 0;
2310 }
2311
2312 static const enum_val_t st_sort_col_vals[] = {
2313     { "name",    "Node name (topic/item)", ST_SORT_COL_NAME },
2314     { "count",   "Item count", ST_SORT_COL_COUNT },
2315     { "average", "Average value of the node", ST_SORT_COL_AVG },
2316     { "min",     "Minimum value of the node", ST_SORT_COL_MIN },
2317     { "max",     "Maximum value of the node", ST_SORT_COL_MAX },
2318     { "burst",   "Burst rate of the node", ST_SORT_COL_BURSTRATE },
2319     { NULL,      NULL,         0 }
2320 };
2321
2322 static void
2323 stats_callback(void)
2324 {
2325     /* Test for a sane tap update interval */
2326     if (prefs.tap_update_interval < 100 || prefs.tap_update_interval > 10000)
2327         prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL;
2328
2329     /* burst resolution can't be less than 1 (ms) */
2330     if (prefs.st_burst_resolution < 1) {
2331         prefs.st_burst_resolution = 1;
2332     }
2333     else if (prefs.st_burst_resolution > ST_MAX_BURSTRES) {
2334         prefs.st_burst_resolution = ST_MAX_BURSTRES;
2335     }
2336     /* make sure burst window value makes sense */
2337     if (prefs.st_burst_windowlen < prefs.st_burst_resolution) {
2338         prefs.st_burst_windowlen = prefs.st_burst_resolution;
2339     }
2340     /* round burst window down to multiple of resolution */
2341     prefs.st_burst_windowlen -= prefs.st_burst_windowlen%prefs.st_burst_resolution;
2342     if ((prefs.st_burst_windowlen/prefs.st_burst_resolution) > ST_MAX_BURSTBUCKETS) {
2343         prefs.st_burst_windowlen = prefs.st_burst_resolution*ST_MAX_BURSTBUCKETS;
2344     }
2345 }
2346
2347 static void
2348 gui_callback(void)
2349 {
2350     /* Ensure there is at least one file count */
2351     if (prefs.gui_recent_files_count_max == 0)
2352       prefs.gui_recent_files_count_max = 10;
2353
2354     /* Ensure there is at least one display filter entry */
2355     if (prefs.gui_recent_df_entries_max == 0)
2356       prefs.gui_recent_df_entries_max = 10;
2357 }
2358
2359 static void
2360 gui_layout_callback(void)
2361 {
2362     if (prefs.gui_layout_type == layout_unused ||
2363         prefs.gui_layout_type >= layout_type_max) {
2364       /* XXX - report an error?  It's not a syntax error - we'd need to
2365          add a way of reporting a *semantic* error. */
2366       prefs.gui_layout_type = layout_type_5;
2367     }
2368 }
2369
2370 /******************************************************
2371  * All custom preference function callbacks
2372  ******************************************************/
2373 static void custom_pref_no_cb(pref_t* pref _U_) {}
2374
2375
2376 /*
2377  * Console log level custom preference functions
2378  */
2379 static void
2380 console_log_level_reset_cb(pref_t* pref)
2381 {
2382     *pref->varp.uint = pref->default_val.uint;
2383 }
2384
2385 static prefs_set_pref_e
2386 console_log_level_set_cb(pref_t* pref, const gchar* value, unsigned int* changed_flags)
2387 {
2388     guint    uval;
2389
2390     if (!ws_strtou32(value, NULL, &uval))
2391         return PREFS_SET_SYNTAX_ERR;        /* number was bad */
2392
2393     if (*pref->varp.uint != uval) {
2394         *changed_flags = prefs_get_effect_flags(pref);
2395         *pref->varp.uint = uval;
2396     }
2397
2398     if (*pref->varp.uint & (G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG)) {
2399       /*
2400        * GLib >= 2.32 drops INFO and DEBUG messages by default. Tell
2401        * it not to do that.
2402        */
2403        g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
2404     }
2405
2406     return PREFS_SET_OK;
2407 }
2408
2409 static const char * console_log_level_type_name_cb(void) {
2410     return "Log level";
2411 }
2412
2413 static char * console_log_level_type_description_cb(void) {
2414     return g_strdup_printf(
2415         "Console log level (for debugging)\n"
2416         "A bitmask of log levels:\n"
2417         "ERROR    = 4\n"
2418         "CRITICAL = 8\n"
2419         "WARNING  = 16\n"
2420         "MESSAGE  = 32\n"
2421         "INFO     = 64\n"
2422         "DEBUG    = 128");
2423 }
2424
2425 static gboolean console_log_level_is_default_cb(pref_t* pref) {
2426     return *pref->varp.uint == pref->default_val.uint;
2427 }
2428
2429 static char * console_log_level_to_str_cb(pref_t* pref, gboolean default_val) {
2430     return g_strdup_printf("%u",  default_val ? pref->default_val.uint : *pref->varp.uint);
2431 }
2432
2433 /*
2434  * Column preference functions
2435  */
2436 #define PRS_COL_HIDDEN                   "column.hidden"
2437 #define PRS_COL_FMT                      "column.format"
2438 #define PRS_COL_NUM                      "column.number"
2439 static module_t *gui_column_module = NULL;
2440
2441 static prefs_set_pref_e
2442 column_hidden_set_cb(pref_t* pref, const gchar* value, unsigned int* changed_flags)
2443 {
2444     GList       *clp;
2445     fmt_data    *cfmt;
2446     pref_t  *format_pref;
2447
2448     (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2449
2450     /*
2451      * Set the "visible" flag for the existing columns; we need to
2452      * do this if we set PRS_COL_HIDDEN but don't set PRS_COL_FMT
2453      * after setting it (which might be the case if, for example, we
2454      * set PRS_COL_HIDDEN on the command line).
2455      */
2456     format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT);
2457     for (clp = *format_pref->varp.list; clp != NULL; clp = clp->next) {
2458       cfmt = (fmt_data *)clp->data;
2459       cfmt->visible = prefs_is_column_visible(*pref->varp.string, cfmt);
2460     }
2461
2462     return PREFS_SET_OK;
2463 }
2464
2465 static const char *
2466 column_hidden_type_name_cb(void)
2467 {
2468     return "Packet list hidden columns";
2469 }
2470
2471 static char *
2472 column_hidden_type_description_cb(void)
2473 {
2474     return g_strdup("List all columns to hide in the packet list.");
2475 }
2476
2477 static char *
2478 column_hidden_to_str_cb(pref_t* pref, gboolean default_val)
2479 {
2480     GString     *cols_hidden = g_string_new ("");
2481     GList       *clp;
2482     fmt_data    *cfmt;
2483     pref_t  *format_pref;
2484
2485     if (default_val)
2486         return g_strdup(pref->default_val.string);
2487
2488     format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT);
2489     clp = (format_pref) ? *format_pref->varp.list : NULL;
2490     while (clp) {
2491         gchar *prefs_fmt;
2492         cfmt = (fmt_data *) clp->data;
2493         if ((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) {
2494             prefs_fmt = g_strdup_printf("%s:%s:%d:%c",
2495                     col_format_to_string(cfmt->fmt),
2496                     cfmt->custom_fields,
2497                     cfmt->custom_occurrence,
2498                     cfmt->resolved ? 'R' : 'U');
2499         } else {
2500             prefs_fmt = g_strdup(col_format_to_string(cfmt->fmt));
2501         }
2502         if (!cfmt->visible) {
2503             if (cols_hidden->len)
2504                 g_string_append (cols_hidden, ",");
2505             g_string_append (cols_hidden, prefs_fmt);
2506         }
2507         g_free(prefs_fmt);
2508         clp = clp->next;
2509     }
2510
2511     return g_string_free (cols_hidden, FALSE);
2512 }
2513
2514 static gboolean
2515 column_hidden_is_default_cb(pref_t* pref)
2516 {
2517     char *cur_hidden_str = column_hidden_to_str_cb(pref, FALSE);
2518     gboolean is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
2519
2520     g_free(cur_hidden_str);
2521     return is_default;
2522 }
2523
2524
2525 /* Number of columns "preference".  This is only used internally and is not written to the
2526  * preference file
2527  */
2528 static void
2529 column_num_reset_cb(pref_t* pref)
2530 {
2531     *pref->varp.uint = pref->default_val.uint;
2532 }
2533
2534 static prefs_set_pref_e
2535 column_num_set_cb(pref_t* pref _U_, const gchar* value _U_, unsigned int* changed_flags _U_)
2536 {
2537     /* Don't write this to the preferences file */
2538     return PREFS_SET_OK;
2539 }
2540
2541 static const char *
2542 column_num_type_name_cb(void)
2543 {
2544     return NULL;
2545 }
2546
2547 static char *
2548 column_num_type_description_cb(void)
2549 {
2550     return g_strdup("");
2551 }
2552
2553 static gboolean
2554 column_num_is_default_cb(pref_t* pref _U_)
2555 {
2556     return TRUE;
2557 }
2558
2559 static char *
2560 column_num_to_str_cb(pref_t* pref _U_, gboolean default_val _U_)
2561 {
2562     return g_strdup("");
2563 }
2564
2565 /*
2566  * Column format custom preference functions
2567  */
2568 static void
2569 column_format_init_cb(pref_t* pref, GList** value)
2570 {
2571     fmt_data *src_cfmt, *dest_cfmt;
2572     GList *entry;
2573
2574     pref->varp.list = value;
2575
2576     pref->default_val.list = NULL;
2577     for (entry = *pref->varp.list; entry != NULL; entry = g_list_next(entry)) {
2578         src_cfmt = (fmt_data *)entry->data;
2579         dest_cfmt = g_new(fmt_data,1);
2580         dest_cfmt->title = g_strdup(src_cfmt->title);
2581         dest_cfmt->fmt = src_cfmt->fmt;
2582         if (src_cfmt->custom_fields) {
2583             dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields);
2584             dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2585         } else {
2586             dest_cfmt->custom_fields = NULL;
2587             dest_cfmt->custom_occurrence = 0;
2588         }
2589         dest_cfmt->visible = src_cfmt->visible;
2590         dest_cfmt->resolved = src_cfmt->resolved;
2591         pref->default_val.list = g_list_append(pref->default_val.list, dest_cfmt);
2592     }
2593 }
2594
2595 static void
2596 column_format_free_cb(pref_t* pref)
2597 {
2598     free_col_info(*pref->varp.list);
2599     free_col_info(pref->default_val.list);
2600 }
2601
2602 static void
2603 column_format_reset_cb(pref_t* pref)
2604 {
2605     fmt_data *src_cfmt, *dest_cfmt;
2606     GList *entry;
2607     pref_t  *col_num_pref;
2608
2609     free_col_info(*pref->varp.list);
2610     *pref->varp.list = NULL;
2611
2612     for (entry = pref->default_val.list; entry != NULL; entry = g_list_next(entry)) {
2613         src_cfmt = (fmt_data *)entry->data;
2614         dest_cfmt = g_new(fmt_data,1);
2615         dest_cfmt->title = g_strdup(src_cfmt->title);
2616         dest_cfmt->fmt = src_cfmt->fmt;
2617         if (src_cfmt->custom_fields) {
2618             dest_cfmt->custom_fields = g_strdup(src_cfmt->custom_fields);
2619             dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
2620         } else {
2621             dest_cfmt->custom_fields = NULL;
2622             dest_cfmt->custom_occurrence = 0;
2623         }
2624         dest_cfmt->visible = src_cfmt->visible;
2625         dest_cfmt->resolved = src_cfmt->resolved;
2626         *pref->varp.list = g_list_append(*pref->varp.list, dest_cfmt);
2627     }
2628
2629     col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
2630     g_assert(col_num_pref != NULL); /* Should never happen */
2631     column_num_reset_cb(col_num_pref);
2632 }
2633
2634 static prefs_set_pref_e
2635 column_format_set_cb(pref_t* pref, const gchar* value, unsigned int* changed_flags _U_)
2636 {
2637     GList    *col_l, *col_l_elt;
2638     fmt_data *cfmt;
2639     gint     llen;
2640     pref_t   *hidden_pref, *col_num_pref;
2641
2642     col_l = prefs_get_string_list(value);
2643     if (col_l == NULL)
2644       return PREFS_SET_SYNTAX_ERR;
2645     if ((g_list_length(col_l) % 2) != 0) {
2646       /* A title didn't have a matching format.  */
2647       prefs_clear_string_list(col_l);
2648       return PREFS_SET_SYNTAX_ERR;
2649     }
2650     /* Check to make sure all column formats are valid.  */
2651     col_l_elt = g_list_first(col_l);
2652     while (col_l_elt) {
2653       fmt_data cfmt_check;
2654
2655       /* Go past the title.  */
2656       col_l_elt = col_l_elt->next;
2657
2658       /* Parse the format to see if it's valid.  */
2659       if (!parse_column_format(&cfmt_check, (char *)col_l_elt->data)) {
2660         /* It's not a valid column format.  */
2661         prefs_clear_string_list(col_l);
2662         return PREFS_SET_SYNTAX_ERR;
2663       }
2664       if (cfmt_check.fmt != COL_CUSTOM) {
2665         /* Some predefined columns have been migrated to use custom columns.
2666          * We'll convert these silently here */
2667         try_convert_to_custom_column(&col_l_elt->data);
2668       } else {
2669         /* We don't need the custom column field on this pass. */
2670         g_free(cfmt_check.custom_fields);
2671       }
2672
2673       /* Go past the format.  */
2674       col_l_elt = col_l_elt->next;
2675     }
2676
2677     /* They're all valid; process them. */
2678     free_col_info(*pref->varp.list);
2679     *pref->varp.list = NULL;
2680     hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN);
2681     g_assert(hidden_pref != NULL); /* Should never happen */
2682     col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
2683     g_assert(col_num_pref != NULL); /* Should never happen */
2684     llen             = g_list_length(col_l);
2685     *col_num_pref->varp.uint = llen / 2;
2686     col_l_elt = g_list_first(col_l);
2687     while (col_l_elt) {
2688       cfmt           = g_new(fmt_data,1);
2689       cfmt->title    = g_strdup((gchar *)col_l_elt->data);
2690       col_l_elt      = col_l_elt->next;
2691       parse_column_format(cfmt, (char *)col_l_elt->data);
2692       cfmt->visible   = prefs_is_column_visible(*hidden_pref->varp.string, cfmt);
2693       col_l_elt      = col_l_elt->next;
2694       *pref->varp.list = g_list_append(*pref->varp.list, cfmt);
2695     }
2696
2697     prefs_clear_string_list(col_l);
2698     free_string_like_preference(hidden_pref);
2699     return PREFS_SET_OK;
2700 }
2701
2702
2703 static const char *
2704 column_format_type_name_cb(void)
2705 {
2706     return "Packet list column format";
2707 }
2708
2709 static char *
2710 column_format_type_description_cb(void)
2711 {
2712     return g_strdup("Each pair of strings consists of a column title and its format");
2713 }
2714
2715 static gboolean
2716 column_format_is_default_cb(pref_t* pref)
2717 {
2718     GList       *clp = *pref->varp.list,
2719                 *pref_col = g_list_first(clp),
2720                 *def_col = g_list_first(pref->default_val.list);
2721     fmt_data    *cfmt, *def_cfmt;
2722     gboolean    is_default = TRUE;
2723     pref_t      *col_num_pref;
2724
2725     /* See if the column data has changed from the default */
2726     col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
2727     if (col_num_pref && *col_num_pref->varp.uint != col_num_pref->default_val.uint) {
2728         is_default = FALSE;
2729     } else {
2730         while (pref_col && def_col) {
2731             cfmt = (fmt_data *) pref_col->data;
2732             def_cfmt = (fmt_data *) def_col->data;
2733             if ((g_strcmp0(cfmt->title, def_cfmt->title) != 0) ||
2734                     (cfmt->fmt != def_cfmt->fmt) ||
2735                     (((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) &&
2736                      ((g_strcmp0(cfmt->custom_fields, def_cfmt->custom_fields) != 0) ||
2737                       (cfmt->resolved != def_cfmt->resolved)))) {
2738                 is_default = FALSE;
2739                 break;
2740             }
2741
2742             pref_col = pref_col->next;
2743             def_col = def_col->next;
2744         }
2745     }
2746
2747     return is_default;
2748 }
2749
2750 static char *
2751 column_format_to_str_cb(pref_t* pref, gboolean default_val)
2752 {
2753     GList       *pref_l = default_val ? pref->default_val.list : *pref->varp.list;
2754     GList       *clp = g_list_first(pref_l);
2755     GList       *col_l;
2756     fmt_data    *cfmt;
2757     gchar       *prefs_fmt;
2758     char        *column_format_str;
2759
2760     col_l = NULL;
2761     while (clp) {
2762         cfmt = (fmt_data *) clp->data;
2763         col_l = g_list_append(col_l, g_strdup(cfmt->title));
2764         if ((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_fields)) {
2765             prefs_fmt = g_strdup_printf("%s:%s:%d:%c",
2766                     col_format_to_string(cfmt->fmt),
2767                     cfmt->custom_fields,
2768                     cfmt->custom_occurrence,
2769                     cfmt->resolved ? 'R' : 'U');
2770         } else {
2771             prefs_fmt = g_strdup(col_format_to_string(cfmt->fmt));
2772         }
2773         col_l = g_list_append(col_l, prefs_fmt);
2774         clp = clp->next;
2775     }
2776
2777     column_format_str = join_string_list(col_l);
2778     prefs_clear_string_list(col_l);
2779     return column_format_str;
2780 }
2781
2782
2783 /******  Capture column custom preference functions  ******/
2784
2785 /* This routine is only called when Wireshark is started, NOT when another profile is selected.
2786    Copy the pref->capture_columns list (just loaded with the capture_cols[] struct values)
2787    to prefs->default_val.list.
2788 */
2789 static void
2790 capture_column_init_cb(pref_t* pref, GList** capture_cols_values)
2791 {
2792     GList   *ccv_list = *capture_cols_values,
2793             *dlist = NULL;
2794
2795     /*  */
2796     while (ccv_list) {
2797         dlist = g_list_append(dlist, g_strdup((gchar *)ccv_list->data));
2798         ccv_list = ccv_list->next;
2799     }
2800
2801     pref->default_val.list = dlist;
2802     pref->varp.list = &prefs.capture_columns;
2803     pref->stashed_val.boolval = FALSE;
2804 }
2805
2806 /* Free the prefs->capture_columns list strings and remove the list entries.
2807    Note that since pref->varp.list points to &prefs.capture_columns, it is
2808    also freed.
2809 */
2810 static void
2811 capture_column_free_cb(pref_t* pref)
2812 {
2813     prefs_clear_string_list(prefs.capture_columns);
2814     prefs.capture_columns = NULL;
2815
2816     if (pref->stashed_val.boolval == TRUE) {
2817       prefs_clear_string_list(pref->default_val.list);
2818       pref->default_val.list = NULL;
2819     }
2820 }
2821
2822 /* Copy pref->default_val.list to *pref->varp.list.
2823 */
2824 static void
2825 capture_column_reset_cb(pref_t* pref)
2826 {
2827     GList *vlist = NULL, *dlist;
2828
2829     /* Free the column name strings and remove the links from *pref->varp.list */
2830     prefs_clear_string_list(*pref->varp.list);
2831
2832     for (dlist = pref->default_val.list; dlist != NULL; dlist = g_list_next(dlist)) {
2833       vlist = g_list_append(vlist, g_strdup((gchar *)dlist->data));
2834     }
2835     *pref->varp.list = vlist;
2836 }
2837
2838 static prefs_set_pref_e
2839 capture_column_set_cb(pref_t* pref, const gchar* value, unsigned int* changed_flags _U_)
2840 {
2841     GList *col_l  = prefs_get_string_list(value);
2842     GList *col_l_elt;
2843     gchar *col_name;
2844     int i;
2845
2846     if (col_l == NULL)
2847       return PREFS_SET_SYNTAX_ERR;
2848
2849     capture_column_free_cb(pref);
2850
2851     /* If value (the list of capture.columns read from preferences) is empty, set capture.columns
2852        to the full list of valid capture column names. */
2853     col_l_elt = g_list_first(col_l);
2854     if (!(*(gchar *)col_l_elt->data)) {
2855         for (i = 0; i < num_capture_cols; i++) {
2856           col_name = g_strdup(capture_cols[i]);
2857           prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
2858         }
2859     }
2860
2861     /* Verify that all the column names are valid. If not, use the entire list of valid columns.
2862      */
2863     while (col_l_elt) {
2864       gboolean found_match = FALSE;
2865       col_name = (gchar *)col_l_elt->data;
2866
2867       for (i = 0; i < num_capture_cols; i++) {
2868         if (strcmp(col_name, capture_cols[i])==0) {
2869           found_match = TRUE;
2870           break;
2871         }
2872       }
2873       if (!found_match) {
2874         /* One or more cols are invalid so use the entire list of valid cols. */
2875         for (i = 0; i < num_capture_cols; i++) {
2876           col_name = g_strdup(capture_cols[i]);
2877           prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
2878         }
2879         pref->varp.list = &prefs.capture_columns;
2880         prefs_clear_string_list(col_l);
2881         return PREFS_SET_SYNTAX_ERR;
2882       }
2883       col_l_elt = col_l_elt->next;
2884     }
2885
2886     col_l_elt = g_list_first(col_l);
2887     while (col_l_elt) {
2888       col_name = (gchar *)col_l_elt->data;
2889       prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
2890       col_l_elt = col_l_elt->next;
2891     }
2892     pref->varp.list = &prefs.capture_columns;
2893     g_list_free(col_l);
2894     return PREFS_SET_OK;
2895 }
2896
2897
2898 static const char *
2899 capture_column_type_name_cb(void)
2900 {
2901     return "Column list";
2902 }
2903
2904 static char *
2905 capture_column_type_description_cb(void)
2906 {
2907     return g_strdup(
2908         "List of columns to be displayed in the capture options dialog.\n"
2909         CAPTURE_COL_TYPE_DESCRIPTION);
2910 }
2911
2912 static gboolean
2913 capture_column_is_default_cb(pref_t* pref)
2914 {
2915     GList   *pref_col = g_list_first(prefs.capture_columns),
2916             *def_col = g_list_first(pref->default_val.list);
2917     gboolean is_default = TRUE;
2918
2919     /* See if the column data has changed from the default */
2920     while (pref_col && def_col) {
2921         if (strcmp((gchar *)pref_col->data, (gchar *)def_col->data) != 0) {
2922             is_default = FALSE;
2923             break;
2924         }
2925         pref_col = pref_col->next;
2926         def_col = def_col->next;
2927     }
2928
2929     /* Ensure the same column count */
2930     if (((pref_col == NULL) && (def_col != NULL)) ||
2931         ((pref_col != NULL) && (def_col == NULL)))
2932         is_default = FALSE;
2933
2934     return is_default;
2935 }
2936
2937 static char *
2938 capture_column_to_str_cb(pref_t* pref, gboolean default_val)
2939 {
2940
2941     GList       *pref_l = default_val ? pref->default_val.list : prefs.capture_columns;
2942     GList       *clp = g_list_first(pref_l);
2943     GList       *col_l = NULL;
2944     gchar       *col;
2945     char        *capture_column_str;
2946
2947     while (clp) {
2948         col = (gchar *) clp->data;
2949         col_l = g_list_append(col_l, g_strdup(col));
2950         clp = clp->next;
2951     }
2952
2953     capture_column_str = join_string_list(col_l);
2954     prefs_clear_string_list(col_l);
2955     return capture_column_str;
2956 }
2957
2958 static prefs_set_pref_e
2959 colorized_frame_set_cb(pref_t* pref, const gchar* value, unsigned int* changed_flags)
2960 {
2961     (*changed_flags) |= prefs_set_string_value(pref, value, pref_current);
2962     return PREFS_SET_OK;
2963 }
2964
2965 static const char *
2966 colorized_frame_type_name_cb(void)
2967 {
2968    /* Don't write the colors of the 10 easy-access-colorfilters to the preferences
2969     * file until the colors can be changed in the GUI. Currently this is not really
2970     * possible since the STOCK-icons for these colors are hardcoded.
2971     *
2972     * XXX Find a way to change the colors of the STOCK-icons on the fly and then
2973     *     add these 10 colors to the list of colors that can be changed through
2974     *     the preferences.
2975     *
2976     */
2977     return NULL;
2978 }
2979
2980 static char *
2981 colorized_frame_type_description_cb(void)
2982 {
2983     return g_strdup("");
2984 }
2985
2986 static gboolean
2987 colorized_frame_is_default_cb(pref_t* pref _U_)
2988 {
2989     return TRUE;
2990 }
2991
2992 static char *
2993 colorized_frame_to_str_cb(pref_t* pref _U_, gboolean default_val _U_)
2994 {
2995     return g_strdup("");
2996 }
2997
2998 /*
2999  * Register all non-dissector modules' preferences.
3000  */
3001 static module_t *gui_module = NULL;
3002 static module_t *gui_color_module = NULL;
3003 static module_t *nameres_module = NULL;
3004
3005 static void
3006 prefs_register_modules(void)
3007 {
3008     module_t *printing, *capture_module, *console_module,
3009         *gui_layout_module, *gui_font_module;
3010     module_t *extcap_module;
3011     unsigned int layout_gui_flags;
3012     struct pref_custom_cbs custom_cbs;
3013
3014     if (protocols_module != NULL) {
3015         /* Already setup preferences */
3016         return;
3017     }
3018
3019     /* GUI
3020      * These are "simple" GUI preferences that can be read/written using the
3021      * preference module API.  These preferences still use their own
3022      * configuration screens for access, but this cuts down on the
3023      * preference "string compare list" in set_pref()
3024      */
3025     extcap_module = prefs_register_module(NULL, "extcap", "Extcap Utilities",
3026         "Extcap Utilities", NULL, FALSE);
3027
3028     /* Setting default value to true */
3029     prefs.extcap_save_on_start = TRUE;
3030     prefs_register_bool_preference(extcap_module, "gui_save_on_start",
3031                                    "Save arguments on start of capture",
3032                                    "Save arguments on start of capture",
3033                                    &prefs.extcap_save_on_start);
3034
3035     /* GUI
3036      * These are "simple" GUI preferences that can be read/written using the
3037      * preference module API.  These preferences still use their own
3038      * configuration screens for access, but this cuts down on the
3039      * preference "string compare list" in set_pref()
3040      */
3041     gui_module = prefs_register_module(NULL, "gui", "User Interface",
3042         "User Interface", &gui_callback, FALSE);
3043
3044     /* gui.console_open is placed first in the list so that any problems encountered
3045      *  in the following prefs can be displayed in the console window.
3046      */
3047     prefs_register_enum_preference(gui_module, "console_open",
3048                        "Open a console window",
3049                        "Open a console window (Windows only)",
3050                        (gint*)(void*)(&prefs.gui_console_open), gui_console_open_type, FALSE);
3051
3052     prefs_register_obsolete_preference(gui_module, "scrollbar_on_right");
3053     prefs_register_obsolete_preference(gui_module, "packet_list_sel_browse");
3054     prefs_register_obsolete_preference(gui_module, "protocol_tree_sel_browse");
3055     prefs_register_obsolete_preference(gui_module, "tree_view_altern_colors");
3056     prefs_register_obsolete_preference(gui_module, "expert_composite_eyecandy");
3057     prefs_register_obsolete_preference(gui_module, "filter_toolbar_show_in_statusbar");
3058
3059     prefs_register_bool_preference(gui_module, "restore_filter_after_following_stream",
3060                                    "Restore current display filter after following a stream",
3061                                    "Restore current display filter after following a stream?",
3062                                    &prefs.restore_filter_after_following_stream);
3063
3064     prefs_register_obsolete_preference(gui_module, "protocol_tree_line_style");
3065
3066     prefs_register_obsolete_preference(gui_module, "protocol_tree_expander_style");
3067
3068     prefs_register_obsolete_preference(gui_module, "hex_dump_highlight_style");
3069
3070     gui_column_module = prefs_register_subtree(gui_module, "Columns", "Columns", NULL);
3071     /* For reading older preference files with "column." preferences */
3072     prefs_register_module_alias("column", gui_column_module);
3073
3074     custom_cbs.free_cb = free_string_like_preference;
3075     custom_cbs.reset_cb = reset_string_like_preference;
3076     custom_cbs.set_cb = column_hidden_set_cb;
3077     custom_cbs.type_name_cb = column_hidden_type_name_cb;
3078     custom_cbs.type_description_cb = column_hidden_type_description_cb;
3079     custom_cbs.is_default_cb = column_hidden_is_default_cb;
3080     custom_cbs.to_str_cb = column_hidden_to_str_cb;
3081     register_string_like_preference(gui_column_module, PRS_COL_HIDDEN, "Packet list hidden columns",
3082         "List all columns to hide in the packet list",
3083         &cols_hidden_list, PREF_CUSTOM, &custom_cbs, FALSE);
3084
3085     custom_cbs.free_cb = column_format_free_cb;
3086     custom_cbs.reset_cb = column_format_reset_cb;
3087     custom_cbs.set_cb = column_format_set_cb;
3088     custom_cbs.type_name_cb = column_format_type_name_cb;
3089     custom_cbs.type_description_cb = column_format_type_description_cb;
3090     custom_cbs.is_default_cb = column_format_is_default_cb;
3091     custom_cbs.to_str_cb = column_format_to_str_cb;
3092
3093     prefs_register_list_custom_preference(gui_column_module, PRS_COL_FMT, "Packet list column format",
3094         "Each pair of strings consists of a column title and its format", &custom_cbs,
3095         column_format_init_cb, &prefs.col_list);
3096
3097     /* Number of columns.  This is only used internally and is not written to the
3098      * preference file
3099      */
3100     custom_cbs.free_cb = custom_pref_no_cb;
3101     custom_cbs.reset_cb = column_num_reset_cb;
3102     custom_cbs.set_cb = column_num_set_cb;
3103     custom_cbs.type_name_cb = column_num_type_name_cb;
3104     custom_cbs.type_description_cb = column_num_type_description_cb;
3105     custom_cbs.is_default_cb = column_num_is_default_cb;
3106     custom_cbs.to_str_cb = column_num_to_str_cb;
3107     prefs_register_uint_custom_preference(gui_column_module, PRS_COL_NUM, "Number of columns",
3108         "Number of columns in col_list", &custom_cbs, &prefs.num_cols);
3109
3110     /* User Interface : Font */
3111     gui_font_module = prefs_register_subtree(gui_module, "Font", "Font", NULL);
3112
3113     prefs_register_obsolete_preference(gui_font_module, "font_name");
3114
3115     prefs_register_obsolete_preference(gui_font_module, "gtk2.font_name");
3116
3117     register_string_like_preference(gui_font_module, "qt.font_name", "Font name",
3118         "Font name for packet list, protocol tree, and hex dump panes. (Qt)",
3119         &prefs.gui_qt_font_name, PREF_STRING, NULL, TRUE);
3120
3121     /* User Interface : Colors */
3122     gui_color_module = prefs_register_subtree(gui_module, "Colors", "Colors", NULL);
3123
3124     prefs_register_color_preference(gui_color_module, "active_frame.fg", "Foregound color for an active selected item",
3125         "Foregound color for an active selected item", &prefs.gui_active_fg);
3126
3127     prefs_register_color_preference(gui_color_module, "active_frame.bg", "Backgound color for an active selected item",
3128         "Backgound color for an active selected item", &prefs.gui_active_bg);
3129
3130     prefs_register_enum_preference(gui_color_module, "active_frame.style", "Color style for an active selected item",
3131         "Color style for an active selected item", &prefs.gui_active_style, gui_selection_style, FALSE);
3132
3133     prefs_register_color_preference(gui_color_module, "inactive_frame.fg", "Foregound color for an inactive selected item",
3134         "Foregound color for an inactive selected item", &prefs.gui_inactive_fg);
3135
3136     prefs_register_color_preference(gui_color_module, "inactive_frame.bg", "Backgound color for an inactive selected item",
3137         "Backgound color for an inactive selected item", &prefs.gui_inactive_bg);
3138
3139     prefs_register_enum_preference(gui_color_module, "inactive_frame.style", "Color style for an inactive selected item",
3140         "Color style for an inactive selected item", &prefs.gui_inactive_style, gui_selection_style, FALSE);
3141
3142     prefs_register_color_preference(gui_color_module, "marked_frame.fg", "Color preferences for a marked frame",
3143         "Color preferences for a marked frame", &prefs.gui_marked_fg);
3144
3145     prefs_register_color_preference(gui_color_module, "marked_frame.bg", "Color preferences for a marked frame",
3146         "Color preferences for a marked frame", &prefs.gui_marked_bg);
3147
3148     prefs_register_color_preference(gui_color_module, "ignored_frame.fg", "Color preferences for a ignored frame",
3149         "Color preferences for a ignored frame", &prefs.gui_ignored_fg);
3150
3151     prefs_register_color_preference(gui_color_module, "ignored_frame.bg", "Color preferences for a ignored frame",
3152         "Color preferences for a ignored frame", &prefs.gui_ignored_bg);
3153
3154     prefs_register_color_preference(gui_color_module, "stream.client.fg", "TCP stream window color preference",
3155         "TCP stream window color preference", &prefs.st_client_fg);
3156
3157     prefs_register_color_preference(gui_color_module, "stream.client.bg", "TCP stream window color preference",
3158         "TCP stream window color preference", &prefs.st_client_bg);
3159
3160     prefs_register_color_preference(gui_color_module, "stream.server.fg", "TCP stream window color preference",
3161         "TCP stream window color preference", &prefs.st_server_fg);
3162
3163     prefs_register_color_preference(gui_color_module, "stream.server.bg", "TCP stream window color preference",
3164         "TCP stream window color preference", &prefs.st_server_bg);
3165
3166     custom_cbs.free_cb = free_string_like_preference;
3167     custom_cbs.reset_cb = reset_string_like_preference;
3168     custom_cbs.set_cb = colorized_frame_set_cb;
3169     custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3170     custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3171     custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3172     custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3173     register_string_like_preference(gui_column_module, "colorized_frame.fg", "Colorized Foreground",
3174         "Filter Colorized Foreground",
3175         &prefs.gui_colorized_fg, PREF_CUSTOM, &custom_cbs, TRUE);
3176
3177     custom_cbs.free_cb = free_string_like_preference;
3178     custom_cbs.reset_cb = reset_string_like_preference;
3179     custom_cbs.set_cb = colorized_frame_set_cb;
3180     custom_cbs.type_name_cb = colorized_frame_type_name_cb;
3181     custom_cbs.type_description_cb = colorized_frame_type_description_cb;
3182     custom_cbs.is_default_cb = colorized_frame_is_default_cb;
3183     custom_cbs.to_str_cb = colorized_frame_to_str_cb;
3184     register_string_like_preference(gui_column_module, "colorized_frame.bg", "Colorized Background",
3185         "Filter Colorized Background",
3186         &prefs.gui_colorized_bg, PREF_CUSTOM, &custom_cbs, TRUE);
3187
3188     prefs_register_color_preference(gui_color_module, "color_filter_bg.valid", "Valid color filter background",
3189         "Valid color filter background", &prefs.gui_text_valid);
3190
3191     prefs_register_color_preference(gui_color_module, "color_filter_bg.invalid", "Invalid color filter background",
3192         "Invalid color filter background", &prefs.gui_text_invalid);
3193
3194     prefs_register_color_preference(gui_color_module, "color_filter_bg.deprecated", "Deprecated color filter background",
3195         "Deprecated color filter background", &prefs.gui_text_deprecated);
3196
3197     prefs_register_enum_preference(gui_module, "fileopen.style",
3198                        "Where to start the File Open dialog box",
3199                        "Where to start the File Open dialog box",
3200                        &prefs.gui_fileopen_style, gui_fileopen_style, FALSE);
3201
3202     prefs_register_uint_preference(gui_module, "recent_files_count.max",
3203                                    "The max. number of items in the open recent files list",
3204                                    "The max. number of items in the open recent files list",
3205                                    10,
3206                                    &prefs.gui_recent_files_count_max);
3207
3208     prefs_register_uint_preference(gui_module, "recent_display_filter_entries.max",
3209                                    "The max. number of entries in the display filter list",
3210                                    "The max. number of entries in the display filter list",
3211                                    10,
3212                                    &prefs.gui_recent_df_entries_max);
3213
3214     register_string_like_preference(gui_module, "fileopen.dir", "Start Directory",
3215         "Directory to start in when opening File Open dialog.",
3216         &prefs.gui_fileopen_dir, PREF_DIRNAME, NULL, TRUE);
3217
3218     prefs_register_obsolete_preference(gui_module, "fileopen.remembered_dir");
3219
3220     prefs_register_uint_preference(gui_module, "fileopen.preview",
3221                                    "The preview timeout in the File Open dialog",
3222                                    "The preview timeout in the File Open dialog",
3223                                    10,
3224                                    &prefs.gui_fileopen_preview);
3225
3226     prefs_register_bool_preference(gui_module, "ask_unsaved",
3227                                    "Ask to save unsaved capture files",
3228                                    "Ask to save unsaved capture files?",
3229                                    &prefs.gui_ask_unsaved);
3230
3231     prefs_register_bool_preference(gui_module, "autocomplete_filter",
3232                                    "Display autocompletion for filter text",
3233                                    "Display an autocomplete suggestion for display and capture filter controls",
3234                                    &prefs.gui_autocomplete_filter);
3235
3236     prefs_register_bool_preference(gui_module, "find_wrap",
3237                                    "Wrap to beginning/end of file during search",
3238                                    "Wrap to beginning/end of file during search?",
3239                                    &prefs.gui_find_wrap);
3240
3241     prefs_register_obsolete_preference(gui_module, "use_pref_save");
3242
3243     prefs_register_bool_preference(gui_module, "geometry.save.position",
3244                                    "Save window position at exit",
3245                                    "Save window position at exit?",
3246                                    &prefs.gui_geometry_save_position);
3247
3248     prefs_register_bool_preference(gui_module, "geometry.save.size",
3249                                    "Save window size at exit",
3250                                    "Save window size at exit?",
3251                                    &prefs.gui_geometry_save_size);
3252
3253     prefs_register_bool_preference(gui_module, "geometry.save.maximized",
3254                                    "Save window maximized state at exit",
3255                                    "Save window maximized state at exit?",
3256                                    &prefs.gui_geometry_save_maximized);
3257
3258     prefs_register_obsolete_preference(gui_module, "macosx_style");
3259
3260     prefs_register_obsolete_preference(gui_module, "geometry.main.x");
3261     prefs_register_obsolete_preference(gui_module, "geometry.main.y");
3262     prefs_register_obsolete_preference(gui_module, "geometry.main.width");
3263     prefs_register_obsolete_preference(gui_module, "geometry.main.height");
3264     prefs_register_obsolete_preference(gui_module, "toolbar_main_show");
3265
3266     prefs_register_enum_preference(gui_module, "toolbar_main_style",
3267                        "Main Toolbar style",
3268                        "Main Toolbar style",
3269                        &prefs.gui_toolbar_main_style, gui_toolbar_style, FALSE);
3270
3271     prefs_register_obsolete_preference(gui_module, "toolbar_filter_style");
3272     prefs_register_obsolete_preference(gui_module, "webbrowser");
3273
3274     prefs_register_bool_preference(gui_module, "update.enabled",
3275                                    "Check for updates",
3276                                    "Check for updates (Windows only)",
3277                                    &prefs.gui_update_enabled);
3278
3279     prefs_register_enum_preference(gui_module, "update.channel",
3280                        "Update channel",
3281                        "The type of update to fetch. You should probably leave this set to UPDATE_CHANNEL_STABLE.",
3282                        (gint*)(void*)(&prefs.gui_update_channel), gui_update_channel, FALSE);
3283
3284     prefs_register_uint_preference(gui_module, "update.interval",
3285                                    "How often to check for software updates",
3286                                    "How often to check for software updates in seconds",
3287                                    10,
3288                                    &prefs.gui_update_interval);
3289
3290     register_string_like_preference(gui_module, "window_title", "Custom window title",
3291         "Custom window title to be appended to the existing title\n"
3292         "%F = file path of the capture file\n"
3293         "%P = profile name\n"
3294         "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3295         "%V = version info",
3296         &prefs.gui_window_title, PREF_STRING, NULL, TRUE);
3297
3298     register_string_like_preference(gui_module, "prepend_window_title", "Custom window title prefix",
3299         "Custom window title to be prepended to the existing title\n"
3300         "%F = file path of the capture file\n"
3301         "%P = profile name\n"
3302         "%S = a conditional separator (\" - \") that only shows when surrounded by variables with values or static text\n"
3303         "%V = version info",
3304         &prefs.gui_prepend_window_title, PREF_STRING, NULL, TRUE);
3305
3306     register_string_like_preference(gui_module, "start_title", "Custom start page title",
3307         "Custom start page title",
3308         &prefs.gui_start_title, PREF_STRING, NULL, TRUE);
3309
3310     prefs_register_enum_preference(gui_module, "version_placement",
3311                        "Show version in the start page and/or main screen's title bar",
3312                        "Show version in the start page and/or main screen's title bar",
3313                        (gint*)(void*)(&prefs.gui_version_placement), gui_version_placement_type, FALSE);
3314
3315     prefs_register_obsolete_preference(gui_module, "auto_scroll_on_expand");
3316     prefs_register_obsolete_preference(gui_module, "auto_scroll_percentage");
3317
3318     /* User Interface : Layout */
3319     gui_layout_module = prefs_register_subtree(gui_module, "Layout", "Layout", gui_layout_callback);
3320     /* Adjust the preference effects of layout GUI for better handling of preferences at Wireshark (GUI) level */
3321     layout_gui_flags = prefs_get_module_effect_flags(gui_layout_module);
3322     layout_gui_flags |= PREF_EFFECT_GUI_LAYOUT;
3323     layout_gui_flags &= (~PREF_EFFECT_DISSECTION);
3324
3325     prefs_register_uint_preference(gui_layout_module, "layout_type",
3326                                    "Layout type",
3327                                    "Layout type (1-6)",
3328                                    10,
3329                                    (guint*)(void*)(&prefs.gui_layout_type));
3330     prefs_set_effect_flags_by_name(gui_layout_module, "layout_type", layout_gui_flags);
3331
3332     prefs_register_enum_preference(gui_layout_module, "layout_content_1",
3333                        "Layout content of the pane 1",
3334                        "Layout content of the pane 1",
3335                        (gint*)(void*)(&prefs.gui_layout_content_1), gui_layout_content, FALSE);
3336     prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_1", layout_gui_flags);
3337
3338     prefs_register_enum_preference(gui_layout_module, "layout_content_2",
3339                        "Layout content of the pane 2",
3340                        "Layout content of the pane 2",
3341                        (gint*)(void*)(&prefs.gui_layout_content_2), gui_layout_content, FALSE);
3342     prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_2", layout_gui_flags);
3343
3344     prefs_register_enum_preference(gui_layout_module, "layout_content_3",
3345                        "Layout content of the pane 3",
3346                        "Layout content of the pane 3",
3347                        (gint*)(void*)(&prefs.gui_layout_content_3), gui_layout_content, FALSE);
3348     prefs_set_effect_flags_by_name(gui_layout_module, "layout_content_3", layout_gui_flags);
3349
3350     prefs_register_bool_preference(gui_layout_module, "packet_list_separator.enabled",
3351                                    "Enable Packet List Separator",
3352                                    "Enable Packet List Separator",
3353                                    &prefs.gui_qt_packet_list_separator);
3354
3355     prefs_register_bool_preference(gui_layout_module, "show_selected_packet.enabled",
3356                                    "Show selected packet in the Status Bar",
3357                                    "Show selected packet in the Status Bar",
3358                                    &prefs.gui_qt_show_selected_packet);
3359
3360     prefs_register_bool_preference(gui_layout_module, "show_file_load_time.enabled",
3361                                    "Show file load time in the Status Bar",
3362                                    "Show file load time in the Status Bar",
3363                                    &prefs.gui_qt_show_file_load_time);
3364
3365     prefs_register_bool_preference(gui_module, "packet_editor.enabled",
3366                                    "Enable Packet Editor",
3367                                    "Enable Packet Editor (Experimental)",
3368                                    &prefs.gui_packet_editor);
3369
3370     prefs_register_enum_preference(gui_module, "packet_list_elide_mode",
3371                        "Elide mode",
3372                        "The position of \"...\" in packet list text.",
3373                        (gint*)(void*)(&prefs.gui_packet_list_elide_mode), gui_packet_list_elide_mode, FALSE);
3374
3375     prefs_register_bool_preference(gui_layout_module, "packet_list_show_related",
3376                                    "Show Related Packets",
3377                                    "Show related packet indicators in the first column",
3378                                    &prefs.gui_packet_list_show_related);
3379
3380     prefs_register_bool_preference(gui_layout_module, "packet_list_show_minimap",
3381                                    "Enable Intelligent Scroll Bar",
3382                                    "Show the intelligent scroll bar (a minimap of packet list colors in the scrollbar)",
3383                                    &prefs.gui_packet_list_show_minimap);
3384
3385
3386     prefs_register_bool_preference(gui_module, "interfaces_show_hidden",
3387                                    "Show hidden interfaces",
3388                                    "Show all interfaces, including interfaces marked as hidden",
3389                                    &prefs.gui_interfaces_show_hidden);
3390
3391     prefs_register_bool_preference(gui_module, "interfaces_remote_display",
3392                                    "Show Remote interfaces",
3393                                    "Show remote interfaces in the interface selection",
3394                                    &prefs.gui_interfaces_remote_display);
3395
3396     register_string_like_preference(gui_module, "interfaces_hidden_types", "Hide interface types in list",
3397         "Hide the given interface types in the startup list.\n"
3398         "A commma-separated string of interface type values (e.g. 5,9).\n"
3399          "0 = Wired,\n"
3400          "1 = AirPCAP,\n"
3401          "2 = Pipe,\n"
3402          "3 = STDIN,\n"
3403          "4 = Bluetooth,\n"
3404          "5 = Wireless,\n"
3405          "6 = Dial-Up,\n"
3406          "7 = USB,\n"
3407          "8 = External Capture,\n"
3408          "9 = Virtual",
3409         &prefs.gui_interfaces_hide_types, PREF_STRING, NULL, TRUE);
3410
3411     /* Console
3412      * These are preferences that can be read/written using the
3413      * preference module API.  These preferences still use their own
3414      * configuration screens for access, but this cuts down on the
3415      * preference "string compare list" in set_pref()
3416      */
3417     console_module = prefs_register_module(NULL, "console", "Console",
3418         "Console logging and debugging output", NULL, FALSE);
3419
3420     custom_cbs.free_cb = custom_pref_no_cb;
3421     custom_cbs.reset_cb = console_log_level_reset_cb;
3422     custom_cbs.set_cb = console_log_level_set_cb;
3423     custom_cbs.type_name_cb = console_log_level_type_name_cb;
3424     custom_cbs.type_description_cb = console_log_level_type_description_cb;
3425     custom_cbs.is_default_cb = console_log_level_is_default_cb;
3426     custom_cbs.to_str_cb = console_log_level_to_str_cb;
3427     prefs_register_uint_custom_preference(console_module, "log.level", "logging level",
3428         "A bitmask of GLib log levels", &custom_cbs, &prefs.console_log_level);
3429
3430     prefs_register_bool_preference(console_module, "incomplete_dissectors_check_debug",
3431                                    "Print debug line for incomplete dissectors",
3432                                    "Look for dissectors that left some bytes undecoded (debug)",
3433                                    &prefs.incomplete_dissectors_check_debug);
3434
3435     /* Display filter Expressions
3436      * This used to be an array of individual fields that has now been
3437      * converted to a UAT.  Just make it part of the GUI category even
3438      * though the name of the preference will never be seen in preference
3439      * file
3440      */
3441     filter_expression_register_uat(gui_module);
3442
3443     /* Capture
3444      * These are preferences that can be read/written using the
3445      * preference module API.  These preferences still use their own
3446      * configuration screens for access, but this cuts down on the
3447      * preference "string compare list" in set_pref()
3448      */
3449     capture_module = prefs_register_module(NULL, "capture", "Capture",
3450         "Capture preferences", NULL, FALSE);
3451     /* Capture preferences don't affect dissection */
3452     prefs_set_module_effect_flags(capture_module, PREF_EFFECT_CAPTURE);
3453
3454     register_string_like_preference(capture_module, "device", "Default capture device",
3455         "Default capture device",
3456         &prefs.capture_device, PREF_STRING, NULL, FALSE);
3457
3458     register_string_like_preference(capture_module, "devices_linktypes", "Interface link-layer header type",
3459         "Interface link-layer header types (Ex: en0(1),en1(143),...)",
3460         &prefs.capture_devices_linktypes, PREF_STRING, NULL, FALSE);
3461
3462     register_string_like_preference(capture_module, "devices_descr", "Interface descriptions",
3463         "Interface descriptions (Ex: eth0(eth0 descr),eth1(eth1 descr),...)",
3464         &prefs.capture_devices_descr, PREF_STRING, NULL, FALSE);
3465
3466     register_string_like_preference(capture_module, "devices_hide", "Hide interface",
3467         "Hide interface? (Ex: eth0,eth3,...)",
3468         &prefs.capture_devices_hide, PREF_STRING, NULL, FALSE);
3469
3470     register_string_like_preference(capture_module, "devices_monitor_mode", "Capture in monitor mode",
3471         "By default, capture in monitor mode on interface? (Ex: eth0,eth3,...)",
3472         &prefs.capture_devices_monitor_mode, PREF_STRING, NULL, FALSE);
3473
3474     register_string_like_preference(capture_module, "devices_buffersize", "Interface buffer size",
3475         "Interface buffer size (Ex: en0(1),en1(143),...)",
3476         &prefs.capture_devices_buffersize, PREF_STRING, NULL, FALSE);
3477
3478     register_string_like_preference(capture_module, "devices_snaplen", "Interface snap length",
3479         "Interface snap length (Ex: en0(65535),en1(1430),...)",
3480         &prefs.capture_devices_snaplen, PREF_STRING, NULL, FALSE);
3481
3482     register_string_like_preference(capture_module, "devices_pmode", "Interface promiscuous mode",
3483         "Interface promiscuous mode (Ex: en0(0),en1(1),...)",
3484         &prefs.capture_devices_pmode, PREF_STRING, NULL, FALSE);
3485
3486     prefs_register_bool_preference(capture_module, "prom_mode", "Capture in promiscuous mode",
3487         "Capture in promiscuous mode?", &prefs.capture_prom_mode);
3488
3489     register_string_like_preference(capture_module, "devices_filter", "Interface capture filter",
3490         "Interface capture filter (Ex: en0(tcp),en1(udp),...)",
3491         &prefs.capture_devices_filter, PREF_STRING, NULL, FALSE);
3492
3493     prefs_register_bool_preference(capture_module, "pcap_ng", "Capture in pcapng format",
3494         "Capture in pcapng format?", &prefs.capture_pcap_ng);
3495
3496     prefs_register_bool_preference(capture_module, "real_time_update", "Update packet list in real time during capture",
3497         "Update packet list in real time during capture?", &prefs.capture_real_time);
3498
3499     prefs_register_bool_preference(capture_module, "no_interface_load", "Don't load interfaces on startup",
3500         "Don't automatically load capture interfaces on startup", &prefs.capture_no_interface_load);
3501
3502     prefs_register_bool_preference(capture_module, "no_extcap", "Disable external capture interfaces",
3503         "Disable external capture modules (extcap)", &prefs.capture_no_extcap);
3504
3505     /* We might want to make this a "recent" setting. */
3506     prefs_register_bool_preference(capture_module, "auto_scroll", "Scroll packet list during capture",
3507         "Scroll packet list during capture?", &prefs.capture_auto_scroll);
3508
3509     prefs_register_bool_preference(capture_module, "show_info", "Show capture information dialog while capturing",
3510         "Show capture information dialog while capturing?", &prefs.capture_show_info);
3511
3512     prefs_register_obsolete_preference(capture_module, "syntax_check_filter");
3513
3514     custom_cbs.free_cb = capture_column_free_cb;
3515     custom_cbs.reset_cb = capture_column_reset_cb;
3516     custom_cbs.set_cb = capture_column_set_cb;
3517     custom_cbs.type_name_cb = capture_column_type_name_cb;
3518     custom_cbs.type_description_cb = capture_column_type_description_cb;
3519     custom_cbs.is_default_cb = capture_column_is_default_cb;
3520     custom_cbs.to_str_cb = capture_column_to_str_cb;
3521     prefs_register_list_custom_preference(capture_module, "columns", "Capture options dialog column list",
3522         "List of columns to be displayed", &custom_cbs, capture_column_init_cb, &prefs.capture_columns);
3523
3524     /* Name Resolution */
3525     nameres_module = prefs_register_module(NULL, "nameres", "Name Resolution",
3526         "Name Resolution", NULL, TRUE);
3527     addr_resolve_pref_init(nameres_module);
3528     oid_pref_init(nameres_module);
3529     maxmind_db_pref_init(nameres_module);
3530
3531     /* Printing
3532      * None of these have any effect; we keep them as obsolete preferences
3533      * in order to avoid errors when reading older preference files.
3534      */
3535     printing = prefs_register_module(NULL, "print", "Printing",
3536         "Printing", NULL, FALSE);
3537     prefs_register_obsolete_preference(printing, "format");
3538     prefs_register_obsolete_preference(printing, "command");
3539     prefs_register_obsolete_preference(printing, "file");
3540
3541     /* Codecs */
3542     codecs_module = prefs_register_module(NULL, "codecs", "Codecs",
3543         "Codecs", NULL, TRUE);
3544
3545     /* Statistics */
3546     stats_module = prefs_register_module(NULL, "statistics", "Statistics",
3547         "Statistics", &stats_callback, TRUE);
3548
3549     prefs_register_uint_preference(stats_module, "update_interval",
3550                                    "Tap update interval in ms",
3551                                    "Determines time between tap updates",
3552                                    10,
3553                                    &prefs.tap_update_interval);
3554
3555     prefs_register_obsolete_preference(stats_module, "rtp_player_max_visible");
3556
3557     prefs_register_bool_preference(stats_module, "st_enable_burstinfo",
3558             "Enable the calculation of burst information",
3559             "If enabled burst rates will be calcuted for statistics that use the stats_tree system. "
3560             "Burst rates are calculated over a much shorter time interval than the rate column.",
3561             &prefs.st_enable_burstinfo);
3562
3563     prefs_register_bool_preference(stats_module, "st_burst_showcount",
3564             "Show burst count for item rather than rate",
3565             "If selected the stats_tree statistics nodes will show the count of events "
3566             "within the burst window instead of a burst rate. Burst rate is calculated "
3567             "as number of events within burst window divided by the burst windown length.",
3568             &prefs.st_burst_showcount);
3569
3570     prefs_register_uint_preference(stats_module, "st_burst_resolution",
3571             "Burst rate resolution (ms)",
3572             "Sets the duration of the time interval into which events are grouped when calculating "
3573             "the burst rate. Higher resolution (smaller number) increases processing overhead.",
3574             10,&prefs.st_burst_resolution);
3575
3576     prefs_register_uint_preference(stats_module, "st_burst_windowlen",
3577             "Burst rate window size (ms)",
3578             "Sets the duration of the sliding window during which the burst rate is "
3579             "measured. Longer window relative to burst rate resolution increases "
3580             "processing overhead. Will be truncated to a multiple of burst resolution.",
3581             10,&prefs.st_burst_windowlen);
3582
3583     prefs_register_enum_preference(stats_module, "st_sort_defcolflag",
3584             "Default sort column for stats_tree stats",
3585             "Sets the default column by which stats based on the stats_tree "
3586             "system is sorted.",
3587             &prefs.st_sort_defcolflag, st_sort_col_vals, FALSE);
3588
3589      prefs_register_bool_preference(stats_module, "st_sort_defdescending",
3590             "Default stats_tree sort order is descending",
3591             "When selected, statistics based on the stats_tree system will by default "
3592             "be sorted in descending order.",
3593             &prefs.st_sort_defdescending);
3594
3595      prefs_register_bool_preference(stats_module, "st_sort_casesensitve",
3596             "Case sensitive sort of stats_tree item names",
3597             "When selected, the item/node names of statistics based on the stats_tree "
3598             "system will be sorted taking case into account. Else the case of the name "
3599             "will be ignored.",
3600             &prefs.st_sort_casesensitve);
3601
3602      prefs_register_bool_preference(stats_module, "st_sort_rng_nameonly",
3603             "Always sort 'range' nodes by name",
3604             "When selected, the stats_tree nodes representing a range of values "
3605             "(0-49, 50-100, etc.) will always be sorted by name (the range of the "
3606             "node). Else range nodes are sorted by the same column as the rest of "
3607             " the tree.",
3608             &prefs.st_sort_rng_nameonly);
3609
3610      prefs_register_bool_preference(stats_module, "st_sort_rng_fixorder",
3611             "Always sort 'range' nodes in ascending order",
3612             "When selected, the stats_tree nodes representing a range of values "
3613             "(0-49, 50-100, etc.) will always be sorted ascending; else it follows "
3614             "the sort direction of the tree. Only effective if \"Always sort "
3615             "'range' nodes by name\" is also selected.",
3616             &prefs.st_sort_rng_fixorder);
3617
3618      prefs_register_bool_preference(stats_module, "st_sort_showfullname",
3619             "Display the full stats_tree plug-in name",
3620             "When selected, the full name (including menu path) of the stats_tree "
3621             "plug-in is show in windows. If cleared the plug-in name is shown "
3622             "without menu path (only the part of the name after last '/' character.)",
3623             &prefs.st_sort_showfullname);
3624
3625     /* Protocols */
3626     protocols_module = prefs_register_module(NULL, "protocols", "Protocols",
3627                                              "Protocols", NULL, TRUE);
3628
3629     prefs_register_bool_preference(protocols_module, "display_hidden_proto_items",
3630                                    "Display hidden protocol items",
3631                                    "Display all hidden protocol items in the packet list.",
3632                                    &prefs.display_hidden_proto_items);
3633
3634     prefs_register_bool_preference(protocols_module, "display_byte_fields_with_spaces",
3635                                    "Display byte fields with a space character between bytes",
3636                                    "Display all byte fields with a space character between each byte in the packet list.",
3637                                    &prefs.display_byte_fields_with_spaces);
3638
3639     prefs_register_bool_preference(protocols_module, "enable_incomplete_dissectors_check",
3640                                    "Look for incomplete dissectors",
3641                                    "Look for dissectors that left some bytes undecoded.",
3642                                    &prefs.enable_incomplete_dissectors_check);
3643
3644     prefs_register_bool_preference(protocols_module, "strict_conversation_tracking_heuristics",
3645                                    "Enable stricter conversation tracking heuristics",
3646                                    "Protocols may use things like VLAN ID or interface ID to narrow the potential for duplicate conversations."
3647                                    "Currently only ICMP and ICMPv6 use this preference to add VLAN ID to conversation tracking",
3648                                    &prefs.strict_conversation_tracking_heuristics);
3649
3650     /* Obsolete preferences
3651      * These "modules" were reorganized/renamed to correspond to their GUI
3652      * configuration screen within the preferences dialog
3653      */
3654
3655     /* taps is now part of the stats module */
3656     prefs_register_module(NULL, "taps", "TAPS", "TAPS", NULL, FALSE);
3657     /* packet_list is now part of the protocol (parent) module */
3658     prefs_register_module(NULL, "packet_list", "PACKET_LIST", "PACKET_LIST", NULL, FALSE);
3659     /* stream is now part of the gui module */
3660     prefs_register_module(NULL, "stream", "STREAM", "STREAM", NULL, FALSE);
3661
3662 }
3663
3664 /* Parse through a list of comma-separated, possibly quoted strings.
3665    Return a list of the string data. */
3666 GList *
3667 prefs_get_string_list(const gchar *str)
3668 {
3669     enum { PRE_STRING, IN_QUOT, NOT_IN_QUOT };
3670
3671     gint      state = PRE_STRING, i = 0, j = 0;
3672     gboolean  backslash = FALSE;
3673     guchar    cur_c;
3674     gchar    *slstr = NULL;
3675     GList    *sl = NULL;
3676
3677     /* Allocate a buffer for the first string.   */
3678     slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
3679     j = 0;
3680
3681     for (;;) {
3682         cur_c = str[i];
3683         if (cur_c == '\0') {
3684             /* It's the end of the input, so it's the end of the string we
3685                were working on, and there's no more input. */
3686             if (state == IN_QUOT || backslash) {
3687                 /* We were in the middle of a quoted string or backslash escape,
3688                    and ran out of characters; that's an error.  */
3689                 g_free(slstr);
3690                 prefs_clear_string_list(sl);
3691                 return NULL;
3692             }
3693             slstr[j] = '\0';
3694             if (j > 0)
3695                 sl = g_list_append(sl, slstr);
3696             else
3697                 g_free(slstr);
3698             break;
3699         }
3700         if (cur_c == '"' && ! backslash) {
3701             switch (state) {
3702             case PRE_STRING:
3703                 /* We hadn't yet started processing a string; this starts the
3704                    string, and we're now quoting.  */
3705                 state = IN_QUOT;
3706                 break;
3707             case IN_QUOT:
3708                 /* We're in the middle of a quoted string, and we saw a quotation
3709                    mark; we're no longer quoting.   */
3710                 state = NOT_IN_QUOT;
3711                 break;
3712             case NOT_IN_QUOT:
3713                 /* We're working on a string, but haven't seen a quote; we're
3714                    now quoting.  */
3715                 state = IN_QUOT;
3716                 break;
3717             default:
3718                 break;
3719             }
3720         } else if (cur_c == '\\' && ! backslash) {
3721             /* We saw a backslash, and the previous character wasn't a
3722                backslash; escape the next character.
3723
3724                This also means we've started a new string. */
3725             backslash = TRUE;
3726             if (state == PRE_STRING)
3727                 state = NOT_IN_QUOT;
3728         } else if (cur_c == ',' && state != IN_QUOT && ! backslash) {
3729             /* We saw a comma, and we're not in the middle of a quoted string
3730                and it wasn't preceded by a backslash; it's the end of
3731                the string we were working on...  */
3732             slstr[j] = '\0';
3733             if (j > 0) {
3734                 sl = g_list_append(sl, slstr);
3735                 slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
3736             }
3737
3738             /* ...and the beginning of a new string.  */
3739             state = PRE_STRING;
3740             j = 0;
3741         } else if (!g_ascii_isspace(cur_c) || state != PRE_STRING) {
3742             /* Either this isn't a white-space character, or we've started a
3743                string (i.e., already seen a non-white-space character for that
3744                string and put it into the string).
3745
3746                The character is to be put into the string; do so if there's
3747                room.  */
3748             if (j < COL_MAX_LEN) {
3749                 slstr[j] = cur_c;
3750                 j++;
3751             }
3752
3753             /* If it was backslash-escaped, we're done with the backslash escape.  */
3754             backslash = FALSE;
3755         }
3756         i++;
3757     }
3758     return(sl);
3759 }
3760
3761 char *join_string_list(GList *sl)
3762 {
3763     GString      *joined_str = g_string_new("");
3764     GList        *cur, *first;
3765     gchar        *str;
3766     guint         item_count = 0;
3767
3768     cur = first = g_list_first(sl);
3769     while (cur) {
3770         item_count++;
3771         str = (gchar *)cur->data;
3772
3773         if (cur != first)
3774             g_string_append_c(joined_str, ',');
3775
3776         if (item_count % 2) {
3777             /* Wrap the line.  */
3778             g_string_append(joined_str, "\n\t");
3779         } else
3780             g_string_append_c(joined_str, ' ');
3781
3782         g_string_append_c(joined_str, '"');
3783         while (*str) {
3784             gunichar uc = g_utf8_get_char (str);
3785
3786             if (uc == '"' || uc == '\\')
3787                 g_string_append_c(joined_str, '\\');
3788
3789             if (g_unichar_isprint(uc))
3790                 g_string_append_unichar (joined_str, uc);
3791
3792             str = g_utf8_next_char (str);
3793         }
3794
3795         g_string_append_c(joined_str, '"');
3796
3797         cur = cur->next;
3798     }
3799     return g_string_free(joined_str, FALSE);
3800 }
3801
3802 void
3803 prefs_clear_string_list(GList *sl)
3804 {
3805     g_list_free_full(sl, g_free);
3806 }
3807
3808 /*
3809  * Takes a string, a pointer to an array of "enum_val_t"s, and a default gint
3810  * value.
3811  * The array must be terminated by an entry with a null "name" string.
3812  *
3813  * If the string matches a "name" string in an entry, the value from that
3814  * entry is returned.
3815  *
3816  * Otherwise, if a string matches a "description" string in an entry, the
3817  * value from that entry is returned; we do that for backwards compatibility,
3818  * as we used to have only a "name" string that was used both for command-line
3819  * and configuration-file values and in the GUI (which meant either that
3820  * the GUI had what might be somewhat cryptic values to select from or that
3821  * the "-o" flag took long strings, often with spaces in them).
3822  *
3823  * Otherwise, the default value that was passed as the third argument is
3824  * returned.
3825  */
3826 static gint
3827 find_val_for_string(const char *needle, const enum_val_t *haystack,
3828                     gint default_value)
3829 {
3830     int i;
3831
3832     for (i = 0; haystack[i].name != NULL; i++) {
3833         if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) {
3834             return haystack[i].value;
3835         }
3836     }
3837     for (i = 0; haystack[i].name != NULL; i++) {
3838         if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) {
3839             return haystack[i].value;
3840         }
3841     }
3842     return default_value;
3843 }
3844
3845
3846 /* Array of columns that have been migrated to custom columns */
3847 struct deprecated_columns {
3848     const gchar *col_fmt;
3849     const gchar *col_expr;
3850 };
3851 static struct deprecated_columns migrated_columns[] = {
3852     { /* COL_COS_VALUE */ "%U", "vlan.priority" },
3853     { /* COL_CIRCUIT_ID */ "%c", "iax2.call" },
3854     { /* COL_BSSGP_TLLI */ "%l", "bssgp.tlli" },
3855     { /* COL_HPUX_SUBSYS */ "%H", "nettl.subsys" },
3856     { /* COL_HPUX_DEVID */ "%P", "nettl.devid" },
3857     { /* COL_FR_DLCI */ "%C", "fr.dlci" },
3858     { /* COL_REL_CONV_TIME */ "%rct", "tcp.time_relative" },
3859     { /* COL_DELTA_CONV_TIME */ "%dct", "tcp.time_delta" },
3860     { /* COL_OXID */ "%XO", "fc.ox_id" },
3861     { /* COL_RXID */ "%XR", "fc.rx_id" },
3862     { /* COL_SRCIDX */ "%Xd", "mdshdr.srcidx" },
3863     { /* COL_DSTIDX */ "%Xs", "mdshdr.dstidx" },
3864     { /* COL_DCE_CTX */ "%z", "dcerpc.cn_ctx_id" }
3865 };
3866
3867 static gboolean
3868 is_deprecated_column_format(const gchar* fmt)
3869 {
3870     guint haystack_idx;
3871
3872     for (haystack_idx = 0;
3873          haystack_idx < G_N_ELEMENTS(migrated_columns);
3874          ++haystack_idx) {
3875
3876         if (strcmp(migrated_columns[haystack_idx].col_fmt, fmt) == 0) {
3877             return TRUE;
3878         }
3879     }
3880
3881     return FALSE;
3882 }
3883
3884 /* Preferences file format:
3885  * - Configuration directives start at the beginning of the line, and
3886  *   are terminated with a colon.
3887  * - Directives can be continued on the next line by preceding them with
3888  *   whitespace.
3889  *
3890  * Example:
3891
3892 # This is a comment line
3893 print.command: lpr
3894 print.file: /a/very/long/path/
3895             to/wireshark-out.ps
3896  *
3897  */
3898
3899 #define DEF_NUM_COLS    7
3900
3901 /*
3902  * Parse a column format, filling in the relevant fields of a fmt_data.
3903  */
3904 static gboolean
3905 parse_column_format(fmt_data *cfmt, const char *fmt)
3906 {
3907     const gchar *cust_format = col_format_to_string(COL_CUSTOM);
3908     size_t cust_format_len = strlen(cust_format);
3909     gchar **cust_format_info;
3910     char *p;
3911     int col_fmt;
3912     gchar *col_custom_fields = NULL;
3913     long col_custom_occurrence = 0;
3914     gboolean col_resolved = TRUE;
3915
3916     /*
3917      * Is this a custom column?
3918      */
3919     if ((strlen(fmt) > cust_format_len) && (fmt[cust_format_len] == ':') &&
3920         strncmp(fmt, cust_format, cust_format_len) == 0) {
3921         /* Yes. */
3922         col_fmt = COL_CUSTOM;
3923         cust_format_info = g_strsplit(&fmt[cust_format_len+1],":",3); /* add 1 for ':' */
3924         col_custom_fields = g_strdup(cust_format_info[0]);
3925         if (col_custom_fields && cust_format_info[1]) {
3926             col_custom_occurrence = strtol(cust_format_info[1], &p, 10);
3927             if (p == cust_format_info[1] || *p != '\0') {
3928                 /* Not a valid number. */
3929                 g_free(col_custom_fields);
3930                 g_strfreev(cust_format_info);
3931                 return FALSE;
3932             }
3933         }
3934         if (col_custom_fields && cust_format_info[1] && cust_format_info[2]) {
3935             col_resolved = (cust_format_info[2][0] == 'U') ? FALSE : TRUE;
3936         }
3937         g_strfreev(cust_format_info);
3938     } else {
3939         col_fmt = get_column_format_from_str(fmt);
3940         if ((col_fmt == -1) && (!is_deprecated_column_format(fmt)))
3941             return FALSE;
3942     }
3943
3944     cfmt->fmt = col_fmt;
3945     cfmt->custom_fields = col_custom_fields;
3946     cfmt->custom_occurrence = (int)col_custom_occurrence;
3947     cfmt->resolved = col_resolved;
3948     return TRUE;
3949 }
3950
3951 /* Initialize non-dissector preferences to wired-in default values Called
3952  * at program startup and any time the profile changes. (The dissector
3953  * preferences are assumed to be set to those values by the dissectors.)
3954  * They may be overridden by the global preferences file or the user's
3955  * preferences file.
3956  */
3957 static void
3958 init_prefs(void)
3959 {
3960     if (prefs_initialized)
3961         return;
3962
3963     uat_load_all();
3964
3965     /*
3966      * Ensure the "global" preferences have been initialized so the
3967      * preference API has the proper default values to work from
3968      */
3969     pre_init_prefs();
3970
3971     prefs_register_modules();
3972
3973     prefs_initialized = TRUE;
3974 }
3975
3976 /*
3977  * Initialize non-dissector preferences used by the "register preference" API
3978  * to default values so the default values can be used when registered.
3979  *
3980  * String, filename, and directory preferences will be g_freed so they must
3981  * be g_mallocated.
3982  */
3983 static void
3984 pre_init_prefs(void)
3985 {
3986     int         i;
3987     gchar       *col_name;
3988     fmt_data    *cfmt;
3989     static const gchar *col_fmt[DEF_NUM_COLS*2] = {
3990         "No.",      "%m", "Time",        "%t",
3991         "Source",   "%s", "Destination", "%d",
3992         "Protocol", "%p", "Length",      "%L",
3993         "Info",     "%i"};
3994
3995     prefs.restore_filter_after_following_stream = FALSE;
3996     prefs.gui_toolbar_main_style = TB_STYLE_ICONS;
3997     /* We try to find the best font in the Qt code */
3998     g_free(prefs.gui_qt_font_name);
3999     prefs.gui_qt_font_name           = g_strdup("");
4000     prefs.gui_active_fg.red          =         0;
4001     prefs.gui_active_fg.green        =         0;
4002     prefs.gui_active_fg.blue         =         0;
4003     prefs.gui_active_bg.red          =     52223;
4004     prefs.gui_active_bg.green        =     59647;
4005     prefs.gui_active_bg.blue         =     65535;
4006     prefs.gui_active_style           = COLOR_STYLE_DEFAULT;
4007     prefs.gui_inactive_fg.red        =         0;
4008     prefs.gui_inactive_fg.green      =         0;
4009     prefs.gui_inactive_fg.blue       =         0;
4010     prefs.gui_inactive_bg.red        =     61439;
4011     prefs.gui_inactive_bg.green      =     61439;
4012     prefs.gui_inactive_bg.blue       =     61439;
4013     prefs.gui_inactive_style         = COLOR_STYLE_DEFAULT;
4014     prefs.gui_marked_fg.red          =     65535;
4015     prefs.gui_marked_fg.green        =     65535;
4016     prefs.gui_marked_fg.blue         =     65535;
4017     prefs.gui_marked_bg.red          =         0;
4018     prefs.gui_marked_bg.green        =      8224;
4019     prefs.gui_marked_bg.blue         =     10794;
4020     prefs.gui_ignored_fg.red         =     32767;
4021     prefs.gui_ignored_fg.green       =     32767;
4022     prefs.gui_ignored_fg.blue        =     32767;
4023     prefs.gui_ignored_bg.red         =     65535;
4024     prefs.gui_ignored_bg.green       =     65535;
4025     prefs.gui_ignored_bg.blue        =     65535;
4026     g_free(prefs.gui_colorized_fg);
4027     prefs.gui_colorized_fg           = g_strdup("000000,000000,000000,000000,000000,000000,000000,000000,000000,000000");
4028     g_free(prefs.gui_colorized_bg);
4029     prefs.gui_colorized_bg           = g_strdup("ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0");
4030     prefs.st_client_fg.red           = 32767;
4031     prefs.st_client_fg.green         =     0;
4032     prefs.st_client_fg.blue          =     0;
4033     prefs.st_client_bg.red           = 64507;
4034     prefs.st_client_bg.green         = 60909;
4035     prefs.st_client_bg.blue          = 60909;
4036     prefs.st_server_fg.red           =     0;
4037     prefs.st_server_fg.green         =     0;
4038     prefs.st_server_fg.blue          = 32767;
4039     prefs.st_server_bg.red           = 60909;
4040     prefs.st_server_bg.green         = 60909;
4041     prefs.st_server_bg.blue          = 64507;
4042
4043     if (gui_theme_is_dark) {
4044         // Green, red and yellow with HSV V = 84
4045         prefs.gui_text_valid.red         = 0x0000; /* dark green */
4046         prefs.gui_text_valid.green       = 0x66ff;
4047         prefs.gui_text_valid.blue        = 0x0000;
4048         prefs.gui_text_invalid.red       = 0x66FF; /* dark red */
4049         prefs.gui_text_invalid.green     = 0x0000;
4050         prefs.gui_text_invalid.blue      = 0x0000;
4051         prefs.gui_text_deprecated.red    = 0x66FF; /* dark yellow / olive */
4052         prefs.gui_text_deprecated.green  = 0x66FF;
4053         prefs.gui_text_deprecated.blue   = 0x0000;
4054     } else {
4055         // Green, red and yellow with HSV V = 20
4056         prefs.gui_text_valid.red         = 0xAFFF; /* light green */
4057         prefs.gui_text_valid.green       = 0xFFFF;
4058         prefs.gui_text_valid.blue        = 0xAFFF;
4059         prefs.gui_text_invalid.red       = 0xFFFF; /* light red */
4060         prefs.gui_text_invalid.green     = 0xAFFF;
4061         prefs.gui_text_invalid.blue      = 0xAFFF;
4062         prefs.gui_text_deprecated.red    = 0xFFFF; /* light yellow */
4063         prefs.gui_text_deprecated.green  = 0xFFFF;
4064         prefs.gui_text_deprecated.blue   = 0xAFFF;
4065     }
4066
4067     prefs.gui_geometry_save_position = TRUE;
4068     prefs.gui_geometry_save_size     = TRUE;
4069     prefs.gui_geometry_save_maximized= TRUE;
4070     prefs.gui_console_open           = console_open_never;
4071     prefs.gui_fileopen_style         = FO_STYLE_LAST_OPENED;
4072     prefs.gui_recent_df_entries_max  = 10;
4073     prefs.gui_recent_files_count_max = 10;
4074     g_free(prefs.gui_fileopen_dir);
4075     prefs.gui_fileopen_dir           = g_strdup(get_persdatafile_dir());
4076     prefs.gui_fileopen_preview       = 3;
4077     prefs.gui_ask_unsaved            = TRUE;
4078     prefs.gui_autocomplete_filter    = TRUE;
4079     prefs.gui_find_wrap              = TRUE;
4080     prefs.gui_update_enabled         = TRUE;
4081     prefs.gui_update_channel         = UPDATE_CHANNEL_STABLE;
4082     prefs.gui_update_interval        = 60*60*24; /* Seconds */
4083     g_free(prefs.gui_window_title);
4084     prefs.gui_window_title           = g_strdup("");
4085     g_free(prefs.gui_prepend_window_title);
4086     prefs.gui_prepend_window_title   = g_strdup("");
4087     g_free(prefs.gui_start_title);
4088     prefs.gui_start_title            = g_strdup("The World's Most Popular Network Protocol Analyzer");
4089     prefs.gui_version_placement      = version_both;
4090     prefs.gui_layout_type            = layout_type_5;
4091     prefs.gui_layout_content_1       = layout_pane_content_plist;
4092     prefs.gui_layout_content_2       = layout_pane_content_pdetails;
4093     prefs.gui_layout_content_3       = layout_pane_content_pbytes;
4094     prefs.gui_packet_editor          = FALSE;
4095     prefs.gui_packet_list_elide_mode = ELIDE_RIGHT;
4096     prefs.gui_packet_list_show_related = TRUE;
4097     prefs.gui_packet_list_show_minimap = TRUE;
4098     g_free (prefs.gui_interfaces_hide_types);
4099     prefs.gui_interfaces_hide_types = g_strdup("");
4100     prefs.gui_interfaces_show_hidden = FALSE;
4101     prefs.gui_interfaces_remote_display = TRUE;
4102     prefs.gui_qt_packet_list_separator = FALSE;
4103     prefs.gui_qt_show_selected_packet = FALSE;
4104     prefs.gui_qt_show_file_load_time = FALSE;
4105
4106     if (prefs.col_list) {
4107         free_col_info(prefs.col_list);
4108         prefs.col_list = NULL;
4109     }
4110     for (i = 0; i < DEF_NUM_COLS; i++) {
4111         cfmt = g_new(fmt_data,1);
4112         cfmt->title = g_strdup(col_fmt[i * 2]);
4113         parse_column_format(cfmt, col_fmt[(i * 2) + 1]);
4114         cfmt->visible = TRUE;
4115         cfmt->resolved = TRUE;
4116         cfmt->custom_fields = NULL;
4117         cfmt->custom_occurrence = 0;
4118         prefs.col_list = g_list_append(prefs.col_list, cfmt);
4119     }
4120     prefs.num_cols  = DEF_NUM_COLS;
4121
4122 /* set the default values for the capture dialog box */
4123     prefs.capture_prom_mode             = TRUE;
4124 #ifdef PCAP_NG_DEFAULT
4125     prefs.capture_pcap_ng               = TRUE;
4126 #else
4127     prefs.capture_pcap_ng               = FALSE;
4128 #endif
4129     prefs.capture_real_time             = TRUE;
4130     prefs.capture_no_extcap             = FALSE;
4131     prefs.capture_auto_scroll           = TRUE;
4132     prefs.capture_show_info             = FALSE;
4133
4134     if (!prefs.capture_columns) {
4135         /* First time through */
4136         for (i = 0; i < num_capture_cols; i++) {
4137             col_name = g_strdup(capture_cols[i]);
4138             prefs.capture_columns = g_list_append(prefs.capture_columns, col_name);
4139         }
4140     }
4141
4142     prefs.console_log_level          =
4143         G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR;
4144
4145 /* set the default values for the tap/statistics dialog box */
4146     prefs.tap_update_interval    = TAP_UPDATE_DEFAULT_INTERVAL;
4147     prefs.st_enable_burstinfo = TRUE;
4148     prefs.st_burst_showcount = FALSE;
4149     prefs.st_burst_resolution = ST_DEF_BURSTRES;
4150     prefs.st_burst_windowlen = ST_DEF_BURSTLEN;
4151     prefs.st_sort_casesensitve = TRUE;
4152     prefs.st_sort_rng_fixorder = TRUE;
4153     prefs.st_sort_rng_nameonly = TRUE;
4154     prefs.st_sort_defcolflag = ST_SORT_COL_COUNT;
4155     prefs.st_sort_defdescending = TRUE;
4156     prefs.st_sort_showfullname = FALSE;
4157     prefs.display_hidden_proto_items = FALSE;
4158     prefs.display_byte_fields_with_spaces = FALSE;
4159 }
4160
4161 /*
4162  * Reset a single dissector preference.
4163  */
4164 void
4165 reset_pref(pref_t *pref)
4166 {
4167     int type;
4168     if (!pref) return;
4169
4170     type = pref->type;
4171
4172     /*
4173      * This preference is no longer supported; it's not a
4174      * real preference, so we don't reset it (i.e., we
4175      * treat it as if it weren't found in the list of
4176      * preferences, and we weren't called in the first place).
4177      */
4178     if (IS_PREF_OBSOLETE(type))
4179         return;
4180     else
4181         RESET_PREF_OBSOLETE(type);
4182
4183     switch (type) {
4184
4185     case PREF_UINT:
4186     case PREF_DECODE_AS_UINT:
4187         *pref->varp.uint = pref->default_val.uint;
4188         break;
4189
4190     case PREF_BOOL:
4191         *pref->varp.boolp = pref->default_val.boolval;
4192         break;
4193
4194     case PREF_ENUM:
4195         /*
4196          * For now, we save the "description" value, so that if we
4197          * save the preferences older versions of Wireshark can at
4198          * least read preferences that they supported; we support
4199          * either the short name or the description when reading
4200          * the preferences file or a "-o" option.
4201          */
4202         *pref->varp.enump = pref->default_val.enumval;
4203         break;
4204
4205     case PREF_STRING:
4206     case PREF_SAVE_FILENAME:
4207     case PREF_OPEN_FILENAME:
4208     case PREF_DIRNAME:
4209         reset_string_like_preference(pref);
4210         break;
4211
4212     case PREF_RANGE:
4213     case PREF_DECODE_AS_RANGE:
4214         wmem_free(wmem_epan_scope(), *pref->varp.range);
4215         *pref->varp.range = range_copy(wmem_epan_scope(), pref->default_val.range);
4216         break;
4217
4218     case PREF_STATIC_TEXT:
4219     case PREF_UAT:
4220         /* Nothing to do */
4221         break;
4222
4223     case PREF_COLOR:
4224         *pref->varp.colorp = pref->default_val.color;
4225         break;
4226
4227     case PREF_CUSTOM:
4228         pref->custom_cbs.reset_cb(pref);
4229         break;
4230     }
4231 }
4232
4233 static void
4234 reset_pref_cb(gpointer data, gpointer user_data)
4235 {
4236     pref_t *pref = (pref_t *) data;
4237     module_t *module = (module_t *)user_data;
4238
4239     if (pref && (pref->type == PREF_RANGE || pref->type == PREF_DECODE_AS_RANGE)) {
4240         /*
4241          * Some dissectors expect the range (returned via prefs_get_range_value)
4242          * to remain valid if it has not changed. If it did change, then we
4243          * should set "prefs_changed_flags" to ensure that the preference apply
4244          * callback is invoked. That callback will notify dissectors that it
4245          * should no longer assume the range to be valid.
4246          */
4247         if (ranges_are_equal(*pref->varp.range, pref->default_val.range)) {
4248             /* Optimization: do not invoke apply callback if nothing changed. */
4249             return;
4250         }
4251         module->prefs_changed_flags |= prefs_get_effect_flags(pref);
4252     }
4253     reset_pref(pref);
4254 }
4255
4256 /*
4257  * Reset all preferences for a module.
4258  */
4259 static gboolean
4260 reset_module_prefs(const void *key _U_, void *value, void *data _U_)
4261 {
4262     module_t *module = (module_t *)value;
4263     g_list_foreach(module->prefs, reset_pref_cb, module);
4264     return FALSE;
4265 }
4266
4267 /* Reset preferences */
4268 void
4269 prefs_reset(void)
4270 {
4271     prefs_initialized = FALSE;
4272     g_free(prefs.saved_at_version);
4273     prefs.saved_at_version = NULL;
4274
4275     /*
4276      * Unload all UAT preferences.
4277      */
4278     uat_unload_all();
4279
4280     /*
4281      * Unload any loaded MIBs.
4282      */
4283     oids_cleanup();
4284
4285     /*
4286      * Reset the non-dissector preferences.
4287      */
4288     init_prefs();
4289
4290     /*
4291      * Reset the non-UAT dissector preferences.
4292      */
4293     wmem_tree_foreach(prefs_modules, reset_module_prefs, NULL);
4294 }
4295
4296 /* Read the preferences file, fill in "prefs", and return a pointer to it.
4297
4298    If we got an error (other than "it doesn't exist") we report it through
4299    the UI. */
4300 e_prefs *
4301 read_prefs(void)
4302 {
4303     int         err;
4304     char        *pf_path;
4305     FILE        *pf;
4306
4307     /* clean up libsmi structures before reading prefs */
4308     oids_cleanup();
4309
4310     init_prefs();
4311
4312     /*
4313      * If we don't already have the pathname of the global preferences
4314      * file, construct it.  Then, in either case, try to open the file.
4315      */
4316     if (gpf_path == NULL) {
4317         /*
4318          * We don't have the path; try the new path first, and, if that
4319          * file doesn't exist, try the old path.
4320          */
4321         gpf_path = get_datafile_path(PF_NAME);
4322         if ((pf = ws_fopen(gpf_path, "r")) == NULL && errno == ENOENT) {
4323             /*
4324              * It doesn't exist by the new name; try the old name.
4325              */
4326             g_free(gpf_path);
4327             gpf_path = get_datafile_path(OLD_GPF_NAME);
4328             pf = ws_fopen(gpf_path, "r");
4329         }
4330     } else {
4331         /*
4332          * We have the path; try it.
4333          */
4334         pf = ws_fopen(gpf_path, "r");
4335     }
4336
4337     /*
4338      * If we were able to open the file, read it.
4339      * XXX - if it failed for a reason other than "it doesn't exist",
4340      * report the error.
4341      */
4342     if (pf != NULL) {
4343         /*
4344          * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
4345          * seen.
4346          */
4347         mgcp_tcp_port_count = 0;
4348         mgcp_udp_port_count = 0;
4349
4350         /* We succeeded in opening it; read it. */
4351         err = read_prefs_file(gpf_path, pf, set_pref, NULL);
4352         if (err != 0) {
4353             /* We had an error reading the file; report it. */
4354             report_warning("Error reading global preferences file \"%s\": %s.",
4355                            gpf_path, g_strerror(err));
4356         }
4357         fclose(pf);
4358     } else {
4359         /* We failed to open it.  If we failed for some reason other than
4360            "it doesn't exist", report the error. */
4361         if (errno != ENOENT) {
4362             if (errno != 0) {
4363                 report_warning("Can't open global preferences file \"%s\": %s.",
4364                                gpf_path, g_strerror(errno));
4365             }
4366         }
4367     }
4368
4369     /* Construct the pathname of the user's preferences file. */
4370     pf_path = get_persconffile_path(PF_NAME, TRUE);
4371
4372     /* Read the user's preferences file, if it exists. */
4373     if ((pf = ws_fopen(pf_path, "r")) != NULL) {
4374         /*
4375          * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
4376          * seen.
4377          */
4378         mgcp_tcp_port_count = 0;
4379         mgcp_udp_port_count = 0;
4380
4381         /* We succeeded in opening it; read it. */
4382         err = read_prefs_file(pf_path, pf, set_pref, NULL);
4383         if (err != 0) {
4384             /* We had an error reading the file; report it. */
4385             report_warning("Error reading your preferences file \"%s\": %s.",
4386                            pf_path, g_strerror(err));
4387         } else
4388             g_free(pf_path);
4389         fclose(pf);
4390     } else {
4391         /* We failed to open it.  If we failed for some reason other than
4392            "it doesn't exist", return the errno and the pathname, so our
4393            caller can report the error. */
4394         if (errno != ENOENT) {
4395             report_warning("Can't open your preferences file \"%s\": %s.",
4396                            pf_path, g_strerror(errno));
4397         } else
4398             g_free(pf_path);
4399     }
4400
4401     /* load SMI modules if needed */
4402     oids_init();
4403
4404     return &prefs;
4405 }
4406
4407 /* read the preferences file (or similar) and call the callback
4408  * function to set each key/value pair found */
4409 int
4410 read_prefs_file(const char *pf_path, FILE *pf,
4411                 pref_set_pair_cb pref_set_pair_fct, void *private_data)
4412 {
4413     enum {
4414         START,    /* beginning of a line */
4415         IN_VAR,   /* processing key name */
4416         PRE_VAL,  /* finished processing key name, skipping white space befor evalue */
4417         IN_VAL,   /* processing value */
4418         IN_SKIP   /* skipping to the end of the line */
4419     } state = START;
4420     int       got_c;
4421     GString  *cur_val;
4422     GString  *cur_var;
4423     gboolean  got_val = FALSE;
4424     gint      fline = 1, pline = 1;
4425     gchar     hint[] = "(save preferences to remove this warning)";
4426     gchar     ver[128];
4427
4428     cur_val = g_string_new("");
4429     cur_var = g_string_new("");
4430
4431     /* Try to read in the profile name in the first line of the preferences file. */
4432     if (fscanf(pf, "# Configuration file for %127[^\r\n]", ver) == 1) {
4433         /* Assume trailing period and remove it */
4434         g_free(prefs.saved_at_version);
4435         prefs.saved_at_version = g_strndup(ver, strlen(ver) - 1);
4436     }
4437     rewind(pf);
4438
4439     while ((got_c = ws_getc_unlocked(pf)) != EOF) {
4440         if (got_c == '\r') {
4441             /* Treat CR-LF at the end of a line like LF, so that if we're reading
4442              * a Windows-format file on UN*X, we handle it the same way we'd handle
4443              * a UN*X-format file. */
4444             got_c = ws_getc_unlocked(pf);
4445             if (got_c == EOF)
4446                 break;
4447             if (got_c != '\n') {
4448                 /* Put back the character after the CR, and process the CR normally. */
4449                 ungetc(got_c, pf);
4450                 got_c = '\r';
4451             }
4452         }
4453         if (got_c == '\n') {
4454             state = START;
4455             fline++;
4456             continue;
4457         }
4458
4459         switch (state) {
4460         case START:
4461             if (g_ascii_isalnum(got_c)) {
4462                 if (cur_var->len > 0) {
4463                     if (got_val) {
4464                         if (cur_val->len > 0) {
4465                             if (cur_val->str[cur_val->len-1] == ',') {
4466                                 /*
4467                                  * If the pref has a trailing comma, eliminate it.
4468                                  */
4469                                 cur_val->str[cur_val->len-1] = '\0';
4470                                 g_warning ("%s line %d: trailing comma in \"%s\" %s", pf_path, pline, cur_var->str, hint);
4471                             }
4472                         }
4473                         /* Call the routine to set the preference; it will parse
4474                            the value as appropriate.
4475
4476                            Since we're reading a file, rather than processing
4477                            explicit user input, for range preferences, silently
4478                            lower values in excess of the range's maximum, rather
4479                            than reporting errors and failing. */
4480                         switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, FALSE)) {
4481
4482                         case PREFS_SET_OK:
4483                             break;
4484
4485                         case PREFS_SET_SYNTAX_ERR:
4486                             g_warning ("Syntax error in preference \"%s\" at line %d of\n%s %s",
4487                                        cur_var->str, pline, pf_path, hint);
4488                             break;
4489
4490                         case PREFS_SET_NO_SUCH_PREF:
4491                             g_warning ("No such preference \"%s\" at line %d of\n%s %s",
4492                                        cur_var->str, pline, pf_path, hint);
4493                             prefs.unknown_prefs = TRUE;
4494                             break;
4495
4496                         case PREFS_SET_OBSOLETE:
4497                             /*
4498                              * If an attempt is made to save the
4499                              * preferences, a popup warning will be
4500                              * displayed stating that obsolete prefs
4501                              * have been detected and the user will
4502                              * be given the opportunity to save these
4503                              * prefs under a different profile name.
4504                              * The prefs in question need to be listed
4505                              * in the console window so that the
4506                              * user can make an informed choice.
4507                              */
4508                             g_warning ("Obsolete preference \"%s\" at line %d of\n%s %s",
4509                                        cur_var->str, pline, pf_path, hint);
4510                             prefs.unknown_prefs = TRUE;
4511                             break;
4512                         }
4513                     } else {
4514                         g_warning ("Incomplete preference at line %d: of\n%s %s", pline, pf_path, hint);
4515                     }
4516                 }
4517                 state      = IN_VAR;
4518                 got_val    = FALSE;
4519                 g_string_truncate(cur_var, 0);
4520                 g_string_append_c(cur_var, (gchar) got_c);
4521                 pline = fline;
4522             } else if (g_ascii_isspace(got_c) && cur_var->len > 0 && got_val) {
4523                 state = PRE_VAL;
4524             } else if (got_c == '#') {
4525                 state = IN_SKIP;
4526             } else {
4527                 g_warning ("Malformed preference at line %d of\n%s %s", fline, pf_path, hint);
4528             }
4529             break;
4530         case IN_VAR:
4531             if (got_c != ':') {
4532                 g_string_append_c(cur_var, (gchar) got_c);
4533             } else {
4534                 /* This is a colon (':') */
4535                 state   = PRE_VAL;
4536                 g_string_truncate(cur_val, 0);
4537                 /*
4538                  * Set got_val to TRUE to accommodate prefs such as
4539                  * "gui.fileopen.dir" that do not require a value.
4540                  */
4541                 got_val = TRUE;
4542             }
4543             break;
4544         case PRE_VAL:
4545             if (!g_ascii_isspace(got_c)) {
4546                 state = IN_VAL;
4547                 g_string_append_c(cur_val, (gchar) got_c);
4548             }
4549             break;
4550         case IN_VAL:
4551             g_string_append_c(cur_val, (gchar) got_c);
4552             break;
4553         case IN_SKIP:
4554             break;
4555         }
4556     }
4557     if (cur_var->len > 0) {
4558         if (got_val) {
4559             /* Call the routine to set the preference; it will parse
4560                the value as appropriate.
4561
4562                Since we're reading a file, rather than processing
4563                explicit user input, for range preferences, silently
4564                lower values in excess of the range's maximum, rather
4565                than reporting errors and failing. */
4566             switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, FALSE)) {
4567
4568             case PREFS_SET_OK:
4569                 break;
4570
4571             case PREFS_SET_SYNTAX_ERR:
4572                 g_warning ("Syntax error in preference %s at line %d of\n%s %s",
4573                            cur_var->str, pline, pf_path, hint);
4574                 break;
4575
4576             case PREFS_SET_NO_SUCH_PREF:
4577                 g_warning ("No such preference \"%s\" at line %d of\n%s %s",
4578                            cur_var->str, pline, pf_path, hint);
4579                 prefs.unknown_prefs = TRUE;
4580                 break;
4581
4582             case PREFS_SET_OBSOLETE:
4583                 prefs.unknown_prefs = TRUE;
4584                 break;
4585             }
4586         } else {
4587             g_warning("Incomplete preference at line %d of\n%s %s",
4588                        pline, pf_path, hint);
4589         }
4590     }
4591
4592     g_string_free(cur_val, TRUE);
4593     g_string_free(cur_var, TRUE);
4594
4595     if (ferror(pf))
4596         return errno;
4597     else
4598         return 0;
4599 }
4600
4601 /*
4602  * If we were handed a preference starting with "uat:", try to turn it into
4603  * a valid uat entry.
4604  */
4605 static gboolean
4606 prefs_set_uat_pref(char *uat_entry, char **errmsg) {
4607     gchar *p, *colonp;
4608     uat_t *uat;
4609     gboolean ret;
4610
4611     colonp = strchr(uat_entry, ':');
4612     if (colonp == NULL)
4613         return FALSE;
4614
4615     p = colonp;
4616     *p++ = '\0';
4617
4618     /*
4619      * Skip over any white space (there probably won't be any, but
4620      * as we allow it in the preferences file, we might as well
4621      * allow it here).
4622      */
4623     while (g_ascii_isspace(*p))
4624         p++;
4625     if (*p == '\0') {
4626         /*
4627          * Put the colon back, so if our caller uses, in an
4628          * error message, the string they passed us, the message
4629          * looks correct.
4630          */
4631         *colonp = ':';
4632         return FALSE;
4633     }
4634
4635     uat = uat_find(uat_entry);
4636     *colonp = ':';
4637     if (uat == NULL) {
4638         *errmsg = g_strdup("Unknown preference");
4639         return FALSE;
4640     }
4641
4642     ret = uat_load_str(uat, p, errmsg);
4643     return ret;
4644 }
4645
4646 /*
4647  * Given a string of the form "<pref name>:<pref value>", as might appear
4648  * as an argument to a "-o" option, parse it and set the preference in
4649  * question.  Return an indication of whether it succeeded or failed
4650  * in some fashion.
4651  */
4652 prefs_set_pref_e
4653 prefs_set_pref(char *prefarg, char **errmsg)
4654 {
4655     gchar *p, *colonp;
4656     prefs_set_pref_e ret;
4657
4658     /*
4659      * Set the counters of "mgcp.{tcp,udp}.port" entries we've
4660      * seen to values that keep us from trying to interpret them
4661      * as "mgcp.{tcp,udp}.gateway_port" or "mgcp.{tcp,udp}.callagent_port",
4662      * as, from the command line, we have no way of guessing which
4663      * the user had in mind.
4664      */
4665     mgcp_tcp_port_count = -1;
4666     mgcp_udp_port_count = -1;
4667
4668     *errmsg = NULL;
4669
4670     colonp = strchr(prefarg, ':');
4671     if (colonp == NULL)
4672         return PREFS_SET_SYNTAX_ERR;
4673
4674     p = colonp;
4675     *p++ = '\0';
4676
4677     /*
4678      * Skip over any white space (there probably won't be any, but
4679      * as we allow it in the preferences file, we might as well
4680      * allow it here).
4681      */
4682     while (g_ascii_isspace(*p))
4683         p++;
4684     if (*p == '\0') {
4685         /*
4686          * Put the colon back, so if our caller uses, in an
4687          * error message, the string they passed us, the message
4688          * looks correct.
4689          */
4690         *colonp = ':';
4691         return PREFS_SET_SYNTAX_ERR;
4692     }
4693     if (strcmp(prefarg, "uat")) {
4694         ret = set_pref(prefarg, p, NULL, TRUE);
4695     } else {
4696         ret = prefs_set_uat_pref(p, errmsg) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR;
4697     }
4698     *colonp = ':';    /* put the colon back */
4699     return ret;
4700 }
4701
4702 guint prefs_get_uint_value_real(pref_t *pref, pref_source_t source)
4703 {
4704     switch (source)
4705     {
4706     case pref_default:
4707         return pref->default_val.uint;
4708         break;
4709     case pref_stashed:
4710         return pref->stashed_val.uint;
4711         break;
4712     case pref_current:
4713         return *pref->varp.uint;
4714         break;
4715     default:
4716         g_assert_not_reached();
4717         break;
4718     }
4719
4720     return 0;
4721 }
4722
4723 guint prefs_get_uint_value(const char *module_name, const char* pref_name)
4724 {
4725     return prefs_get_uint_value_real(prefs_find_preference(prefs_find_module(module_name), pref_name), pref_current);
4726 }
4727
4728 unsigned int prefs_set_uint_value(pref_t *pref, guint value, pref_source_t source)
4729 {
4730     unsigned int changed = 0;
4731     switch (source)
4732     {
4733     case pref_default:
4734         if (pref->default_val.uint != value) {
4735             pref->default_val.uint = value;
4736             changed = prefs_get_effect_flags(pref);
4737         }
4738         break;
4739     case pref_stashed:
4740         if (pref->stashed_val.uint != value) {
4741             pref->stashed_val.uint = value;
4742             changed = prefs_get_effect_flags(pref);
4743         }
4744         break;
4745     case pref_current:
4746         if (*pref->varp.uint != value) {
4747             *pref->varp.uint = value;
4748             changed = prefs_get_effect_flags(pref);
4749         }
4750         break;
4751     default:
4752         g_assert_not_reached();
4753         break;
4754     }
4755
4756     return changed;
4757 }
4758
4759 guint prefs_get_uint_base(pref_t *pref)
4760 {
4761     return pref->info.base;
4762 }
4763
4764 /*
4765  * Returns TRUE if the given device is hidden
4766  */
4767 gboolean
4768 prefs_is_capture_device_hidden(const char *name)
4769 {
4770     gchar *tok, *devices;
4771     size_t len;
4772
4773     if (prefs.capture_devices_hide && name) {
4774         devices = g_strdup (prefs.capture_devices_hide);
4775         len = strlen (name);
4776         for (tok = strtok (devices, ","); tok; tok = strtok(NULL, ",")) {
4777             if (strlen (tok) == len && strcmp (name, tok) == 0) {
4778                 g_free (devices);
4779                 return TRUE;
4780             }
4781         }
4782         g_free (devices);
4783     }
4784
4785     return FALSE;
4786 }
4787
4788 /*
4789  * Returns TRUE if the given column is visible (not hidden)
4790  */
4791 static gboolean
4792 prefs_is_column_visible(const gchar *cols_hidden, fmt_data *cfmt)
4793 {
4794     gchar *tok, *cols;
4795     fmt_data cfmt_hidden;
4796
4797     /*
4798      * Do we have a list of hidden columns?
4799      */
4800     if (cols_hidden) {
4801         /*
4802          * Yes - check the column against each of the ones in the
4803          * list.
4804          */
4805         cols = g_strdup(cols_hidden);
4806         for (tok = strtok(cols, ","); tok; tok = strtok(NULL, ",")) {
4807             tok = g_strstrip(tok);
4808
4809             /*
4810              * Parse this column format.
4811              */
4812             if (!parse_column_format(&cfmt_hidden, tok)) {
4813                 /*
4814                  * It's not valid; ignore it.
4815                  */
4816                 continue;
4817             }
4818
4819             /*
4820              * Does it match the column?
4821              */
4822             if (cfmt->fmt != cfmt_hidden.fmt) {
4823                 /* No. */
4824                 g_free(cfmt_hidden.custom_fields);
4825                 cfmt_hidden.custom_fields = NULL;
4826                 continue;
4827             }
4828             if (cfmt->fmt == COL_CUSTOM) {
4829                 /*
4830                  * A custom column has to have the same custom field,
4831                  * occurrence and resolved settings.
4832                  */
4833                 if (cfmt_hidden.custom_fields && cfmt->custom_fields) {
4834                     if (strcmp(cfmt->custom_fields,
4835                                cfmt_hidden.custom_fields) != 0) {
4836                         /* Different fields. */
4837                         g_free(cfmt_hidden.custom_fields);
4838                         cfmt_hidden.custom_fields = NULL;
4839                         continue;
4840                     }
4841                     if ((cfmt->custom_occurrence != cfmt_hidden.custom_occurrence) ||
4842                         (cfmt->resolved != cfmt_hidden.resolved)) {
4843                         /* Different occurrences or resolved settings. */
4844                         g_free(cfmt_hidden.custom_fields);
4845                         cfmt_hidden.custom_fields = NULL;
4846                         continue;
4847                     }
4848                 }
4849             }
4850
4851             /*
4852              * OK, they match, so it's one of the hidden fields,
4853              * hence not visible.
4854              */
4855             g_free(cfmt_hidden.custom_fields);
4856             g_free(cols);
4857             return FALSE;
4858         }
4859         g_free(cols);
4860     }
4861
4862     /*
4863      * No - either there are no hidden columns or this isn't one
4864      * of them - so it is visible.
4865      */
4866     return TRUE;
4867 }
4868
4869 /*
4870  * Returns TRUE if the given device should capture in monitor mode by default
4871  */
4872 gboolean
4873 prefs_capture_device_monitor_mode(const char *name)
4874 {
4875     gchar *tok, *devices;
4876     size_t len;
4877
4878     if (prefs.capture_devices_monitor_mode && name) {
4879         devices = g_strdup (prefs.capture_devices_monitor_mode);
4880         len = strlen (name);
4881         for (tok = strtok (devices, ","); tok; tok = strtok(NULL, ",")) {
4882             if (strlen (tok) == len && strcmp (name, tok) == 0) {
4883                 g_free (devices);
4884                 return TRUE;
4885             }
4886         }
4887         g_free (devices);
4888     }
4889
4890     return FALSE;
4891 }
4892
4893 /*
4894  * Returns TRUE if the user has marked this column as visible
4895  */
4896 gboolean
4897 prefs_capture_options_dialog_column_is_visible(const gchar *column)
4898 {
4899     GList *curr;
4900     gchar *col;
4901
4902     for (curr = g_list_first(prefs.capture_columns); curr; curr = g_list_next(curr)) {
4903         col = (gchar *)curr->data;
4904         if (col && (g_ascii_strcasecmp(col, column) == 0)) {
4905             return TRUE;
4906         }
4907     }
4908     return FALSE;
4909 }
4910
4911 gboolean
4912 prefs_has_layout_pane_content (layout_pane_content_e layout_pane_content)
4913 {
4914     return ((prefs.gui_layout_content_1 == layout_pane_content) ||
4915             (prefs.gui_layout_content_2 == layout_pane_content) ||
4916             (prefs.gui_layout_content_3 == layout_pane_content));
4917 }
4918
4919 #define PRS_GUI_FILTER_LABEL             "gui.filter_expressions.label"
4920 #define PRS_GUI_FILTER_EXPR              "gui.filter_expressions.expr"
4921 #define PRS_GUI_FILTER_ENABLED           "gui.filter_expressions.enabled"
4922
4923 /*
4924  * Extract the red, green, and blue components of a 24-bit RGB value
4925  * and convert them from [0,255] to [0,65535].
4926  */
4927 #define RED_COMPONENT(x)   (guint16) (((((x) >> 16) & 0xff) * 65535 / 255))
4928 #define GREEN_COMPONENT(x) (guint16) (((((x) >>  8) & 0xff) * 65535 / 255))
4929 #define BLUE_COMPONENT(x)  (guint16) ( (((x)        & 0xff) * 65535 / 255))
4930
4931 char
4932 string_to_name_resolve(const char *string, e_addr_resolve *name_resolve)
4933 {
4934     char c;
4935
4936     memset(name_resolve, 0, sizeof(e_addr_resolve));
4937     while ((c = *string++) != '\0') {
4938         switch (c) {
4939         case 'm':
4940             name_resolve->mac_name = TRUE;
4941             break;
4942         case 'n':
4943             name_resolve->network_name = TRUE;
4944             break;
4945         case 'N':
4946             name_resolve->use_external_net_name_resolver = TRUE;
4947             break;
4948         case 't':
4949             name_resolve->transport_name = TRUE;
4950             break;
4951         case 'd':
4952             name_resolve->dns_pkt_addr_resolution = TRUE;
4953             break;
4954         case 'v':
4955             name_resolve->vlan_name = TRUE;
4956             break;
4957         default:
4958             /*
4959              * Unrecognized letter.
4960              */
4961             return c;
4962         }
4963     }
4964     return '\0';
4965 }
4966
4967 static void
4968 try_convert_to_custom_column(gpointer *el_data)
4969 {
4970     guint haystack_idx;
4971
4972     gchar **fmt = (gchar **) el_data;
4973
4974     for (haystack_idx = 0;
4975          haystack_idx < G_N_ELEMENTS(migrated_columns);
4976          ++haystack_idx) {
4977
4978         if (strcmp(migrated_columns[haystack_idx].col_fmt, *fmt) == 0) {
4979             gchar *cust_col = g_strdup_printf("%%Cus:%s:0",
4980                                 migrated_columns[haystack_idx].col_expr);
4981
4982             g_free(*fmt);
4983             *fmt = cust_col;
4984         }
4985     }
4986 }
4987
4988 static gboolean
4989 deprecated_heur_dissector_pref(gchar *pref_name, const gchar *value)
4990 {
4991     struct heur_pref_name
4992     {
4993         const char* pref_name;
4994         const char* short_name;
4995         gboolean  more_dissectors; /* For multiple dissectors controlled by the same preference */
4996     };
4997
4998     struct heur_pref_name heur_prefs[] = {
4999         {"acn.heuristic_acn", "acn_udp", 0},
5000         {"bfcp.enable", "bfcp_tcp", 1},
5001         {"bfcp.enable", "bfcp_udp", 0},
5002         {"bt-dht.enable", "bittorrent_dht_udp", 0},
5003         {"bt-utp.enable", "bt_utp_udp", 0},
5004         {"cattp.enable", "cattp_udp", 0},
5005         {"cfp.enable", "fp_eth", 0},
5006         {"dicom.heuristic", "dicom_tcp", 0},
5007         {"dnp3.heuristics", "dnp3_tcp", 1},
5008         {"dnp3.heuristics", "dnp3_udp", 0},
5009         {"dvb-s2_modeadapt.enable", "dvb_s2_udp", 0},
5010         {"esl.enable", "esl_eth", 0},
5011         {"fp.udp_heur", "fp_udp", 0},
5012         {"gvsp.enable_heuristic", "gvsp_udp", 0},
5013         {"hdcp2.enable", "hdcp2_tcp", 0},
5014         {"hislip.enable_heuristic", "hislip_tcp", 0},
5015         {"infiniband.dissect_eoib", "mellanox_eoib", 1},
5016         {"infiniband.identify_payload", "eth_over_ib", 0},
5017         {"jxta.udp.heuristic", "jxta_udp", 0},
5018         {"jxta.tcp.heuristic", "jxta_tcp", 0},
5019         {"jxta.sctp.heuristic", "jxta_sctp", 0},
5020         {"mac-lte.heuristic_mac_lte_over_udp", "mac_lte_udp", 0},
5021         {"mbim.bulk_heuristic", "mbim_usb_bulk", 0},
5022         {"norm.heuristic_norm", "rmt_norm_udp", 0},
5023         {"openflow.heuristic", "openflow_tcp", 0},
5024         {"pdcp-lte.heuristic_pdcp_lte_over_udp", "pdcp_lte_udp", 0},
5025         {"rlc.heuristic_rlc_over_udp", "rlc_udp", 0},
5026         {"rlc-lte.heuristic_rlc_lte_over_udp", "rlc_lte_udp", 0},
5027         {"rtcp.heuristic_rtcp", "rtcp_udp", 1},
5028         {"rtcp.heuristic_rtcp", "rtcp_stun", 0},
5029         {"rtp.heuristic_rtp", "rtp_udp", 1},
5030         {"rtp.heuristic_rtp", "rtp_stun", 0},
5031         {"teredo.heuristic_teredo", "teredo_udp", 0},
5032         {"vssmonitoring.use_heuristics", "vssmonitoring_eth", 0},
5033         {"xml.heuristic", "xml_http", 1},
5034         {"xml.heuristic", "xml_sip", 1},
5035         {"xml.heuristic", "xml_media", 0},
5036         {"xml.heuristic_tcp", "xml_tcp", 0},
5037         {"xml.heuristic_udp", "xml_udp", 0},
5038     };
5039
5040     unsigned int i;
5041     heur_dtbl_entry_t* heuristic;
5042
5043
5044     for (i = 0; i < sizeof(heur_prefs)/sizeof(struct heur_pref_name); i++)
5045     {
5046         if (strcmp(pref_name, heur_prefs[i].pref_name) == 0)
5047         {
5048             heuristic = find_heur_dissector_by_unique_short_name(heur_prefs[i].short_name);
5049             if (heuristic != NULL) {
5050                 heuristic->enabled = ((g_ascii_strcasecmp(value, "true") == 0) ? TRUE : FALSE);
5051             }
5052
5053             if (!heur_prefs[i].more_dissectors)
5054                 return TRUE;
5055         }
5056     }
5057
5058
5059     return FALSE;
5060 }
5061
5062 static gboolean
5063 deprecated_enable_dissector_pref(gchar *pref_name, const gchar *value)
5064 {
5065     struct dissector_pref_name
5066     {
5067         const char* pref_name;
5068         const char* short_name;
5069     };
5070
5071     struct dissector_pref_name dissector_prefs[] = {
5072         {"transum.tsumenabled", "TRANSUM"},
5073         {"snort.enable_snort_dissector", "Snort"},
5074         {"prp.enable", "PRP"},
5075     };
5076
5077     unsigned int i;
5078     int proto_id;
5079
5080     for (i = 0; i < sizeof(dissector_prefs)/sizeof(struct dissector_pref_name); i++)
5081     {
5082         if (strcmp(pref_name, dissector_prefs[i].pref_name) == 0)
5083         {
5084             proto_id = proto_get_id_by_short_name(dissector_prefs[i].short_name);
5085             if (proto_id >= 0)
5086                 proto_set_decoding(proto_id, ((g_ascii_strcasecmp(value, "true") == 0) ? TRUE : FALSE));
5087             return TRUE;
5088         }
5089     }
5090
5091     return FALSE;
5092 }
5093
5094 static gboolean
5095 deprecated_port_pref(gchar *pref_name, const gchar *value)
5096 {
5097     struct port_pref_name
5098     {
5099         const char* pref_name;
5100         const char* module_name;    /* the protocol filter name */
5101         const char* table_name;
5102         guint base;
5103     };
5104
5105     struct obsolete_pref_name
5106     {
5107         const char* pref_name;
5108     };
5109
5110     /* For now this is only supporting TCP/UDP port dissector preferences
5111        which are assumed to be decimal */
5112     struct port_pref_name port_prefs[] = {
5113         /* TCP */
5114         {"cmp.tcp_alternate_port", "CMP", "tcp.port", 10},
5115         {"h248.tcp_port", "H248", "tcp.port", 10},
5116         {"cops.tcp.cops_port", "COPS", "tcp.port", 10},
5117         {"dhcpfo.tcp_port", "DHCPFO", "tcp.port", 10},
5118         {"enttec.tcp_port", "ENTTEC", "tcp.port", 10},
5119         {"forces.tcp_alternate_port", "ForCES", "tcp.port", 10},
5120         {"ged125.tcp_port", "GED125", "tcp.port", 10},
5121         {"hpfeeds.dissector_port", "HPFEEDS", "tcp.port", 10},
5122         {"lsc.port", "LSC", "tcp.port", 10},
5123         {"megaco.tcp.txt_port", "MEGACO", "tcp.port", 10},
5124         {"netsync.tcp_port", "Netsync", "tcp.port", 10},
5125         {"osi.tpkt_port", "OSI", "tcp.port", 10},
5126         {"rsync.tcp_port", "RSYNC", "tcp.port", 10},
5127         {"sametime.tcp_port", "SAMETIME", "tcp.port", 10},
5128         {"sigcomp.tcp.port2", "SIGCOMP", "tcp.port", 10},
5129         {"synphasor.tcp_port", "synphasor", "tcp.port", 10},
5130         {"tipc.alternate_port", "TIPC", "tcp.port", 10},
5131         {"vnc.alternate_port", "VNC", "tcp.port", 10},
5132         {"scop.port", "SCoP", "tcp.port", 10},
5133         {"scop.port_secure", "SCoP", "tcp.port", 10},
5134         /* UDP */
5135         {"h248.udp_port", "H248", "udp.port", 10},
5136         {"actrace.udp_port", "ACtrace", "udp.port", 10},
5137         {"brp.port", "BRP", "udp.port", 10},
5138         {"bvlc.additional_udp_port", "BVLC", "udp.port", 10},
5139         {"capwap.udp.port.control", "capwap", "udp.port", 10},
5140         {"capwap.udp.port.data", "capwap", "udp.port", 10},
5141         {"coap.udp_port", "CoAP", "udp.port", 10},
5142         {"enttec.udp_port", "ENTTEC", "udp.port", 10},
5143         {"forces.udp_alternate_port", "ForCES", "udp.port", 10},
5144         {"ldss.udp_port", "LDSS", "udp.port", 10},
5145         {"lmp.udp_port", "LMP", "udp.port", 10},
5146         {"ltp.port", "LTP", "udp.port", 10},
5147         {"lwres.udp.lwres_port", "LWRES", "udp.port", 10},
5148         {"megaco.udp.txt_port", "MEGACO", "udp.port", 10},
5149         {"pgm.udp.encap_ucast_port", "PGM", "udp.port", 10},
5150         {"pgm.udp.encap_mcast_port", "PGM", "udp.port", 10},
5151         {"quic.udp.quic.port", "QUIC", "udp.port", 10},
5152         {"quic.udp.quics.port", "QUIC", "udp.port", 10},
5153         {"radius.alternate_port", "RADIUS", "udp.port", 10},
5154         {"rdt.default_udp_port", "RDT", "udp.port", 10},
5155         {"alc.default.udp_port", "ALC", "udp.port", 10},
5156         {"sigcomp.udp.port2", "SIGCOMP", "udp.port", 10},
5157         {"synphasor.udp_port", "synphasor", "udp.port", 10},
5158         {"tdmop.udpport", "TDMoP", "udp.port", 10},
5159         {"uaudp.port1", "UAUDP", "udp.port", 10},
5160         {"uaudp.port2", "UAUDP", "udp.port", 10},
5161         {"uaudp.port3", "UAUDP", "udp.port", 10},
5162         {"uaudp.port4", "UAUDP", "udp.port", 10},
5163         {"uhd.dissector_port", "UHD", "udp.port", 10},
5164         {"vrt.dissector_port", "vrt", "udp.port", 10},
5165     };
5166
5167     struct port_pref_name port_range_prefs[] = {
5168         /* TCP */
5169         {"couchbase.tcp.ports", "Couchbase", "tcp.port", 10},
5170         {"gsm_ipa.tcp_ports", "GSM over IP", "tcp.port", 10},
5171         {"kafka.tcp.ports", "Kafka", "tcp.port", 10},
5172         {"kt.tcp.ports", "Kyoto Tycoon", "tcp.port", 10},
5173         {"memcache.tcp.ports", "MEMCACHE", "tcp.port", 10},
5174         {"mrcpv2.tcp.port_range", "MRCPv2", "tcp.port", 10},
5175         {"rtsp.tcp.port_range", "RTSP", "tcp.port", 10},
5176         {"sip.tcp.ports", "SIP", "tcp.port", 10},
5177         {"tds.tcp_ports", "TDS", "tcp.port", 10},
5178         {"uma.tcp.ports", "UMA", "tcp.port", 10},
5179         /* UDP */
5180         {"aruba_erm.udp.ports", "ARUBA_ERM", "udp.port", 10},
5181         {"diameter.udp.ports", "DIAMETER", "udp.port", 10},
5182         {"dmp.udp_ports", "DMP", "udp.port", 10},
5183         {"dns.udp.ports", "DNS", "udp.port", 10},
5184         {"gsm_ipa.udp_ports", "GSM over IP", "udp.port", 10},
5185         {"hcrt.dissector_udp_port", "HCrt", "udp.port", 10},
5186         {"memcache.udp.ports", "MEMCACHE", "udp.port", 10},
5187         {"nb_rtpmux.udp_ports", "NB_RTPMUX", "udp.port", 10},
5188         {"gprs-ns.udp.ports", "GPRS-NS", "udp.port", 10},
5189         {"p_mul.udp_ports", "P_MUL", "udp.port", 10},
5190         {"radius.ports", "RADIUS", "udp.port", 10},
5191         {"sflow.ports", "sFlow", "udp.port", 10},
5192         {"sscop.udp.ports", "SSCOP", "udp.port", 10},
5193         {"tftp.udp_ports", "TFTP", "udp.port", 10},
5194         {"tipc.udp.ports", "TIPC", "udp.port", 10},
5195     };
5196
5197     /* These are subdissectors of TPKT/OSITP that used to have a
5198        TCP port preference even though they were never
5199        directly on TCP.  Convert them to use Decode As
5200        with the TPKT dissector handle */
5201     struct port_pref_name tpkt_subdissector_port_prefs[] = {
5202         {"dap.tcp.port", "DAP", "tcp.port", 10},
5203         {"disp.tcp.port", "DISP", "tcp.port", 10},
5204         {"dop.tcp.port", "DOP", "tcp.port", 10},
5205         {"dsp.tcp.port", "DSP", "tcp.port", 10},
5206         {"p1.tcp.port", "P1", "tcp.port", 10},
5207         {"p7.tcp.port", "P7", "tcp.port", 10},
5208         {"rdp.tcp.port", "RDP", "tcp.port", 10},
5209     };
5210
5211     /* These are obsolete preferences from the dissectors' view,
5212        (typically because of a switch from a single value to a
5213        range value) but the name of the preference conflicts
5214        with the generated preference name from the dissector table.
5215        Don't allow the obsolete preference through to be handled */
5216     struct obsolete_pref_name obsolete_prefs[] = {
5217         {"diameter.tcp.port"},
5218         {"kafka.tcp.port"},
5219         {"mrcpv2.tcp.port"},
5220         {"rtsp.tcp.port"},
5221         {"sip.tcp.port"},
5222         {"t38.tcp.port"},
5223     };
5224
5225     unsigned int i;
5226     guint    uval;
5227     dissector_table_t sub_dissectors;
5228     dissector_handle_t handle, tpkt_handle;
5229     module_t *module;
5230     pref_t *pref;
5231
5232     static gboolean sanity_checked;
5233     if (!sanity_checked) {
5234         sanity_checked = TRUE;
5235         for (i = 0; i < G_N_ELEMENTS(port_prefs); i++) {
5236             module = prefs_find_module(port_prefs[i].module_name);
5237             if (!module) {
5238                 g_warning("Deprecated ports pref check - module '%s' not found", port_prefs[i].module_name);
5239                 continue;
5240             }
5241             pref = prefs_find_preference(module, port_prefs[i].table_name);
5242             if (!pref) {
5243                 g_warning("Deprecated ports pref '%s.%s' not found", module->name, port_prefs[i].table_name);
5244                 continue;
5245             }
5246             if (pref->type != PREF_DECODE_AS_UINT && pref->type != PREF_DECODE_AS_RANGE) {
5247                 g_warning("Deprecated ports pref '%s.%s' has wrong type: %#x (%s)", module->name, port_prefs[i].table_name, pref->type, prefs_pref_type_name(pref));
5248             }
5249         }
5250     }
5251
5252     for (i = 0; i < G_N_ELEMENTS(port_prefs); i++) {
5253         if (strcmp(pref_name, port_prefs[i].pref_name) == 0) {
5254             if (!ws_basestrtou32(value, NULL, &uval, port_prefs[i].base))
5255                 return FALSE;        /* number was bad */
5256
5257             module = prefs_find_module(port_prefs[i].module_name);
5258             pref = prefs_find_preference(module, port_prefs[i].table_name);
5259             if (pref != NULL) {
5260                 module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5261                 if (pref->type == PREF_DECODE_AS_UINT) {
5262                     *pref->varp.uint = uval;
5263                 } else if (pref->type == PREF_DECODE_AS_RANGE) {
5264                     // The legacy preference was a port number, but the new
5265                     // preference is a port range. Add to existing range.
5266                     if (uval) {
5267                         prefs_range_add_value(pref, uval);
5268                     }
5269                 }
5270             }
5271
5272             /* If the value is zero, it wouldn't add to the Decode As tables */
5273             if (uval != 0)
5274             {
5275                 sub_dissectors = find_dissector_table(port_prefs[i].table_name);
5276                 if (sub_dissectors != NULL) {
5277                     handle = dissector_table_get_dissector_handle(sub_dissectors, port_prefs[i].module_name);
5278                     if (handle != NULL) {
5279                         dissector_change_uint(port_prefs[i].table_name, uval, handle);
5280                         decode_build_reset_list(port_prefs[i].table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(uval), NULL, NULL);
5281                     }
5282                 }
5283             }
5284
5285             return TRUE;
5286         }
5287     }
5288
5289     for (i = 0; i < sizeof(port_range_prefs)/sizeof(struct port_pref_name); i++)
5290     {
5291         if (strcmp(pref_name, port_range_prefs[i].pref_name) == 0)
5292         {
5293             guint32 range_i, range_j;
5294
5295             sub_dissectors = find_dissector_table(port_range_prefs[i].table_name);
5296             if (sub_dissectors != NULL) {
5297                 switch (dissector_table_get_type(sub_dissectors)) {
5298                 case FT_UINT8:
5299                 case FT_UINT16:
5300                 case FT_UINT24:
5301                 case FT_UINT32:
5302                     break;
5303
5304                 default:
5305                     g_error("The dissector table %s (%s) is not an integer type - are you using a buggy plugin?", port_range_prefs[i].table_name, get_dissector_table_ui_name(port_range_prefs[i].table_name));
5306                     g_assert_not_reached();
5307                 }
5308
5309                 module = prefs_find_module(port_range_prefs[i].module_name);
5310                 pref = prefs_find_preference(module, port_range_prefs[i].table_name);
5311                 if (pref != NULL)
5312                 {
5313                     if (!prefs_set_range_value_work(pref, value, TRUE, &module->prefs_changed_flags))
5314                     {
5315                         return FALSE;        /* number was bad */
5316                     }
5317
5318                     handle = dissector_table_get_dissector_handle(sub_dissectors, port_range_prefs[i].module_name);
5319                     if (handle != NULL) {
5320
5321                         for (range_i = 0; range_i < (*pref->varp.range)->nranges; range_i++) {
5322                             for (range_j = (*pref->varp.range)->ranges[range_i].low; range_j < (*pref->varp.range)->ranges[range_i].high; range_j++) {
5323                                 dissector_change_uint(port_range_prefs[i].table_name, range_j, handle);
5324                                 decode_build_reset_list(port_range_prefs[i].table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(range_j), NULL, NULL);
5325                             }
5326
5327                             dissector_change_uint(port_range_prefs[i].table_name, (*pref->varp.range)->ranges[range_i].high, handle);
5328                             decode_build_reset_list(port_range_prefs[i].table_name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[range_i].high), NULL, NULL);
5329                         }
5330                     }
5331                 }
5332             }
5333
5334             return TRUE;
5335         }
5336     }
5337
5338     for (i = 0; i < sizeof(tpkt_subdissector_port_prefs)/sizeof(struct port_pref_name); i++)
5339     {
5340         if (strcmp(pref_name, tpkt_subdissector_port_prefs[i].pref_name) == 0)
5341         {
5342             /* XXX - give an error if it doesn't fit in a guint? */
5343             if (!ws_basestrtou32(value, NULL, &uval, tpkt_subdissector_port_prefs[i].base))
5344                 return FALSE;        /* number was bad */
5345
5346             /* If the value is 0 or 102 (default TPKT port), don't add to the Decode As tables */
5347             if ((uval != 0) && (uval != 102))
5348             {
5349                 tpkt_handle = find_dissector("tpkt");
5350                 if (tpkt_handle != NULL) {
5351                     dissector_change_uint(tpkt_subdissector_port_prefs[i].table_name, uval, tpkt_handle);
5352                 }
5353             }
5354
5355             return TRUE;
5356         }
5357     }
5358
5359     for (i = 0; i < sizeof(obsolete_prefs)/sizeof(struct obsolete_pref_name); i++)
5360     {
5361         if (strcmp(pref_name, obsolete_prefs[i].pref_name) == 0)
5362         {
5363             /* Just ignore the preference */
5364             return TRUE;
5365         }
5366     }
5367     return FALSE;
5368 }
5369
5370 static prefs_set_pref_e
5371 set_pref(gchar *pref_name, const gchar *value, void *private_data _U_,
5372          gboolean return_range_errors)
5373 {
5374     guint    cval;
5375     guint    uval;
5376     gboolean bval;
5377     gint     enum_val;
5378     gchar    *dotp, *last_dotp;
5379     static gchar *filter_label = NULL;
5380     static gboolean filter_enabled = FALSE;
5381     module_t *module, *containing_module;
5382     pref_t   *pref;
5383     int type;
5384
5385     //The PRS_GUI field names are here for backwards compatibility
5386     //display filters have been converted to a UAT.
5387     if (strcmp(pref_name, PRS_GUI_FILTER_LABEL) == 0) {
5388         /* Assume that PRS_GUI_FILTER_EXPR follows this preference. In case of
5389          * malicious preference files, free the previous value to limit the size
5390          * of leaked memory.  */
5391         g_free(filter_label);
5392         filter_label = g_strdup(value);
5393     } else if (strcmp(pref_name, PRS_GUI_FILTER_ENABLED) == 0) {
5394         filter_enabled = (strcmp(value, "TRUE") == 0) ? TRUE : FALSE;
5395     } else if (strcmp(pref_name, PRS_GUI_FILTER_EXPR) == 0) {
5396         /* Comments not supported for "old" preference style */
5397         filter_expression_new(filter_label, value, "", filter_enabled);
5398         g_free(filter_label);
5399         filter_label = NULL;
5400         /* Remember to save the new UAT to file. */
5401         prefs.filter_expressions_old = TRUE;
5402     } else if (strcmp(pref_name, "gui.version_in_start_page") == 0) {
5403         /* Convert deprecated value to closest current equivalent */
5404         if (g_ascii_strcasecmp(value, "true") == 0) {
5405             prefs.gui_version_placement = version_both;
5406         } else {
5407             prefs.gui_version_placement = version_neither;
5408         }
5409     } else if (strcmp(pref_name, "name_resolve") == 0 ||
5410                strcmp(pref_name, "capture.name_resolve") == 0) {
5411         /*
5412          * Handle the deprecated name resolution options.
5413          *
5414          * "TRUE" and "FALSE", for backwards compatibility, are synonyms for
5415          * RESOLV_ALL and RESOLV_NONE.
5416          *
5417          * Otherwise, we treat it as a list of name types we want to resolve.
5418          */
5419         if (g_ascii_strcasecmp(value, "true") == 0) {
5420             gbl_resolv_flags.mac_name = TRUE;
5421             gbl_resolv_flags.network_name = TRUE;
5422             gbl_resolv_flags.transport_name = TRUE;
5423         }
5424         else if (g_ascii_strcasecmp(value, "false") == 0) {
5425             disable_name_resolution();
5426         }
5427         else {
5428             /* start out with none set */
5429             disable_name_resolution();
5430             if (string_to_name_resolve(value, &gbl_resolv_flags) != '\0')
5431                 return PREFS_SET_SYNTAX_ERR;
5432         }
5433     } else if (deprecated_heur_dissector_pref(pref_name, value)) {
5434          /* Handled within deprecated_heur_dissector_pref() if found */
5435     } else if (deprecated_enable_dissector_pref(pref_name, value)) {
5436          /* Handled within deprecated_enable_dissector_pref() if found */
5437     } else if (deprecated_port_pref(pref_name, value)) {
5438          /* Handled within deprecated_port_pref() if found */
5439     } else {
5440         /* Handle deprecated "global" options that don't have a module
5441          * associated with them
5442          */
5443         if ((strcmp(pref_name, "name_resolve_concurrency") == 0) ||
5444             (strcmp(pref_name, "name_resolve_load_smi_modules") == 0)  ||
5445             (strcmp(pref_name, "name_resolve_suppress_smi_errors") == 0)) {
5446             module = nameres_module;
5447             dotp = pref_name;
5448         } else {
5449             /* To which module does this preference belong? */
5450             module = NULL;
5451             last_dotp = pref_name;
5452             while (!module) {
5453                 dotp = strchr(last_dotp, '.');
5454                 if (dotp == NULL) {
5455                     /* Either there's no such module, or no module was specified.
5456                        In either case, that means there's no such preference. */
5457                     return PREFS_SET_NO_SUCH_PREF;
5458                 }
5459                 *dotp = '\0'; /* separate module and preference name */
5460                 module = prefs_find_module(pref_name);
5461
5462                 /*
5463                  * XXX - "Diameter" rather than "diameter" was used in earlier
5464                  * versions of Wireshark; if we didn't find the module, and its name
5465                  * was "Diameter", look for "diameter" instead.
5466                  *
5467                  * In addition, the BEEP protocol used to be the BXXP protocol,
5468                  * so if we didn't find the module, and its name was "bxxp",
5469                  * look for "beep" instead.
5470                  *
5471                  * Also, the preferences for GTP v0 and v1 were combined under
5472                  * a single "gtp" heading, and the preferences for SMPP were
5473                  * moved to "smpp-gsm-sms" and then moved to "gsm-sms-ud".
5474                  * However, SMPP now has its own preferences, so we just map
5475                  * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below.
5476                  *
5477                  * We also renamed "dcp" to "dccp", "x.25" to "x25", "x411" to "p1"
5478                  * and "nsip" to "gprs_ns".
5479                  *
5480                  * The SynOptics Network Management Protocol (SONMP) is now known by
5481                  * its modern name, the Nortel Discovery Protocol (NDP).
5482                  */
5483                 if (module == NULL) {
5484                     /*
5485                      * See if there's a backwards-compatibility name
5486                      * that maps to this module.
5487                      */
5488                     module = prefs_find_module_alias(pref_name);
5489                     if (module == NULL) {
5490                         /*
5491                          * There's no alias for the module; see if the
5492                          * module name matches any protocol aliases.
5493                          */
5494                         header_field_info *hfinfo = proto_registrar_get_byalias(pref_name);
5495                         if (hfinfo) {
5496                             module = (module_t *) wmem_tree_lookup_string(prefs_modules, hfinfo->abbrev, WMEM_TREE_STRING_NOCASE);
5497                         }
5498                     }
5499                     if (module == NULL) {
5500                         /*
5501                          * There aren't any aliases.  Was the module
5502                          * removed rather than renamed?
5503                          */
5504                         if (strcmp(pref_name, "etheric") == 0 ||
5505                             strcmp(pref_name, "isup_thin") == 0) {
5506                             /*
5507                              * The dissectors for these protocols were
5508                              * removed as obsolete on 2009-07-70 in change
5509                              * 739bfc6ff035583abb9434e0e988048de38a8d9a.
5510                              */
5511                             return PREFS_SET_OBSOLETE;
5512                         }
5513                     }
5514                     if (module) {
5515                         g_warning ("Preference \"%s.%s\" has been converted to \"%s.%s\"\n"
5516                                    "Save your preferences to make this change permanent.",
5517                                    pref_name, dotp+1, module->name, dotp+1);
5518                         prefs.unknown_prefs = TRUE;
5519                     }
5520                 }
5521                 *dotp = '.';                /* put the preference string back */
5522                 dotp++;                     /* skip past separator to preference name */
5523                 last_dotp = dotp;
5524             }
5525         }
5526
5527         /* The pref is located in the module or a submodule.
5528          * Assume module, then search for a submodule holding the pref. */
5529         containing_module = module;
5530         pref = prefs_find_preference_with_submodule(module, dotp, &containing_module);
5531
5532         if (pref == NULL) {
5533             prefs.unknown_prefs = TRUE;
5534
5535             /* "gui" prefix was added to column preferences for better organization
5536              * within the preferences file
5537              */
5538             if (module == gui_column_module) {
5539                 /* While this has a subtree, there is no apply callback, so no
5540                  * need to use prefs_find_preference_with_submodule to update
5541                  * containing_module. It would not be useful. */
5542                 pref = prefs_find_preference(module, pref_name);
5543             }
5544             else if (strcmp(module->name, "mgcp") == 0) {
5545                 /*
5546                  * XXX - "mgcp.display raw text toggle" and "mgcp.display dissect tree"
5547                  * rather than "mgcp.display_raw_text" and "mgcp.display_dissect_tree"
5548                  * were used in earlier versions of Wireshark; if we didn't find the
5549                  * preference, it was an MGCP preference, and its name was
5550                  * "display raw text toggle" or "display dissect tree", look for
5551                  * "display_raw_text" or "display_dissect_tree" instead.
5552                  *
5553                  * "mgcp.tcp.port" and "mgcp.udp.port" are harder to handle, as both
5554                  * the gateway and callagent ports were given those names; we interpret
5555                  * the first as "mgcp.{tcp,udp}.gateway_port" and the second as
5556                  * "mgcp.{tcp,udp}.callagent_port", as that's the order in which
5557                  * they were registered by the MCCP dissector and thus that's the
5558                  * order in which they were written to the preferences file.  (If
5559                  * we're not reading the preferences file, but are handling stuff
5560                  * from a "-o" command-line option, we have no clue which the user
5561                  * had in mind - they should have used "mgcp.{tcp,udp}.gateway_port"
5562                  * or "mgcp.{tcp,udp}.callagent_port" instead.)
5563                  */
5564                 if (strcmp(dotp, "display raw text toggle") == 0)
5565                     pref = prefs_find_preference(module, "display_raw_text");
5566                 else if (strcmp(dotp, "display dissect tree") == 0)
5567                     pref = prefs_find_preference(module, "display_dissect_tree");
5568                 else if (strcmp(dotp, "tcp.port") == 0) {
5569                     mgcp_tcp_port_count++;
5570                     if (mgcp_tcp_port_count == 1) {
5571                         /* It's the first one */
5572                         pref = prefs_find_preference(module, "tcp.gateway_port");
5573                     } else if (mgcp_tcp_port_count == 2) {
5574                         /* It's the second one */
5575                         pref = prefs_find_preference(module, "tcp.callagent_port");
5576                     }
5577                     /* Otherwise it's from the command line, and we don't bother
5578                        mapping it. */
5579                 } else if (strcmp(dotp, "udp.port") == 0) {
5580                     mgcp_udp_port_count++;
5581                     if (mgcp_udp_port_count == 1) {
5582                         /* It's the first one */
5583                         pref = prefs_find_preference(module, "udp.gateway_port");
5584                     } else if (mgcp_udp_port_count == 2) {
5585                         /* It's the second one */
5586                         pref = prefs_find_preference(module, "udp.callagent_port");
5587                     }
5588                     /* Otherwise it's from the command line, and we don't bother
5589                        mapping it. */
5590                 }
5591             } else if (strcmp(module->name, "smb") == 0) {
5592                 /* Handle old names for SMB preferences. */
5593                 if (strcmp(dotp, "smb.trans.reassembly") == 0)
5594                     pref = prefs_find_preference(module, "trans_reassembly");
5595                 else if (strcmp(dotp, "smb.dcerpc.reassembly") == 0)
5596                     pref = prefs_find_preference(module, "dcerpc_reassembly");
5597             } else if (strcmp(module->name, "ndmp") == 0) {
5598                 /* Handle old names for NDMP preferences. */
5599                 if (strcmp(dotp, "ndmp.desegment") == 0)
5600                     pref = prefs_find_preference(module, "desegment");
5601             } else if (strcmp(module->name, "diameter") == 0) {
5602                 /* Handle old names for Diameter preferences. */
5603                 if (strcmp(dotp, "diameter.desegment") == 0)
5604                     pref = prefs_find_preference(module, "desegment");
5605             } else if (strcmp(module->name, "pcli") == 0) {
5606                 /* Handle old names for PCLI preferences. */
5607                 if (strcmp(dotp, "pcli.udp_port") == 0)
5608                     pref = prefs_find_preference(module, "udp_port");
5609             } else if (strcmp(module->name, "artnet") == 0) {
5610                 /* Handle old names for ARTNET preferences. */
5611                 if (strcmp(dotp, "artnet.udp_port") == 0)
5612                     pref = prefs_find_preference(module, "udp_port");
5613             } else if (strcmp(module->name, "mapi") == 0) {
5614                 /* Handle old names for MAPI preferences. */
5615                 if (strcmp(dotp, "mapi_decrypt") == 0)
5616                     pref = prefs_find_preference(module, "decrypt");
5617             } else if (strcmp(module->name, "fc") == 0) {
5618                 /* Handle old names for Fibre Channel preferences. */
5619                 if (strcmp(dotp, "reassemble_fc") == 0)
5620                     pref = prefs_find_preference(module, "reassemble");
5621                 else if (strcmp(dotp, "fc_max_frame_size") == 0)
5622                     pref = prefs_find_preference(module, "max_frame_size");
5623             } else if (strcmp(module->name, "fcip") == 0) {
5624                 /* Handle old names for Fibre Channel-over-IP preferences. */
5625                 if (strcmp(dotp, "desegment_fcip_messages") == 0)
5626                     pref = prefs_find_preference(module, "desegment");
5627                 else if (strcmp(dotp, "fcip_port") == 0)
5628                     pref = prefs_find_preference(module, "target_port");
5629             } else if (strcmp(module->name, "gtp") == 0) {
5630                 /* Handle old names for GTP preferences. */
5631                 if (strcmp(dotp, "gtpv0_port") == 0)
5632                     pref = prefs_find_preference(module, "v0_port");
5633                 else if (strcmp(dotp, "gtpv1c_port") == 0)
5634                     pref = prefs_find_preference(module, "v1c_port");
5635                 else if (strcmp(dotp, "gtpv1u_port") == 0)
5636                     pref = prefs_find_preference(module, "v1u_port");
5637                 else if (strcmp(dotp, "gtp_dissect_tpdu") == 0)
5638                     pref = prefs_find_preference(module, "dissect_tpdu");
5639                 else if (strcmp(dotp, "gtpv0_dissect_cdr_as") == 0)
5640                     pref = prefs_find_preference(module, "v0_dissect_cdr_as");
5641                 else if (strcmp(dotp, "gtpv0_check_etsi") == 0)
5642                     pref = prefs_find_preference(module, "v0_check_etsi");
5643                 else if (strcmp(dotp, "gtpv1_check_etsi") == 0)
5644                     pref = prefs_find_preference(module, "v1_check_etsi");
5645             } else if (strcmp(module->name, "ip") == 0) {
5646                 /* Handle old names for IP preferences. */
5647                 if (strcmp(dotp, "ip_summary_in_tree") == 0)
5648                     pref = prefs_find_preference(module, "summary_in_tree");
5649             } else if (strcmp(module->name, "iscsi") == 0) {
5650                 /* Handle old names for iSCSI preferences. */
5651                 if (strcmp(dotp, "iscsi_port") == 0)
5652                     pref = prefs_find_preference(module, "target_port");
5653             } else if (strcmp(module->name, "lmp") == 0) {
5654                 /* Handle old names for LMP preferences. */
5655                 if (strcmp(dotp, "lmp_version") == 0)
5656                     pref = prefs_find_preference(module, "version");
5657             } else if (strcmp(module->name, "mtp3") == 0) {
5658                 /* Handle old names for MTP3 preferences. */
5659                 if (strcmp(dotp, "mtp3_standard") == 0)
5660                     pref = prefs_find_preference(module, "standard");
5661                 else if (strcmp(dotp, "net_addr_format") == 0)
5662                     pref = prefs_find_preference(module, "addr_format");
5663             } else if (strcmp(module->name, "nlm") == 0) {
5664                 /* Handle old names for NLM preferences. */
5665                 if (strcmp(dotp, "nlm_msg_res_matching") == 0)
5666                     pref = prefs_find_preference(module, "msg_res_matching");
5667             } else if (strcmp(module->name, "ppp") == 0) {
5668                 /* Handle old names for PPP preferences. */
5669                 if (strcmp(dotp, "ppp_fcs") == 0)
5670                     pref = prefs_find_preference(module, "fcs_type");
5671                 else if (strcmp(dotp, "ppp_vj") == 0)
5672                     pref = prefs_find_preference(module, "decompress_vj");
5673             } else if (strcmp(module->name, "rsvp") == 0) {
5674                 /* Handle old names for RSVP preferences. */
5675                 if (strcmp(dotp, "rsvp_process_bundle") == 0)
5676                     pref = prefs_find_preference(module, "process_bundle");
5677             } else if (strcmp(module->name, "tcp") == 0) {
5678                 /* Handle old names for TCP preferences. */
5679                 if (strcmp(dotp, "tcp_summary_in_tree") == 0)
5680                     pref = prefs_find_preference(module, "summary_in_tree");
5681                 else if (strcmp(dotp, "tcp_analyze_sequence_numbers") == 0)
5682                     pref = prefs_find_preference(module, "analyze_sequence_numbers");
5683                 else if (strcmp(dotp, "tcp_relative_sequence_numbers") == 0)
5684                     pref = prefs_find_preference(module, "relative_sequence_numbers");
5685             } else if (strcmp(module->name, "udp") == 0) {
5686                 /* Handle old names for UDP preferences. */
5687                 if (strcmp(dotp, "udp_summary_in_tree") == 0)
5688                     pref = prefs_find_preference(module, "summary_in_tree");
5689             } else if (strcmp(module->name, "ndps") == 0) {
5690                 /* Handle old names for NDPS preferences. */
5691                 if (strcmp(dotp, "desegment_ndps") == 0)
5692                     pref = prefs_find_preference(module, "desegment_tcp");
5693             } else if (strcmp(module->name, "http") == 0) {
5694                 /* Handle old names for HTTP preferences. */
5695                 if (strcmp(dotp, "desegment_http_headers") == 0)
5696                     pref = prefs_find_preference(module, "desegment_headers");
5697                 else if (strcmp(dotp, "desegment_http_body") == 0)
5698                     pref = prefs_find_preference(module, "desegment_body");
5699             } else if (strcmp(module->name, "smpp") == 0) {
5700                 /* Handle preferences that moved from SMPP. */
5701                 module_t *new_module = prefs_find_module("gsm-sms-ud");
5702                 if (new_module) {
5703                     if (strcmp(dotp, "port_number_udh_means_wsp") == 0) {
5704                         pref = prefs_find_preference(new_module, "port_number_udh_means_wsp");
5705                         containing_module = new_module;
5706                     } else if (strcmp(dotp, "try_dissect_1st_fragment") == 0) {
5707                         pref = prefs_find_preference(new_module, "try_dissect_1st_fragment");
5708                         containing_module = new_module;
5709                     }
5710                 }
5711             } else if (strcmp(module->name, "asn1") == 0) {
5712                 /* Handle old generic ASN.1 preferences (it's not really a
5713                    rename, as the new preferences support multiple ports,
5714                    but we might as well copy them over). */
5715                 if (strcmp(dotp, "tcp_port") == 0)
5716                     pref = prefs_find_preference(module, "tcp_ports");
5717                 else if (strcmp(dotp, "udp_port") == 0)
5718                     pref = prefs_find_preference(module, "udp_ports");
5719                 else if (strcmp(dotp, "sctp_port") == 0)
5720                     pref = prefs_find_preference(module, "sctp_ports");
5721             } else if (strcmp(module->name, "llcgprs") == 0) {
5722                 if (strcmp(dotp, "ignore_cipher_bit") == 0)
5723                     pref = prefs_find_preference(module, "autodetect_cipher_bit");
5724             } else if (strcmp(module->name, "erf") == 0) {
5725                 if (strcmp(dotp, "erfeth") == 0) {
5726                     /* Handle the old "erfeth" preference; map it to the new
5727                        "ethfcs" preference, and map the values to those for
5728                        the new preference. */
5729                     pref = prefs_find_preference(module, "ethfcs");
5730                     if (strcmp(value, "ethfcs") == 0 || strcmp(value, "Ethernet with FCS") == 0)
5731                         value = "TRUE";
5732                     else if (strcmp(value, "eth") == 0 || strcmp(value, "Ethernet") == 0)
5733                         value = "FALSE";
5734                     else if (strcmp(value, "raw") == 0 || strcmp(value, "Raw data") == 0)
5735                         value = "TRUE";
5736                 } else if (strcmp(dotp, "erfatm") == 0) {
5737                     /* Handle the old "erfatm" preference; map it to the new
5738                        "aal5_type" preference, and map the values to those for
5739                        the new preference. */
5740                     pref = prefs_find_preference(module, "aal5_type");
5741                     if (strcmp(value, "atm") == 0 || strcmp(value, "ATM") == 0)
5742                         value = "guess";
5743                     else if (strcmp(value, "llc") == 0 || strcmp(value, "LLC") == 0)
5744                         value = "llc";
5745                     else if (strcmp(value, "raw") == 0 || strcmp(value, "Raw data") == 0)
5746                         value = "guess";
5747                 } else if (strcmp(dotp, "erfhdlc") == 0) {
5748                     /* Handle the old "erfhdlc" preference; map it to the new
5749                        "hdlc_type" preference, and map the values to those for
5750                        the new preference. */
5751                     pref = prefs_find_preference(module, "hdlc_type");
5752                     if (strcmp(value, "chdlc") == 0 || strcmp(value, "Cisco HDLC") == 0)
5753                         value = "chdlc";
5754                     else if (strcmp(value, "ppp") == 0 || strcmp(value, "PPP serial") == 0)
5755                         value = "ppp";
5756                     else if (strcmp(value, "fr") == 0 || strcmp(value, "Frame Relay") == 0)
5757                         value = "frelay";
5758                     else if (strcmp(value, "mtp2") == 0 || strcmp(value, "SS7 MTP2") == 0)
5759                         value = "mtp2";
5760                     else if (strcmp(value, "raw") == 0 || strcmp(value, "Raw data") == 0)
5761                         value = "guess";
5762                 }
5763             } else if (strcmp(module->name, "eth") == 0) {
5764                 /* "eth.qinq_ethertype" has been changed(restored) to "vlan.qinq.ethertype" */
5765                 if (strcmp(dotp, "qinq_ethertype") == 0) {
5766                     module_t *new_module = prefs_find_module("vlan");
5767                     if (new_module) {
5768                         pref = prefs_find_preference(new_module, "qinq_ethertype");
5769                         containing_module = new_module;
5770                     }
5771                 }
5772             } else if (strcmp(module->name, "taps") == 0) {
5773                 /* taps preferences moved to "statistics" module */
5774                 if (strcmp(dotp, "update_interval") == 0)
5775                     pref = prefs_find_preference(stats_module, dotp);
5776             } else if (strcmp(module->name, "packet_list") == 0) {
5777                 /* packet_list preferences moved to protocol module */
5778                 if (strcmp(dotp, "display_hidden_proto_items") == 0)
5779                     pref = prefs_find_preference(protocols_module, dotp);
5780             } else if (strcmp(module->name, "stream") == 0) {
5781                 /* stream preferences moved to gui color module */
5782                 if ((strcmp(dotp, "client.fg") == 0) ||
5783                     (strcmp(dotp, "client.bg") == 0) ||
5784                     (strcmp(dotp, "server.fg") == 0) ||
5785                     (strcmp(dotp, "server.bg") == 0))
5786                     pref = prefs_find_preference(gui_color_module, pref_name);
5787             } else if (strcmp(module->name, "nameres") == 0) {
5788                 if (strcmp(pref_name, "name_resolve_concurrency") == 0) {
5789                     pref = prefs_find_preference(nameres_module, pref_name);
5790                 } else if (strcmp(pref_name, "name_resolve_load_smi_modules") == 0) {
5791                     pref = prefs_find_preference(nameres_module, "load_smi_modules");
5792                 } else if (strcmp(pref_name, "name_resolve_suppress_smi_errors") == 0) {
5793                     pref = prefs_find_preference(nameres_module, "suppress_smi_errors");
5794                 }
5795             }
5796         }
5797         if (pref == NULL)
5798             return PREFS_SET_NO_SUCH_PREF;        /* no such preference */
5799
5800         type = pref->type;
5801         if (IS_PREF_OBSOLETE(type)) {
5802             return PREFS_SET_OBSOLETE;        /* no such preference any more */
5803         } else {
5804             RESET_PREF_OBSOLETE(type);
5805         }
5806
5807         switch (type) {
5808
5809         case PREF_UINT:
5810             if (!ws_basestrtou32(value, NULL, &uval, pref->info.base))
5811                 return PREFS_SET_SYNTAX_ERR;        /* number was bad */
5812             if (*pref->varp.uint != uval) {
5813                 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5814                 *pref->varp.uint = uval;
5815             }
5816             break;
5817         case PREF_DECODE_AS_UINT:
5818         {
5819             /* This is for backwards compatibility in case any of the preferences
5820                that shared the "Decode As" preference name and used to be PREF_UINT
5821                are now applied directly to the Decode As funtionality */
5822
5823             dissector_table_t sub_dissectors;
5824             dissector_handle_t handle;
5825
5826             if (!ws_basestrtou32(value, NULL, &uval, pref->info.base))
5827                 return PREFS_SET_SYNTAX_ERR;        /* number was bad */
5828
5829             if (*pref->varp.uint != uval) {
5830                 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5831                 *pref->varp.uint = uval;
5832
5833                 /* Name of preference is the dissector table */
5834                 sub_dissectors = find_dissector_table(pref->name);
5835                 if (sub_dissectors != NULL) {
5836                     handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5837                     if (handle != NULL) {
5838                         if (uval != 0) {
5839                             dissector_change_uint(pref->name, uval, handle);
5840                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(uval), NULL, NULL);
5841                         } else {
5842                             dissector_delete_uint(pref->name, *pref->varp.uint, handle);
5843                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), pref->varp.uint, NULL, NULL);
5844                         }
5845
5846                         /* XXX - Do we save the decode_as_entries file here? */
5847                     }
5848                 }
5849             }
5850             break;
5851         }
5852         case PREF_BOOL:
5853             /* XXX - give an error if it's neither "true" nor "false"? */
5854             if (g_ascii_strcasecmp(value, "true") == 0)
5855                 bval = TRUE;
5856             else
5857                 bval = FALSE;
5858             if (*pref->varp.boolp != bval) {
5859                 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5860                 *pref->varp.boolp = bval;
5861             }
5862             break;
5863
5864         case PREF_ENUM:
5865             /* XXX - give an error if it doesn't match? */
5866             enum_val = find_val_for_string(value, pref->info.enum_info.enumvals,
5867                                            *pref->varp.enump);
5868             if (*pref->varp.enump != enum_val) {
5869                 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5870                 *pref->varp.enump = enum_val;
5871             }
5872             break;
5873
5874         case PREF_STRING:
5875         case PREF_SAVE_FILENAME:
5876         case PREF_OPEN_FILENAME:
5877         case PREF_DIRNAME:
5878             containing_module->prefs_changed_flags |= prefs_set_string_value(pref, value, pref_current);
5879             break;
5880
5881         case PREF_RANGE:
5882         {
5883             if (!prefs_set_range_value_work(pref, value, return_range_errors,
5884                                             &containing_module->prefs_changed_flags))
5885                 return PREFS_SET_SYNTAX_ERR;        /* number was bad */
5886             break;
5887         }
5888         case PREF_DECODE_AS_RANGE:
5889         {
5890             /* This is for backwards compatibility in case any of the preferences
5891                that shared the "Decode As" preference name and used to be PREF_RANGE
5892                are now applied directly to the Decode As funtionality */
5893             range_t *newrange;
5894             dissector_table_t sub_dissectors;
5895             dissector_handle_t handle;
5896             guint32 i, j;
5897
5898             if (range_convert_str_work(wmem_epan_scope(), &newrange, value, pref->info.max_value,
5899                                        return_range_errors) != CVT_NO_ERROR) {
5900                 return PREFS_SET_SYNTAX_ERR;        /* number was bad */
5901             }
5902
5903             if (!ranges_are_equal(*pref->varp.range, newrange)) {
5904                 wmem_free(wmem_epan_scope(), *pref->varp.range);
5905                 *pref->varp.range = newrange;
5906                 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5907
5908                 /* Name of preference is the dissector table */
5909                 sub_dissectors = find_dissector_table(pref->name);
5910                 if (sub_dissectors != NULL) {
5911                     handle = dissector_table_get_dissector_handle(sub_dissectors, module->title);
5912                     if (handle != NULL) {
5913                         /* Delete all of the old values from the dissector table */
5914                         for (i = 0; i < (*pref->varp.range)->nranges; i++) {
5915                             for (j = (*pref->varp.range)->ranges[i].low; j < (*pref->varp.range)->ranges[i].high; j++) {
5916                                 dissector_delete_uint(pref->name, j, handle);
5917                                 decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j), NULL, NULL);
5918                             }
5919
5920                             dissector_delete_uint(pref->name, (*pref->varp.range)->ranges[i].high, handle);
5921                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER((*pref->varp.range)->ranges[i].high), NULL, NULL);
5922                         }
5923
5924                         /* Add new values to the dissector table */
5925                         for (i = 0; i < newrange->nranges; i++) {
5926                             for (j = newrange->ranges[i].low; j < newrange->ranges[i].high; j++) {
5927                                 dissector_change_uint(pref->name, j, handle);
5928                                 decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(j), NULL, NULL);
5929                             }
5930
5931                             dissector_change_uint(pref->name, newrange->ranges[i].high, handle);
5932                             decode_build_reset_list(pref->name, dissector_table_get_type(sub_dissectors), GUINT_TO_POINTER(newrange->ranges[i].high), NULL, NULL);
5933                         }
5934
5935                         /* XXX - Do we save the decode_as_entries file here? */
5936                     }
5937                 }
5938             } else {
5939                 wmem_free(wmem_epan_scope(), newrange);
5940             }
5941             break;
5942         }
5943
5944         case PREF_COLOR:
5945         {
5946             if (!ws_hexstrtou32(value, NULL, &cval))
5947                 return PREFS_SET_SYNTAX_ERR;        /* number was bad */
5948             if ((pref->varp.colorp->red != RED_COMPONENT(cval)) ||
5949                 (pref->varp.colorp->green != GREEN_COMPONENT(cval)) ||
5950                 (pref->varp.colorp->blue != BLUE_COMPONENT(cval))) {
5951                 containing_module->prefs_changed_flags |= prefs_get_effect_flags(pref);
5952                 pref->varp.colorp->red   = RED_COMPONENT(cval);
5953                 pref->varp.colorp->green = GREEN_COMPONENT(cval);
5954                 pref->varp.colorp->blue  = BLUE_COMPONENT(cval);
5955             }
5956             break;
5957         }
5958
5959         case PREF_CUSTOM:
5960             return pref->custom_cbs.set_cb(pref, value, &containing_module->prefs_changed_flags);
5961
5962         case PREF_STATIC_TEXT:
5963         case PREF_UAT:
5964         {
5965             break;
5966         }
5967         }
5968     }
5969
5970     return PREFS_SET_OK;
5971 }
5972
5973 typedef struct {
5974     FILE     *pf;
5975     gboolean is_gui_module;
5976 } write_gui_pref_arg_t;
5977
5978 const char *
5979 prefs_pref_type_name(pref_t *pref)
5980 {
5981     const char *type_name = "[Unknown]";
5982     int type;
5983
5984     if (!pref) {
5985         return type_name; /* ...or maybe assert? */
5986     }
5987
5988     type = pref->type;
5989
5990     if (IS_PREF_OBSOLETE(type)) {
5991         type_name = "Obsolete";
5992     } else {
5993         RESET_PREF_OBSOLETE(type);
5994     }
5995
5996     switch (type) {
5997
5998     case PREF_UINT:
5999         switch (pref->info.base) {
6000
6001         case 10:
6002             type_name = "Decimal";
6003             break;
6004
6005         case 8:
6006             type_name = "Octal";
6007             break;
6008
6009         case 16:
6010             type_name = "Hexadecimal";
6011             break;
6012         }
6013         break;
6014
6015     case PREF_BOOL:
6016         type_name = "Boolean";
6017         break;
6018
6019     case PREF_ENUM:
6020         type_name = "Choice";
6021         break;
6022
6023     case PREF_STRING:
6024         type_name = "String";
6025         break;
6026
6027     case PREF_SAVE_FILENAME:
6028     case PREF_OPEN_FILENAME:
6029         type_name = "Filename";
6030         break;
6031
6032     case PREF_DIRNAME:
6033         type_name = "Directory";
6034         break;
6035
6036     case PREF_RANGE:
6037         type_name = "Range";
6038         break;
6039
6040     case PREF_COLOR:
6041         type_name = "Color";
6042         break;
6043
6044     case PREF_CUSTOM:
6045         if (pref->custom_cbs.type_name_cb)
6046             return pref->custom_cbs.type_name_cb();
6047         type_name = "Custom";
6048         break;
6049
6050     case PREF_DECODE_AS_UINT:
6051         type_name = "Decode As value";
6052         break;
6053
6054     case PREF_DECODE_AS_RANGE:
6055         type_name = "Range (for Decode As)";
6056         break;
6057
6058     case PREF_STATIC_TEXT:
6059         type_name = "Static text";
6060         break;
6061
6062     case PREF_UAT:
6063         type_name = "UAT";
6064         break;
6065     }
6066     return type_name;
6067 }
6068
6069 unsigned int
6070 prefs_get_effect_flags(pref_t *pref)
6071 {
6072     if (pref == NULL)
6073         return 0;
6074
6075     return pref->effect_flags;
6076 }
6077
6078 void
6079 prefs_set_effect_flags(pref_t *pref, unsigned int flags)
6080 {
6081     if (pref != NULL) {
6082         pref->effect_flags = flags;
6083     }
6084 }
6085
6086 void
6087 prefs_set_effect_flags_by_name(module_t * module, const char *pref, unsigned int flags)
6088 {
6089     prefs_set_effect_flags(prefs_find_preference(module, pref), flags);
6090 }
6091
6092 unsigned int
6093 prefs_get_module_effect_flags(module_t * module)
6094 {
6095     if (module == NULL)
6096         return 0;
6097
6098     return module->effect_flags;
6099 }
6100
6101 void
6102 prefs_set_module_effect_flags(module_t * module, unsigned int flags)
6103 {
6104     if (module != NULL) {
6105         module->effect_flags = flags;
6106     }
6107 }
6108
6109 char *
6110 prefs_pref_type_description(pref_t *pref)
6111 {
6112     const char *type_desc = "An unknown preference type";
6113     int type;
6114
6115     if (!pref) {
6116         return g_strdup_printf("%s.", type_desc); /* ...or maybe assert? */
6117     }
6118
6119     type = pref->type;
6120
6121     if (IS_PREF_OBSOLETE(type)) {
6122         type_desc = "An obsolete preference";
6123     } else {
6124         RESET_PREF_OBSOLETE(type);
6125     }
6126
6127     switch (type) {
6128
6129     case PREF_UINT:
6130         switch (pref->info.base) {
6131
6132         case 10:
6133             type_desc = "A decimal number";
6134             break;
6135
6136         case 8:
6137             type_desc = "An octal number";
6138             break;
6139
6140         case 16:
6141             type_desc = "A hexadecimal number";
6142             break;
6143         }
6144         break;
6145
6146     case PREF_BOOL:
6147         type_desc = "TRUE or FALSE (case-insensitive)";
6148         break;
6149
6150     case PREF_ENUM:
6151     {
6152         const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6153         GString *enum_str = g_string_new("One of: ");
6154         while (enum_valp->name != NULL) {
6155             g_string_append(enum_str, enum_valp->description);
6156             enum_valp++;
6157             if (enum_valp->name != NULL)
6158                 g_string_append(enum_str, ", ");
6159         }
6160         g_string_append(enum_str, "\n(case-insensitive).");
6161         return g_string_free(enum_str, FALSE);
6162     }
6163
6164     case PREF_STRING:
6165         type_desc = "A string";
6166         break;
6167
6168     case PREF_SAVE_FILENAME:
6169     case PREF_OPEN_FILENAME:
6170         type_desc = "A path to a file";
6171         break;
6172
6173     case PREF_DIRNAME:
6174         type_desc = "A path to a directory";
6175         break;
6176
6177     case PREF_RANGE:
6178     {
6179         type_desc = "A string denoting an positive integer range (e.g., \"1-20,30-40\")";
6180         break;
6181     }
6182
6183     case PREF_COLOR:
6184     {
6185         type_desc = "A six-digit hexadecimal RGB color triplet (e.g. fce94f)";
6186         break;
6187     }
6188
6189     case PREF_CUSTOM:
6190         if (pref->custom_cbs.type_description_cb)
6191             return pref->custom_cbs.type_description_cb();
6192         type_desc = "A custom value";
6193         break;
6194
6195     case PREF_DECODE_AS_UINT:
6196         type_desc = "An integer value used in Decode As";
6197         break;
6198
6199     case PREF_DECODE_AS_RANGE:
6200         type_desc = "A string denoting an positive integer range for Decode As";
6201         break;
6202
6203     case PREF_STATIC_TEXT:
6204         type_desc = "[Static text]";
6205         break;
6206
6207     case PREF_UAT:
6208         type_desc = "Configuration data stored in its own file";
6209         break;
6210
6211     default:
6212         break;
6213     }
6214     return g_strdup(type_desc);
6215 }
6216
6217 gboolean
6218 prefs_pref_is_default(pref_t *pref)
6219 {
6220     int type;
6221     if (!pref) return FALSE;
6222
6223     type = pref->type;
6224     if (IS_PREF_OBSOLETE(type)) {
6225         return FALSE;
6226     } else {
6227         RESET_PREF_OBSOLETE(type);
6228     }
6229
6230     switch (type) {
6231
6232     case PREF_DECODE_AS_UINT:
6233         if (pref->default_val.uint == *pref->varp.uint)
6234             return TRUE;
6235         break;
6236
6237     case PREF_UINT:
6238         if (pref->default_val.uint == *pref->varp.uint)
6239             return TRUE;
6240         break;
6241
6242     case PREF_BOOL:
6243         if (pref->default_val.boolval == *pref->varp.boolp)
6244             return TRUE;
6245         break;
6246
6247     case PREF_ENUM:
6248         if (pref->default_val.enumval == *pref->varp.enump)
6249             return TRUE;
6250         break;
6251
6252     case PREF_STRING:
6253     case PREF_SAVE_FILENAME:
6254     case PREF_OPEN_FILENAME:
6255     case PREF_DIRNAME:
6256         if (!(g_strcmp0(pref->default_val.string, *pref->varp.string)))
6257             return TRUE;
6258         break;
6259
6260     case PREF_DECODE_AS_RANGE:
6261     case PREF_RANGE:
6262     {
6263         if ((ranges_are_equal(pref->default_val.range, *pref->varp.range)))
6264             return TRUE;
6265         break;
6266     }
6267
6268     case PREF_COLOR:
6269     {
6270         if ((pref->default_val.color.red == pref->varp.colorp->red) &&
6271             (pref->default_val.color.green == pref->varp.colorp->green) &&
6272             (pref->default_val.color.blue == pref->varp.colorp->blue))
6273             return TRUE;
6274         break;
6275     }
6276
6277     case PREF_CUSTOM:
6278         return pref->custom_cbs.is_default_cb(pref);
6279
6280     case PREF_STATIC_TEXT:
6281     case PREF_UAT:
6282         return FALSE;
6283         /* g_assert_not_reached(); */
6284         break;
6285     }
6286     return FALSE;
6287 }
6288
6289 char *
6290 prefs_pref_to_str(pref_t *pref, pref_source_t source) {
6291     const char *pref_text = "[Unknown]";
6292     void *valp; /* pointer to preference value */
6293     color_t *pref_color;
6294     gchar *tmp_value, *ret_value;
6295     int type;
6296
6297     if (!pref) {
6298         return g_strdup(pref_text);
6299     }
6300
6301     switch (source) {
6302         case pref_default:
6303             valp = &pref->default_val;
6304             /* valp = &boolval, &enumval, etc. are implied by union property */
6305             pref_color = &pref->default_val.color;
6306             break;
6307         case pref_stashed:
6308             valp = &pref->stashed_val;
6309             /* valp = &boolval, &enumval, etc. are implied by union property */
6310             pref_color = &pref->stashed_val.color;
6311             break;
6312         case pref_current:
6313             valp = pref->varp.uint;
6314             /* valp = boolval, enumval, etc. are implied by union property */
6315             pref_color = pref->varp.colorp;
6316             break;
6317         default:
6318             return g_strdup(pref_text);
6319     }
6320
6321     type = pref->type;
6322     if (IS_PREF_OBSOLETE(type)) {
6323         pref_text = "[Obsolete]";
6324     } else {
6325         RESET_PREF_OBSOLETE(type);
6326     }
6327
6328     switch (type) {
6329
6330     case PREF_DECODE_AS_UINT:
6331     case PREF_UINT:
6332     {
6333         guint pref_uint = *(guint *) valp;
6334         switch (pref->info.base) {
6335
6336         case 10:
6337             return g_strdup_printf("%u", pref_uint);
6338
6339         case 8:
6340             return g_strdup_printf("%#o", pref_uint);
6341
6342         case 16:
6343             return g_strdup_printf("%#x", pref_uint);
6344         }
6345         break;
6346     }
6347
6348     case PREF_BOOL:
6349         return g_strdup((*(gboolean *) valp) ? "TRUE" : "FALSE");
6350
6351     case PREF_ENUM:
6352     {
6353         gint pref_enumval = *(gint *) valp;
6354         /*
6355          * For now, we return the "description" value, so that if we
6356          * save the preferences older versions of Wireshark can at
6357          * least read preferences that they supported; we support
6358          * either the short name or the description when reading
6359          * the preferences file or a "-o" option.
6360          */
6361         const enum_val_t *enum_valp = pref->info.enum_info.enumvals;
6362         while (enum_valp->name != NULL) {
6363             if (enum_valp->value == pref_enumval)
6364                 return g_strdup(enum_valp->description);
6365             enum_valp++;
6366         }
6367         break;
6368     }
6369
6370     case PREF_STRING:
6371     case PREF_SAVE_FILENAME:
6372     case PREF_OPEN_FILENAME:
6373     case PREF_DIRNAME:
6374         return g_strdup(*(const char **) valp);
6375
6376     case PREF_DECODE_AS_RANGE:
6377     case PREF_RANGE:
6378         /* Convert wmem to g_alloc memory */
6379         tmp_value = range_convert_range(NULL, *(range_t **) valp);
6380         ret_value = g_strdup(tmp_value);
6381         wmem_free(NULL, tmp_value);
6382         return ret_value;
6383
6384     case PREF_COLOR:
6385         return g_strdup_printf("%02x%02x%02x",
6386                    (pref_color->red * 255 / 65535),
6387                    (pref_color->green * 255 / 65535),
6388                    (pref_color->blue * 255 / 65535));
6389
6390     case PREF_CUSTOM:
6391         if (pref->custom_cbs.to_str_cb)
6392             return pref->custom_cbs.to_str_cb(pref, source == pref_default ? TRUE : FALSE);
6393         pref_text = "[Custom]";
6394         break;
6395
6396     case PREF_STATIC_TEXT:
6397         pref_text = "[Static text]";
6398         break;
6399
6400     case PREF_UAT:
6401     {
6402         uat_t *uat = pref->varp.uat;
6403         if (uat && uat->filename)
6404             return g_strdup_printf("[Managed in the file \"%s\"]", uat->filename);
6405         else
6406             pref_text = "[Managed in an unknown file]";
6407         break;
6408     }
6409
6410     default:
6411         break;
6412     }
6413     return g_strdup(pref_text);
6414 }
6415
6416 /*
6417  * Write out a single dissector preference.
6418  */
6419 static void
6420 write_pref(gpointer data, gpointer user_data)
6421 {
6422     pref_t *pref = (pref_t *)data;
6423     write_pref_arg_t *arg = (write_pref_arg_t *)user_data;
6424     gchar **desc_lines;
6425     int i;
6426     int type;
6427
6428     type = pref->type;
6429
6430     if (IS_PREF_OBSOLETE(type)) {
6431         /*
6432          * This preference is no longer supported; it's not a
6433          * real preference, so we don't write it out (i.e., we
6434          * treat it as if it weren't found in the list of
6435          * preferences, and we weren't called in the first place).
6436          */
6437         return;
6438     } else {
6439         RESET_PREF_OBSOLETE(type);
6440     }
6441
6442     switch (type) {
6443
6444     case PREF_STATIC_TEXT:
6445     case PREF_UAT:
6446         /* Nothing to do; don't bother printing the description */
6447         return;
6448     case PREF_DECODE_AS_UINT:
6449     case PREF_DECODE_AS_RANGE:
6450         /* Data is saved through Decode As mechanism and not part of preferences file */
6451         return;
6452     default:
6453         break;
6454     }
6455
6456     if (pref->type != PREF_CUSTOM || pref->custom_cbs.type_name_cb() != NULL) {
6457         /*
6458          * The prefix will either be the module name or the parent
6459          * name if it's a subtree
6460          */
6461         const char *name_prefix = (arg->module->name != NULL) ? arg->module->name : arg->module->parent->name;
6462         char *type_desc, *pref_text;
6463         const char * def_prefix = prefs_pref_is_default(pref) ? "#" : "";
6464
6465         if (pref->type == PREF_CUSTOM) fprintf(arg->pf, "\n# %s", pref->custom_cbs.type_name_cb());
6466         fprintf(arg->pf, "\n");
6467         if (pref->description &&
6468                 (g_ascii_strncasecmp(pref->description,"", 2) != 0)) {
6469             if (pref->type != PREF_CUSTOM) {
6470                 /* We get duplicate lines otherwise. */
6471
6472                 desc_lines = g_strsplit(pref->description,"\n",0);
6473                 for (i = 0; desc_lines[i] != NULL; ++i) {
6474                     fprintf(arg->pf, "# %s\n", desc_lines[i]);
6475                 }
6476                 g_strfreev(desc_lines);
6477             }
6478         } else {
6479             fprintf(arg->pf, "# No description\n");
6480         }
6481
6482         type_desc = prefs_pref_type_description(pref);
6483         desc_lines = g_strsplit(type_desc,"\n",0);
6484         for (i = 0; desc_lines[i] != NULL; ++i) {
6485             fprintf(arg->pf, "# %s\n", desc_lines[i]);
6486         }
6487         g_strfreev(desc_lines);
6488         g_free(type_desc);
6489
6490         pref_text = prefs_pref_to_str(pref, pref_current);
6491         fprintf(arg->pf, "%s%s.%s: ", def_prefix, name_prefix, pref->name);
6492         desc_lines = g_strsplit(pref_text,"\n",0);
6493         for (i = 0; desc_lines[i] != NULL; ++i) {
6494             fprintf(arg->pf, "%s%s\n", i == 0 ? "" : def_prefix, desc_lines[i]);
6495         }
6496         if (i == 0) fprintf(arg->pf, "\n");
6497         g_strfreev(desc_lines);
6498         g_free(pref_text);
6499     }
6500
6501 }
6502
6503 static void
6504 count_non_uat_pref(gpointer data, gpointer user_data)
6505 {
6506     pref_t *pref = (pref_t *)data;
6507     int *arg = (int *)user_data;
6508
6509     switch (pref->type)
6510     {
6511     case PREF_UAT:
6512     case PREF_OBSOLETE:
6513     case PREF_DECODE_AS_UINT:
6514     case PREF_DECODE_AS_RANGE:
6515         //These types are not written in preference file
6516         break;
6517     default:
6518         (*arg)++;
6519         break;
6520     }
6521 }
6522
6523 static int num_non_uat_prefs(module_t *module)
6524 {
6525     int num = 0;
6526
6527     g_list_foreach(module->prefs, count_non_uat_pref, &num);
6528
6529     return num;
6530 }
6531
6532 /*
6533  * Write out all preferences for a module.
6534  */
6535 static guint
6536 write_module_prefs(module_t *module, gpointer user_data)
6537 {
6538     write_gui_pref_arg_t *gui_pref_arg = (write_gui_pref_arg_t*)user_data;
6539     write_pref_arg_t arg;
6540
6541     /* The GUI module needs to be explicitly called out so it
6542        can be written out of order */
6543     if ((module == gui_module) && (gui_pref_arg->is_gui_module != TRUE))
6544         return 0;
6545
6546     /* Write a header for the main modules and GUI sub-modules */
6547     if (((module->parent == NULL) || (module->parent == gui_module)) &&
6548         ((prefs_module_has_submodules(module)) ||
6549          (num_non_uat_prefs(module) > 0) ||
6550          (module->name == NULL))) {
6551          if ((module->name == NULL) && (module->parent != NULL)) {
6552             fprintf(gui_pref_arg->pf, "\n####### %s: %s ########\n", module->parent->title, module->title);
6553          } else {
6554             fprintf(gui_pref_arg->pf, "\n####### %s ########\n", module->title);
6555          }
6556     }
6557
6558     arg.module = module;
6559     arg.pf = gui_pref_arg->pf;
6560     g_list_foreach(arg.module->prefs, write_pref, &arg);
6561
6562     if (prefs_module_has_submodules(module))
6563         return prefs_modules_foreach_submodules(module, write_module_prefs, user_data);
6564
6565     return 0;
6566 }
6567
6568 /* Write out "prefs" to the user's preferences file, and return 0.
6569
6570    If the preferences file path is NULL, write to stdout.
6571
6572    If we got an error, stuff a pointer to the path of the preferences file
6573    into "*pf_path_return", and return the errno. */
6574 int
6575 write_prefs(char **pf_path_return)
6576 {
6577     char        *pf_path;
6578     FILE        *pf;
6579     write_gui_pref_arg_t write_gui_pref_info;
6580
6581     /* Needed for "-G defaultprefs" */
6582     init_prefs();
6583
6584     /* To do:
6585      * - Split output lines longer than MAX_VAL_LEN
6586      * - Create a function for the preference directory check/creation
6587      *   so that duplication can be avoided with filter.c
6588      */
6589
6590     if (pf_path_return != NULL) {
6591         pf_path = get_persconffile_path(PF_NAME, TRUE);
6592         if ((pf = ws_fopen(pf_path, "w")) == NULL) {
6593             *pf_path_return = pf_path;
6594             return errno;
6595         }
6596         g_free(pf_path);
6597     } else {
6598         pf = stdout;
6599     }
6600
6601     /*
6602      * If the preferences file is being written, be sure to write UAT files
6603      * first that were migrated from the preferences file.
6604      */
6605     if (pf_path_return != NULL) {
6606         if (prefs.filter_expressions_old) {
6607             char *err = NULL;
6608             prefs.filter_expressions_old = FALSE;
6609             if (!uat_save(uat_get_table_by_name("Display expressions"), &err)) {
6610                 g_warning("Unable to save Display expressions: %s", err);
6611                 g_free(err);
6612             }
6613         }
6614     }
6615
6616     fputs("# Configuration file for Wireshark " VERSION ".\n"
6617           "#\n"
6618           "# This file is regenerated each time preferences are saved within\n"
6619           "# Wireshark. Making manual changes should be safe, however.\n"
6620           "# Preferences that have been commented out have not been\n"
6621           "# changed from their default value.\n", pf);
6622
6623     /*
6624      * For "backwards compatibility" the GUI module is written first as it's
6625      * at the top of the file.  This is followed by all modules that can't
6626      * fit into the preferences read/write API.  Finally the remaining modules
6627      * are written in alphabetical order (including of course the protocol preferences)
6628      */
6629     write_gui_pref_info.pf = pf;
6630     write_gui_pref_info.is_gui_module = TRUE;
6631
6632     write_module_prefs(gui_module, &write_gui_pref_info);
6633
6634     write_gui_pref_info.is_gui_module = FALSE;
6635     prefs_modules_foreach_submodules(NULL, write_module_prefs, &write_gui_pref_info);
6636
6637     fclose(pf);
6638
6639     /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
6640        an error indication, or maybe write to a new preferences file and
6641        rename that file on top of the old one only if there are not I/O
6642        errors. */
6643     return 0;
6644 }
6645
6646 /** The col_list is only partly managed by the custom preference API
6647  * because its data is shared between multiple preferences, so
6648  * it's freed here
6649  */
6650 static void
6651 free_col_info(GList *list)
6652 {
6653     fmt_data *cfmt;
6654     GList *list_head = list;
6655
6656     while (list != NULL) {
6657         cfmt = (fmt_data *)list->data;
6658
6659         g_free(cfmt->title);
6660         g_free(cfmt->custom_fields);
6661         g_free(cfmt);
6662         list = g_list_next(list);
6663     }
6664     g_list_free(list_head);
6665 }
6666
6667 /*
6668  * Editor modelines
6669  *
6670  * Local Variables:
6671  * c-basic-offset: 4
6672  * tab-width: 8
6673  * indent-tabs-mode: nil
6674  * End:
6675  *
6676  * ex: set shiftwidth=4 tabstop=8 expandtab:
6677  * :indentSize=4:tabSize=8:noTabs=true:
6678  */