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