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