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