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