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