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