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