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