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