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