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