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