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