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