remove GTK1 specific font handling
[obnox/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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <glib.h>
39
40 #include <epan/filesystem.h>
41 #include <epan/address.h>
42 #include <epan/addr_resolv.h>
43 #include <epan/packet.h>
44 #include <epan/prefs.h>
45 #include <epan/proto.h>
46 #include "cfile.h"
47 #include <epan/column.h>
48 #include "print.h"
49 #include <wiretap/file_util.h>
50
51 #include <epan/prefs-int.h>
52 #include <epan/uat-int.h>
53
54 #ifdef NEED_G_ASCII_STRCASECMP_H
55 #include "g_ascii_strcasecmp.h"
56 #endif
57
58 /* Internal functions */
59 static module_t *find_subtree(module_t *parent, const char *tilte);
60 static module_t *prefs_register_module_or_subtree(module_t *parent,
61     const char *name, const char *title, const char *description, gboolean is_subtree,
62     void (*apply_cb)(void));
63 static struct preference *find_preference(module_t *, const char *);
64 static prefs_set_pref_e set_pref(gchar*, gchar*, void *);
65 static GList *get_string_list(gchar *);
66 static gchar *put_string_list(GList *);
67 static void   clear_string_list(GList *);
68 static void   free_col_info(e_prefs *);
69
70 #define PF_NAME         "preferences"
71 #define OLD_GPF_NAME    "wireshark.conf"        /* old name for global preferences file */
72
73 static gboolean prefs_initialized = FALSE;
74 static gchar *gpf_path = NULL;
75
76 /*
77  * XXX - variables to allow us to attempt to interpret the first
78  * "mgcp.{tcp,udp}.port" in a preferences file as
79  * "mgcp.{tcp,udp}.gateway_port" and the second as
80  * "mgcp.{tcp,udp}.callagent_port".
81  */
82 static int mgcp_tcp_port_count;
83 static int mgcp_udp_port_count;
84
85 e_prefs prefs;
86
87 static const gchar      *gui_ptree_line_style_text[] =
88         { "NONE", "SOLID", "DOTTED", "TABBED", NULL };
89
90 static const gchar      *gui_ptree_expander_style_text[] =
91         { "NONE", "SQUARE", "TRIANGLE", "CIRCULAR", NULL };
92
93 static const gchar      *gui_hex_dump_highlight_style_text[] =
94         { "BOLD", "INVERSE", NULL };
95
96 static const gchar      *gui_console_open_text[] =
97         { "NEVER", "AUTOMATIC", "ALWAYS", NULL };
98
99 static const gchar      *gui_fileopen_style_text[] =
100         { "LAST_OPENED", "SPECIFIED", NULL };
101
102 /* GTK knows of two ways representing "both", vertical and horizontal aligned.
103  * as this may not work on other guis, we use only "both" in general here */
104 static const gchar      *gui_toolbar_style_text[] =
105         { "ICONS", "TEXT", "BOTH", NULL };
106
107 static const gchar      *gui_layout_content_text[] =
108         { "NONE", "PLIST", "PDETAILS", "PBYTES", NULL };
109
110 /*
111  * List of all modules with preference settings.
112  */
113 static emem_tree_t *prefs_modules = NULL;
114
115 /*
116  * List of all modules that should show up at the top level of the
117  * tree in the preference dialog box.
118  */
119 static emem_tree_t *prefs_top_level_modules = NULL;
120
121 /** Sets up memory used by proto routines. Called at program startup */
122 void prefs_init(void)
123 {
124   prefs_modules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_modules");
125   prefs_top_level_modules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_top_level_modules");
126 }
127
128 /** Frees memory used by proto routines. Called at program shutdown */
129 void prefs_cleanup(void)
130 {
131 }
132
133 /*
134  * Register a module that will have preferences.
135  * Specify the module under which to register it or NULL to register it
136  * at the top level, the name used for the module in the preferences file,
137  * the title used in the tab for it in a preferences dialog box, and a
138  * routine to call back when we apply the preferences.
139  */
140 module_t *
141 prefs_register_module(module_t *parent, const char *name, const char *title,
142     const char *description, void (*apply_cb)(void))
143 {
144         return prefs_register_module_or_subtree(parent, name, title, description,
145             FALSE, apply_cb);
146 }
147
148 /*
149  * Register a subtree that will have modules under it.
150  * Specify the module under which to register it or NULL to register it
151  * at the top level and the title used in the tab for it in a preferences
152  * dialog box.
153  */
154 module_t *
155 prefs_register_subtree(module_t *parent, const char *title, const char *description)
156 {
157         return prefs_register_module_or_subtree(parent, NULL, title, description, TRUE,
158             NULL);
159 }
160
161 static module_t *
162 prefs_register_module_or_subtree(module_t *parent, const char *name,
163     const char *title, const char *description, gboolean is_subtree, void (*apply_cb)(void))
164 {
165         module_t *module;
166         const char *p;
167         guchar c;
168
169         /* this module may have been created as a subtree item previously */
170         if((module = find_subtree(parent, title))) {
171           /* the module is currently a subtree */
172           module->name = name;
173           module->apply_cb = apply_cb;
174           module->description = description;
175
176           if (prefs_find_module(name) == NULL) {
177                 pe_tree_insert_string(prefs_modules, name, module, EMEM_TREE_STRING_NOCASE);
178           }
179
180           return module;
181         }
182
183         module = g_malloc(sizeof (module_t));
184         module->name = name;
185         module->title = title;
186         module->description = description;
187         module->apply_cb = apply_cb;
188         module->prefs = NULL;   /* no preferences, to start */
189         module->submodules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_submodules");
190         module->numprefs = 0;
191         module->prefs_changed = FALSE;
192         module->obsolete = FALSE;
193
194         /*
195          * Do we have a module name?
196          */
197         if (name != NULL) {
198                 /*
199                  * Yes.
200                  * Make sure that only lower-case ASCII letters, numbers,
201                  * underscores, hyphens, and dots appear in the name.
202                  *
203                  * Crash if there is, as that's an error in the code;
204                  * you can make the title a nice string with capitalization,
205                  * white space, punctuation, etc., but the name can be used
206                  * on the command line, and shouldn't require quoting,
207                  * shifting, etc.
208                  */
209                 for (p = name; (c = *p) != '\0'; p++)
210                         g_assert(isascii(c) &&
211                             (islower(c) || isdigit(c) || c == '_' ||
212                              c == '-' || c == '.'));
213
214                 /*
215                  * Make sure there's not already a module with that
216                  * name.  Crash if there is, as that's an error in the
217                  * code, and the code has to be fixed not to register
218                  * more than one module with the same name.
219                  *
220                  * We search the list of all modules; the subtree stuff
221                  * doesn't require preferences in subtrees to have names
222                  * that reflect the subtree they're in (that would require
223                  * protocol preferences to have a bogus "protocol.", or
224                  * something such as that, to be added to all their names).
225                  */
226                 g_assert(prefs_find_module(name) == NULL);
227
228                 /*
229                  * Insert this module in the list of all modules.
230                  */
231                 pe_tree_insert_string(prefs_modules, name, module, EMEM_TREE_STRING_NOCASE);
232         } else {
233                 /*
234                  * This has no name, just a title; check to make sure it's a
235                  * subtree, and crash if it's not.
236                  */
237                 g_assert(is_subtree);
238         }
239
240         /*
241          * Insert this module into the appropriate place in the display
242          * tree.
243          */
244         if (parent == NULL) {
245                 /*
246                  * It goes at the top.
247                  */
248                 pe_tree_insert_string(prefs_top_level_modules, title, module, EMEM_TREE_STRING_NOCASE);
249         } else {
250                 /*
251                  * It goes into the list for this module.
252                  */
253                 pe_tree_insert_string(parent->submodules, title, module, EMEM_TREE_STRING_NOCASE);
254         }
255
256         return module;
257 }
258
259 /*
260  * Register that a protocol has preferences.
261  */
262 module_t *protocols_module;
263
264 module_t *
265 prefs_register_protocol(int id, void (*apply_cb)(void))
266 {
267         protocol_t *protocol;
268
269         /*
270          * Have we yet created the "Protocols" subtree?
271          */
272         if (protocols_module == NULL) {
273                 /*
274                  * No.  Do so.
275                  */
276                 protocols_module = prefs_register_subtree(NULL, "Protocols", NULL);
277         }
278         protocol = find_protocol_by_id(id);
279         return prefs_register_module(protocols_module,
280             proto_get_protocol_filter_name(id),
281             proto_get_protocol_short_name(protocol),
282             proto_get_protocol_name(id), apply_cb);
283 }
284
285
286 module_t *
287 prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(void))
288 {
289         protocol_t *protocol;
290         module_t   *subtree_module;
291         module_t   *new_module;
292         char       *sep = NULL, *ptr = NULL;
293         char       *csubtree = NULL;
294
295         /*
296          * Have we yet created the "Protocols" subtree?
297          */
298         if (protocols_module == NULL) {
299                 /*
300                  * No.  Do so.
301                  */
302                 protocols_module = prefs_register_subtree(NULL, "Protocols", NULL);
303         }
304
305         subtree_module = protocols_module;
306
307         if(subtree) {
308           /* take a copy of the buffer */
309           ptr = csubtree = g_strdup(subtree);
310
311           while(ptr && *ptr) {
312
313             if((sep = strchr(ptr, '/')))
314               *sep++ = '\0';
315
316             if(!(new_module = find_subtree(subtree_module, ptr))) {
317               /* create it */
318               new_module = prefs_register_subtree(subtree_module, ptr, NULL);
319             }
320
321             subtree_module = new_module;
322             ptr = sep;
323
324           }
325
326           /* g_free(csubtree); */
327
328         }
329
330         protocol = find_protocol_by_id(id);
331         return prefs_register_module(subtree_module,
332             proto_get_protocol_filter_name(id),
333             proto_get_protocol_short_name(protocol),
334             proto_get_protocol_name(id), apply_cb);
335 }
336
337
338 /*
339  * Register that a protocol used to have preferences but no longer does,
340  * by creating an "obsolete" module for it.
341  */
342 module_t *
343 prefs_register_protocol_obsolete(int id)
344 {
345         module_t *module;
346         protocol_t *protocol;
347
348         /*
349          * Have we yet created the "Protocols" subtree?
350          */
351         if (protocols_module == NULL) {
352                 /*
353                  * No.  Do so.
354                  */
355                 protocols_module = prefs_register_subtree(NULL, "Protocols", NULL);
356         }
357         protocol = find_protocol_by_id(id);
358         module = prefs_register_module(protocols_module,
359             proto_get_protocol_filter_name(id),
360             proto_get_protocol_short_name(protocol),
361             proto_get_protocol_name(id), NULL);
362         module->obsolete = TRUE;
363         return module;
364 }
365
366 module_t *
367 prefs_find_module(const char *name)
368 {
369         return pe_tree_lookup_string(prefs_modules, name, EMEM_TREE_STRING_NOCASE);
370 }
371
372 static module_t *
373 find_subtree(module_t *parent, const char *name)
374 {
375         return pe_tree_lookup_string(parent ? parent->submodules : prefs_top_level_modules, name, EMEM_TREE_STRING_NOCASE);
376 }
377
378 /*
379  * Call a callback function, with a specified argument, for each module
380  * in a list of modules.  If the list is NULL, searches the top-level
381  * list in the display tree of modules.  If any callback returns a
382  * non-zero value, we stop and return that value, otherwise we
383  * return 0.
384  *
385  * Ignores "obsolete" modules; their sole purpose is to allow old
386  * preferences for dissectors that no longer have preferences to be
387  * silently ignored in preference files.  Does not ignore subtrees,
388  * as this can be used when walking the display tree of modules.
389  */
390
391 typedef struct {
392         module_cb callback;
393         gpointer user_data;
394         guint ret;
395 } call_foreach_t;
396
397 static gboolean
398 call_foreach_cb(void *value, void *data)
399 {
400         module_t *module = (module_t*)value;
401         call_foreach_t *call_data = (call_foreach_t*)data;
402
403         if (!module->obsolete) {
404                 call_data->ret = (*call_data->callback)(module, call_data->user_data);
405         }
406         return (call_data->ret != 0);
407 }
408
409 static guint
410 prefs_module_list_foreach(emem_tree_t *module_list, module_cb callback,
411     gpointer user_data)
412 {
413         call_foreach_t call_data;
414
415         if (module_list == NULL)
416                 module_list = prefs_top_level_modules;
417
418         call_data.callback = callback;
419         call_data.user_data = user_data;
420         call_data.ret = 0;
421         pe_tree_foreach(module_list, call_foreach_cb, &call_data);
422         return call_data.ret;
423 }
424
425 /*
426  * Returns TRUE if module has any submodules
427  */
428 gboolean prefs_module_has_submodules(module_t *module)
429 {
430         if (module->submodules == NULL) {
431                 return FALSE;
432         }
433
434         if (module->submodules->tree == NULL) {
435                 return FALSE;
436         }
437
438         return TRUE;
439 }
440
441 /*
442  * Call a callback function, with a specified argument, for each module
443  * in the list of all modules.  (This list does not include subtrees.)
444  *
445  * Ignores "obsolete" modules; their sole purpose is to allow old
446  * preferences for dissectors that no longer have preferences to be
447  * silently ignored in preference files.
448  */
449 guint
450 prefs_modules_foreach(module_cb callback, gpointer user_data)
451 {
452         return prefs_module_list_foreach(prefs_modules, callback, user_data);
453 }
454
455 /*
456  * Call a callback function, with a specified argument, for each submodule
457  * of specified modules.  If the module is NULL, goes through the top-level
458  * list in the display tree of modules.
459  *
460  * Ignores "obsolete" modules; their sole purpose is to allow old
461  * preferences for dissectors that no longer have preferences to be
462  * silently ignored in preference files.  Does not ignore subtrees,
463  * as this can be used when walking the display tree of modules.
464  */
465 guint
466 prefs_modules_foreach_submodules(module_t *module, module_cb callback, gpointer user_data)
467 {
468         return prefs_module_list_foreach((module)?module->submodules:prefs_top_level_modules, callback, user_data);
469 }
470
471 static gboolean
472 call_apply_cb(void *value, void *data _U_)
473 {
474         module_t *module = value;
475
476         if (module->obsolete)
477                 return FALSE;
478         if (module->prefs_changed) {
479                 if (module->apply_cb != NULL)
480                         (*module->apply_cb)();
481                 module->prefs_changed = FALSE;
482         }
483         return FALSE;
484 }
485
486 /*
487  * Call the "apply" callback function for each module if any of its
488  * preferences have changed, and then clear the flag saying its
489  * preferences have changed, as the module has been notified of that
490  * fact.
491  */
492 void
493 prefs_apply_all(void)
494 {
495         pe_tree_foreach(prefs_modules, call_apply_cb, NULL);
496 }
497
498 /*
499  * Call the "apply" callback function for a specific module if any of
500  * its preferences have changed, and then clear the flag saying its
501  * preferences have changed, as the module has been notified of that
502  * fact.
503  */
504 void
505 prefs_apply(module_t *module)
506 {
507         if (module && module->prefs_changed)
508                 call_apply_cb(module, NULL);
509 }
510
511 /*
512  * Register a preference in a module's list of preferences.
513  * If it has a title, give it an ordinal number; otherwise, it's a
514  * preference that won't show up in the UI, so it shouldn't get an
515  * ordinal number (the ordinal should be the ordinal in the set of
516  * *visible* preferences).
517  */
518 static pref_t *
519 register_preference(module_t *module, const char *name, const char *title,
520     const char *description, pref_type_t type)
521 {
522         pref_t *preference;
523         const gchar *p;
524
525         preference = g_malloc(sizeof (pref_t));
526         preference->name = name;
527         preference->title = title;
528         preference->description = description;
529         preference->type = type;
530         if (title != NULL)
531                 preference->ordinal = module->numprefs;
532         else
533                 preference->ordinal = -1;       /* no ordinal for you */
534
535         /*
536          * Make sure that only lower-case ASCII letters, numbers,
537          * underscores, and dots appear in the preference name.
538          *
539          * Crash if there is, as that's an error in the code;
540          * you can make the title and description nice strings
541          * with capitalization, white space, punctuation, etc.,
542          * but the name can be used on the command line,
543          * and shouldn't require quoting, shifting, etc.
544          */
545         for (p = name; *p != '\0'; p++)
546                 g_assert(isascii((guchar)*p) &&
547                     (islower((guchar)*p) || isdigit((guchar)*p) || *p == '_' || *p == '.'));
548
549         /*
550          * Make sure there's not already a preference with that
551          * name.  Crash if there is, as that's an error in the
552          * code, and the code has to be fixed not to register
553          * more than one preference with the same name.
554          */
555         g_assert(find_preference(module, name) == NULL);
556
557         if (type != PREF_OBSOLETE) {
558                 /*
559                  * Make sure the preference name doesn't begin with the
560                  * module name, as that's redundant and Just Silly.
561                  */
562                 g_assert((strncmp(name, module->name, strlen(module->name)) != 0) ||
563                         (((name[strlen(module->name)]) != '.') && ((name[strlen(module->name)]) != '_')));
564         }
565
566         /*
567          * There isn't already one with that name, so add the
568          * preference.
569          */
570         module->prefs = g_list_append(module->prefs, preference);
571         if (title != NULL)
572                 module->numprefs++;
573
574         return preference;
575 }
576
577 /*
578  * Find a preference in a module's list of preferences, given the module
579  * and the preference's name.
580  */
581 static gint
582 preference_match(gconstpointer a, gconstpointer b)
583 {
584         const pref_t *pref = a;
585         const char *name = b;
586
587         return strcmp(name, pref->name);
588 }
589
590 static struct preference *
591 find_preference(module_t *module, const char *name)
592 {
593         GList *list_entry;
594
595         list_entry = g_list_find_custom(module->prefs, name,
596             preference_match);
597
598         if (list_entry == NULL)
599                 return NULL;    /* no such preference */
600         return (struct preference *) list_entry->data;
601 }
602
603 /*
604  * Returns TRUE if the given protocol has registered preferences
605  */
606 gboolean
607 prefs_is_registered_protocol(const char *name)
608 {
609         module_t *m = prefs_find_module(name);
610
611         return (m != NULL && !m->obsolete);
612 }
613
614 /*
615  * Returns the module title of a registered protocol
616  */
617 const char *
618 prefs_get_title_by_name(const char *name)
619 {
620         module_t *m = prefs_find_module(name);
621
622         return (m != NULL && !m->obsolete) ? m->title : NULL;
623 }
624
625 /*
626  * Register a preference with an unsigned integral value.
627  */
628 void
629 prefs_register_uint_preference(module_t *module, const char *name,
630     const char *title, const char *description, guint base, guint *var)
631 {
632         pref_t *preference;
633
634         preference = register_preference(module, name, title, description,
635             PREF_UINT);
636         preference->varp.uint = var;
637         g_assert(base > 0 && base != 1 && base < 37);
638         preference->info.base = base;
639 }
640
641 /*
642  * Register a preference with an Boolean value.
643  */
644 void
645 prefs_register_bool_preference(module_t *module, const char *name,
646     const char *title, const char *description, gboolean *var)
647 {
648         pref_t *preference;
649
650         preference = register_preference(module, name, title, description,
651             PREF_BOOL);
652         preference->varp.boolp = var;
653 }
654
655 /*
656  * Register a preference with an enumerated value.
657  */
658 void
659 prefs_register_enum_preference(module_t *module, const char *name,
660     const char *title, const char *description, gint *var,
661     const enum_val_t *enumvals, gboolean radio_buttons)
662 {
663         pref_t *preference;
664
665         preference = register_preference(module, name, title, description,
666             PREF_ENUM);
667         preference->varp.enump = var;
668         preference->info.enum_info.enumvals = enumvals;
669         preference->info.enum_info.radio_buttons = radio_buttons;
670 }
671
672 /*
673  * Register a preference with a character-string value.
674  */
675 void
676 prefs_register_string_preference(module_t *module, const char *name,
677     const char *title, const char *description, const char **var)
678 {
679         pref_t *preference;
680
681         preference = register_preference(module, name, title, description,
682             PREF_STRING);
683
684         /*
685          * String preference values should be non-null (as you can't
686          * keep them null after using the preferences GUI, you can at best
687          * have them be null strings) and freeable (as we free them
688          * if we change them).
689          *
690          * If the value is a null pointer, make it a copy of a null
691          * string, otherwise make it a copy of the value.
692          */
693         if (*var == NULL)
694                 *var = g_strdup("");
695         else
696                 *var = g_strdup(*var);
697         preference->varp.string = var;
698         preference->saved_val.string = NULL;
699 }
700
701 /*
702  * Register a preference with a ranged value.
703  */
704 void
705 prefs_register_range_preference(module_t *module, const char *name,
706     const char *title, const char *description, range_t **var,
707     guint32 max_value)
708 {
709         pref_t *preference;
710
711         preference = register_preference(module, name, title, description,
712                                          PREF_RANGE);
713         preference->info.max_value = max_value;
714
715
716         /*
717          * Range preference values should be non-null (as you can't
718          * keep them null after using the preferences GUI, you can at best
719          * have them be empty ranges) and freeable (as we free them
720          * if we change them).
721          *
722          * If the value is a null pointer, make it an empty range.
723          */
724         if (*var == NULL)
725                 *var = range_empty();
726         preference->varp.range = var;
727         preference->saved_val.range = NULL;
728 }
729
730 /*
731  * Register a static text 'preference'.  It can be used to add explanatory
732  * text inline with other preferences in the GUI.
733  * Note: Static preferences are not saved to the preferences file.
734  */
735 void prefs_register_static_text_preference(module_t *module, const char *name,
736     const char *title, const char *description)
737 {
738         register_preference(module, name, title, description, PREF_STATIC_TEXT);
739 }
740
741 /*
742  * Register a uat 'preference'. It adds a button that opens the uat's window in the
743  * preferences tab of the module.
744  */
745 extern void prefs_register_uat_preference(module_t *module,
746                                                                                   const char *name,
747                                                                                   const char *title,
748                                                                                   const char *description,
749                                                                                   void* uat) {
750
751         pref_t* preference = register_preference(module, name, title, description, PREF_UAT);
752
753         preference->varp.uat = uat;
754
755 }
756
757
758
759 /*
760  * Register a preference that used to be supported but no longer is.
761  */
762 void
763 prefs_register_obsolete_preference(module_t *module, const char *name)
764 {
765         register_preference(module, name, NULL, NULL, PREF_OBSOLETE);
766 }
767
768 /*
769  * Call a callback function, with a specified argument, for each preference
770  * in a given module.
771  *
772  * If any of the callbacks return a non-zero value, stop and return that
773  * value, otherwise return 0.
774  */
775 guint
776 prefs_pref_foreach(module_t *module, pref_cb callback, gpointer user_data)
777 {
778         GList *elem;
779         pref_t *pref;
780         guint ret;
781
782         for (elem = g_list_first(module->prefs); elem != NULL;
783             elem = g_list_next(elem)) {
784                 pref = elem->data;
785                 if (pref->type == PREF_OBSOLETE) {
786                         /*
787                          * This preference is no longer supported; it's
788                          * not a real preference, so we don't call the
789                          * callback for it (i.e., we treat it as if it
790                          * weren't found in the list of preferences,
791                          * and we weren't called in the first place).
792                          */
793                         continue;
794                 }
795
796                 ret = (*callback)(pref, user_data);
797                 if (ret != 0)
798                         return ret;
799         }
800         return 0;
801 }
802
803 /*
804  * Register all non-dissector modules' preferences.
805  */
806 void
807 prefs_register_modules(void)
808 {
809 }
810
811 /* Parse through a list of comma-separated, possibly quoted strings.
812    Return a list of the string data. */
813 static GList *
814 get_string_list(gchar *str)
815 {
816   enum { PRE_STRING, IN_QUOT, NOT_IN_QUOT };
817
818   gint      state = PRE_STRING, i = 0, j = 0;
819   gboolean  backslash = FALSE;
820   guchar    cur_c;
821   gchar    *slstr = NULL;
822   GList    *sl = NULL;
823
824   /* Allocate a buffer for the first string.   */
825   slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
826   j = 0;
827
828   for (;;) {
829     cur_c = str[i];
830     if (cur_c == '\0') {
831       /* It's the end of the input, so it's the end of the string we
832          were working on, and there's no more input. */
833       if (state == IN_QUOT || backslash) {
834         /* We were in the middle of a quoted string or backslash escape,
835            and ran out of characters; that's an error.  */
836         g_free(slstr);
837         clear_string_list(sl);
838         return NULL;
839       }
840       slstr[j] = '\0';
841       sl = g_list_append(sl, slstr);
842       break;
843     }
844     if (cur_c == '"' && ! backslash) {
845       switch (state) {
846         case PRE_STRING:
847           /* We hadn't yet started processing a string; this starts the
848              string, and we're now quoting.  */
849           state = IN_QUOT;
850           break;
851         case IN_QUOT:
852           /* We're in the middle of a quoted string, and we saw a quotation
853              mark; we're no longer quoting.   */
854           state = NOT_IN_QUOT;
855           break;
856         case NOT_IN_QUOT:
857           /* We're working on a string, but haven't seen a quote; we're
858              now quoting.  */
859           state = IN_QUOT;
860           break;
861         default:
862           break;
863       }
864     } else if (cur_c == '\\' && ! backslash) {
865       /* We saw a backslash, and the previous character wasn't a
866          backslash; escape the next character.
867
868          This also means we've started a new string. */
869       backslash = TRUE;
870       if (state == PRE_STRING)
871         state = NOT_IN_QUOT;
872     } else if (cur_c == ',' && state != IN_QUOT && ! backslash) {
873       /* We saw a comma, and we're not in the middle of a quoted string
874          and it wasn't preceded by a backslash; it's the end of
875          the string we were working on...  */
876       slstr[j] = '\0';
877       sl = g_list_append(sl, slstr);
878
879       /* ...and the beginning of a new string.  */
880       state = PRE_STRING;
881       slstr = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
882       j = 0;
883     } else if (!isspace(cur_c) || state != PRE_STRING) {
884       /* Either this isn't a white-space character, or we've started a
885          string (i.e., already seen a non-white-space character for that
886          string and put it into the string).
887
888          The character is to be put into the string; do so if there's
889          room.  */
890       if (j < COL_MAX_LEN) {
891         slstr[j] = cur_c;
892         j++;
893       }
894
895       /* If it was backslash-escaped, we're done with the backslash escape.  */
896       backslash = FALSE;
897     }
898     i++;
899   }
900   return(sl);
901 }
902
903 #define MAX_FMT_PREF_LEN      1024
904 #define MAX_FMT_PREF_LINE_LEN   60
905 static gchar *
906 put_string_list(GList *sl)
907 {
908   static gchar  pref_str[MAX_FMT_PREF_LEN] = "";
909   GList        *clp = g_list_first(sl);
910   gchar        *str;
911   int           cur_pos = 0, cur_len = 0;
912   gchar        *quoted_str;
913   int           str_len;
914   gchar        *strp, *quoted_strp, c;
915   int           fmt_len;
916
917   while (clp) {
918     str = clp->data;
919
920     /* Allocate a buffer big enough to hold the entire string, with each
921        character quoted (that's the worst case).  */
922     str_len = strlen(str);
923     quoted_str = g_malloc(str_len*2 + 1);
924
925     /* Now quote any " or \ characters in it. */
926     strp = str;
927     quoted_strp = quoted_str;
928     while ((c = *strp++) != '\0') {
929       if (c == '"' || c == '\\') {
930         /* It has to be backslash-quoted.  */
931         *quoted_strp++ = '\\';
932       }
933       *quoted_strp++ = c;
934     }
935     *quoted_strp = '\0';
936
937     fmt_len = strlen(quoted_str) + 4;
938     if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) {
939       if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) {
940         /* Wrap the line.  */
941         cur_len--;
942         cur_pos = 0;
943         pref_str[cur_len] = '\n'; cur_len++;
944         pref_str[cur_len] = '\t'; cur_len++;
945       }
946       g_snprintf(&pref_str[cur_len], MAX_FMT_PREF_LEN - cur_len, "\"%s\", ", quoted_str);
947       cur_pos += fmt_len;
948       cur_len += fmt_len;
949     }
950     g_free(quoted_str);
951     clp = clp->next;
952   }
953
954   /* If the string is at least two characters long, the last two characters
955      are ", ", and should be discarded, as there are no more items in the
956      string.  */
957   if (cur_len >= 2)
958     pref_str[cur_len - 2] = '\0';
959
960   return(pref_str);
961 }
962
963 static void
964 clear_string_list(GList *sl)
965 {
966   GList *l = sl;
967
968   while (l) {
969     g_free(l->data);
970     l = g_list_remove_link(l, l);
971   }
972 }
973
974 /*
975  * Takes a string, a pointer to an array of "enum_val_t"s, and a default gint
976  * value.
977  * The array must be terminated by an entry with a null "name" string.
978  *
979  * If the string matches a "name" string in an entry, the value from that
980  * entry is returned.
981  *
982  * Otherwise, if a string matches a "desctiption" string in an entry, the
983  * value from that entry is returned; we do that for backwards compatibility,
984  * as we used to have only a "name" string that was used both for command-line
985  * and configuration-file values and in the GUI (which meant either that
986  * the GUI had what might be somewhat cryptic values to select from or that
987  * the "-o" flag took long strings, often with spaces in them).
988  *
989  * Otherwise, the default value that was passed as the third argument is
990  * returned.
991  */
992 gint
993 find_val_for_string(const char *needle, const enum_val_t *haystack,
994     gint default_value)
995 {
996         int i;
997
998         for (i = 0; haystack[i].name != NULL; i++) {
999                 if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) {
1000                         return haystack[i].value;
1001                 }
1002         }
1003         for (i = 0; haystack[i].name != NULL; i++) {
1004                 if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) {
1005                         return haystack[i].value;
1006                 }
1007         }
1008         return default_value;
1009 }
1010
1011 /* Takes an string and a pointer to an array of strings, and a default int value.
1012  * The array must be terminated by a NULL string. If the string is found in the array
1013  * of strings, the index of that string in the array is returned. Otherwise, the
1014  * default value that was passed as the third argument is returned.
1015  */
1016 static int
1017 find_index_from_string_array(char *needle, const char **haystack, int default_value)
1018 {
1019         int i = 0;
1020
1021         while (haystack[i] != NULL) {
1022                 if (strcmp(needle, haystack[i]) == 0) {
1023                         return i;
1024                 }
1025                 i++;
1026         }
1027         return default_value;
1028 }
1029
1030 /* Preferences file format:
1031  * - Configuration directives start at the beginning of the line, and
1032  *   are terminated with a colon.
1033  * - Directives can be continued on the next line by preceding them with
1034  *   whitespace.
1035  *
1036  * Example:
1037
1038 # This is a comment line
1039 print.command: lpr
1040 print.file: /a/very/long/path/
1041         to/wireshark-out.ps
1042  *
1043  */
1044
1045 #define DEF_NUM_COLS    6
1046
1047 /* Initialize preferences to wired-in default values.
1048  * They may be overridden by the global preferences file or the
1049  *  user's preferences file.
1050  */
1051 static void
1052 init_prefs(void) {
1053   int         i;
1054   fmt_data    *cfmt;
1055   const gchar *col_fmt[] = {"No.",      "%m", "Time",        "%t",
1056                            "Source",   "%s", "Destination", "%d",
1057                            "Protocol", "%p", "Info",        "%i"};
1058
1059   if (prefs_initialized)
1060     return;
1061
1062   uat_load_all();
1063
1064   prefs.pr_format  = PR_FMT_TEXT;
1065   prefs.pr_dest    = PR_DEST_CMD;
1066   prefs.pr_file    = g_strdup("wireshark.out");
1067   prefs.pr_cmd     = g_strdup("lpr");
1068   prefs.col_list = NULL;
1069   for (i = 0; i < DEF_NUM_COLS; i++) {
1070     cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
1071     cfmt->title = g_strdup(col_fmt[i * 2]);
1072     cfmt->fmt   = g_strdup(col_fmt[(i * 2) + 1]);
1073     cfmt->custom_field = NULL;
1074     prefs.col_list = g_list_append(prefs.col_list, cfmt);
1075   }
1076   prefs.num_cols  = DEF_NUM_COLS;
1077   prefs.st_client_fg.pixel =     0;
1078   prefs.st_client_fg.red   = 32767;
1079   prefs.st_client_fg.green =     0;
1080   prefs.st_client_fg.blue  =     0;
1081   prefs.st_client_bg.pixel =     0;
1082   prefs.st_client_bg.red   = 64507;
1083   prefs.st_client_bg.green = 60909;
1084   prefs.st_client_bg.blue  = 60909;
1085   prefs.st_server_fg.pixel =     0;
1086   prefs.st_server_fg.red   =     0;
1087   prefs.st_server_fg.green =     0;
1088   prefs.st_server_fg.blue  = 32767;
1089   prefs.st_server_bg.pixel =     0;
1090   prefs.st_server_bg.red   = 60909;
1091   prefs.st_server_bg.green = 60909;
1092   prefs.st_server_bg.blue  = 64507;
1093   prefs.gui_scrollbar_on_right = TRUE;
1094   prefs.gui_plist_sel_browse = FALSE;
1095   prefs.gui_ptree_sel_browse = FALSE;
1096   prefs.gui_altern_colors = FALSE;
1097   prefs.gui_ptree_line_style = 0;
1098   prefs.gui_ptree_expander_style = 1;
1099   prefs.gui_hex_dump_highlight_style = 1;
1100   prefs.filter_toolbar_show_in_statusbar = FALSE;
1101   prefs.gui_toolbar_main_style = TB_STYLE_ICONS;
1102 #ifdef _WIN32
1103   prefs.gui_font_name = g_strdup("Lucida Console 10");
1104 #else
1105   /*
1106    * XXX - for now, we make the initial font name a pattern that matches
1107    * only ISO 8859/1 fonts, so that we don't match 2-byte fonts such
1108    * as ISO 10646 fonts.
1109    *
1110    * Users in locales using other one-byte fonts will have to choose
1111    * a different font from the preferences dialog - or put the font
1112    * selection in the global preferences file to make that font the
1113    * default for all users who don't explicitly specify a different
1114    * font.
1115    *
1116    * Making this a font set rather than a font has two problems:
1117    *
1118    *    1) as far as I know, you can't select font sets with the
1119    *       font selection dialog;
1120    *
1121    *  2) if you use a font set, the text to be drawn must be a
1122    *       multi-byte string in the appropriate locale, but
1123    *       Wireshark does *NOT* guarantee that's the case - in
1124    *       the hex-dump window, each character in the text portion
1125    *       of the display must be a *single* byte, and in the
1126    *       packet-list and protocol-tree windows, text extracted
1127    *       from the packet is not necessarily in the right format.
1128    *
1129    * "Doing this right" may, for the packet-list and protocol-tree
1130    * windows, require that dissectors know what the locale is
1131    * *AND* know what locale and text representation is used in
1132    * the packets they're dissecting, and may be impossible in
1133    * the hex-dump window (except by punting and displaying only
1134    * ASCII characters).
1135    *
1136    * GTK+ 2.0 may simplify part of the problem, as it will, as I
1137    * understand it, use UTF-8-encoded Unicode as its internal
1138    * character set; however, we'd still have to know whatever
1139    * character set and encoding is used in the packet (which
1140    * may differ for different protocols, e.g. SMB might use
1141    * PC code pages for some strings and Unicode for others, whilst
1142    * NFS might use some UNIX character set encoding, e.g. ISO 8859/x,
1143    * or one of the EUC character sets for Asian languages, or one
1144    * of the other multi-byte character sets, or UTF-8, or...).
1145    *
1146    * I.e., as far as I can tell, "internationalizing" the packet-list,
1147    * protocol-tree, and hex-dump windows involves a lot more than, say,
1148    * just using font sets rather than fonts.
1149    */
1150   /* XXX - the above comment was about the GTK1 font stuff, just remove this comment now */
1151   /* XXX- is this the correct default font name for GTK2 none win32? */
1152   prefs.gui_font_name = g_strdup("Monospace 10");
1153 #endif
1154   prefs.gui_marked_fg.pixel        =     65535;
1155   prefs.gui_marked_fg.red          =     65535;
1156   prefs.gui_marked_fg.green        =     65535;
1157   prefs.gui_marked_fg.blue         =     65535;
1158   prefs.gui_marked_bg.pixel        =         0;
1159   prefs.gui_marked_bg.red          =         0;
1160   prefs.gui_marked_bg.green        =         0;
1161   prefs.gui_marked_bg.blue         =         0;
1162   prefs.gui_colorized_fg           = g_strdup("000000,000000,000000,000000,000000,000000,000000,000000,000000,000000");
1163   prefs.gui_colorized_bg           = g_strdup("ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0");
1164   prefs.gui_geometry_save_position =         0;
1165   prefs.gui_geometry_save_size     =         1;
1166   prefs.gui_geometry_save_maximized=         1;
1167   prefs.gui_console_open           = console_open_never;
1168   prefs.gui_fileopen_style         = FO_STYLE_LAST_OPENED;
1169   prefs.gui_recent_files_count_max = 10;
1170   prefs.gui_fileopen_dir           = g_strdup(get_persdatafile_dir());
1171   prefs.gui_fileopen_preview       = 3;
1172   prefs.gui_ask_unsaved            = TRUE;
1173   prefs.gui_find_wrap              = TRUE;
1174   prefs.gui_use_pref_save          = FALSE;
1175   prefs.gui_webbrowser             = g_strdup(HTML_VIEWER " %s");
1176   prefs.gui_window_title           = g_strdup("");
1177   prefs.gui_layout_type            = layout_type_5;
1178   prefs.gui_layout_content_1       = layout_pane_content_plist;
1179   prefs.gui_layout_content_2       = layout_pane_content_pdetails;
1180   prefs.gui_layout_content_3       = layout_pane_content_pbytes;
1181   prefs.console_log_level          =
1182       G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR;
1183
1184 /* set the default values for the capture dialog box */
1185   prefs.capture_device           = NULL;
1186   prefs.capture_devices_descr    = NULL;
1187   prefs.capture_devices_hide     = NULL;
1188   prefs.capture_prom_mode        = TRUE;
1189   prefs.capture_real_time        = TRUE;
1190   prefs.capture_auto_scroll      = TRUE;
1191   prefs.capture_show_info        = FALSE;
1192
1193 /* set the default values for the name resolution dialog box */
1194   prefs.name_resolve             = RESOLV_ALL ^ RESOLV_NETWORK;
1195   prefs.name_resolve_concurrency = 500;
1196
1197 /* set the default values for the rtp player dialog box */
1198   prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE;
1199
1200   prefs_initialized = TRUE;
1201 }
1202
1203 /* Reset preferences */
1204 void
1205 prefs_reset(void)
1206 {
1207   prefs_initialized = FALSE;
1208   if (prefs.pr_file)
1209     g_free(prefs.pr_file);
1210   if (prefs.pr_cmd)
1211     g_free(prefs.pr_cmd);
1212   free_col_info(&prefs);
1213   if (prefs.gui_font_name)
1214     g_free(prefs.gui_font_name);
1215   if (prefs.gui_colorized_fg)
1216     g_free(prefs.gui_colorized_fg);
1217   if (prefs.gui_colorized_bg)
1218     g_free(prefs.gui_colorized_bg);
1219   if (prefs.gui_fileopen_dir)
1220     g_free(prefs.gui_fileopen_dir);
1221   if (prefs.gui_webbrowser)
1222     g_free(prefs.gui_webbrowser);
1223   if (prefs.gui_window_title)
1224     g_free(prefs.gui_window_title);
1225   if (prefs.capture_device)
1226     g_free(prefs.capture_device);
1227   if (prefs.capture_devices_descr)
1228     g_free(prefs.capture_devices_descr);
1229   if (prefs.capture_devices_hide)
1230     g_free(prefs.capture_devices_hide);
1231
1232   uat_unload_all();
1233   init_prefs();
1234 }
1235
1236 /* Read the preferences file, fill in "prefs", and return a pointer to it.
1237
1238    If we got an error (other than "it doesn't exist") trying to read
1239    the global preferences file, stuff the errno into "*gpf_errno_return"
1240    and a pointer to the path of the file into "*gpf_path_return", and
1241    return NULL.
1242
1243    If we got an error (other than "it doesn't exist") trying to read
1244    the user's preferences file, stuff the errno into "*pf_errno_return"
1245    and a pointer to the path of the file into "*pf_path_return", and
1246    return NULL. */
1247 e_prefs *
1248 read_prefs(int *gpf_errno_return, int *gpf_read_errno_return,
1249            char **gpf_path_return, int *pf_errno_return,
1250            int *pf_read_errno_return, char **pf_path_return)
1251 {
1252   int         err;
1253   char        *pf_path;
1254   FILE        *pf;
1255
1256   init_prefs();
1257
1258   /*
1259    * If we don't already have the pathname of the global preferences
1260    * file, construct it.  Then, in either case, try to open the file.
1261    */
1262   if (gpf_path == NULL) {
1263     /*
1264      * We don't have the path; try the new path first, and, if that
1265      * file doesn't exist, try the old path.
1266      */
1267     gpf_path = get_datafile_path(PF_NAME);
1268     if ((pf = eth_fopen(gpf_path, "r")) == NULL && errno == ENOENT) {
1269       /*
1270        * It doesn't exist by the new name; try the old name.
1271        */
1272       g_free(gpf_path);
1273       gpf_path = get_datafile_path(OLD_GPF_NAME);
1274       pf = eth_fopen(gpf_path, "r");
1275     }
1276   } else {
1277     /*
1278      * We have the path; try it.
1279      */
1280     pf = eth_fopen(gpf_path, "r");
1281   }
1282
1283   /*
1284    * If we were able to open the file, read it.
1285    * XXX - if it failed for a reason other than "it doesn't exist",
1286    * report the error.
1287    */
1288   *gpf_path_return = NULL;
1289   if (pf != NULL) {
1290     /*
1291      * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
1292      * seen.
1293      */
1294     mgcp_tcp_port_count = 0;
1295     mgcp_udp_port_count = 0;
1296
1297     /* We succeeded in opening it; read it. */
1298     err = read_prefs_file(gpf_path, pf, set_pref, NULL);
1299     if (err != 0) {
1300       /* We had an error reading the file; return the errno and the
1301          pathname, so our caller can report the error. */
1302       *gpf_errno_return = 0;
1303       *gpf_read_errno_return = err;
1304       *gpf_path_return = gpf_path;
1305     }
1306     fclose(pf);
1307   } else {
1308     /* We failed to open it.  If we failed for some reason other than
1309        "it doesn't exist", return the errno and the pathname, so our
1310        caller can report the error. */
1311     if (errno != ENOENT) {
1312       *gpf_errno_return = errno;
1313       *gpf_read_errno_return = 0;
1314       *gpf_path_return = gpf_path;
1315     }
1316   }
1317
1318   /* Construct the pathname of the user's preferences file. */
1319   pf_path = get_persconffile_path(PF_NAME, TRUE, FALSE);
1320
1321   /* Read the user's preferences file, if it exists. */
1322   *pf_path_return = NULL;
1323   if ((pf = eth_fopen(pf_path, "r")) != NULL) {
1324     /*
1325      * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
1326      * seen.
1327      */
1328     mgcp_tcp_port_count = 0;
1329     mgcp_udp_port_count = 0;
1330
1331     /* We succeeded in opening it; read it. */
1332     err = read_prefs_file(pf_path, pf, set_pref, NULL);
1333     if (err != 0) {
1334       /* We had an error reading the file; return the errno and the
1335          pathname, so our caller can report the error. */
1336       *pf_errno_return = 0;
1337       *pf_read_errno_return = err;
1338       *pf_path_return = pf_path;
1339     } else
1340       g_free(pf_path);
1341     fclose(pf);
1342   } else {
1343     /* We failed to open it.  If we failed for some reason other than
1344        "it doesn't exist", return the errno and the pathname, so our
1345        caller can report the error. */
1346     if (errno != ENOENT) {
1347       *pf_errno_return = errno;
1348       *pf_read_errno_return = 0;
1349       *pf_path_return = pf_path;
1350     } else
1351       g_free(pf_path);
1352   }
1353
1354   return &prefs;
1355 }
1356
1357 /* read the preferences file (or similiar) and call the callback
1358  * function to set each key/value pair found */
1359 int
1360 read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fct, void *private_data)
1361 {
1362   enum { START, IN_VAR, PRE_VAL, IN_VAL, IN_SKIP };
1363   int       got_c, state = START;
1364   GString  *cur_val;
1365   GString  *cur_var;
1366   gboolean  got_val = FALSE;
1367   gint      fline = 1, pline = 1;
1368   gchar     hint[] = "(applying your preferences once should remove this warning)";
1369
1370   cur_val = g_string_new("");
1371   cur_var = g_string_new("");
1372
1373   while ((got_c = getc(pf)) != EOF) {
1374     if (got_c == '\n') {
1375       state = START;
1376       fline++;
1377       continue;
1378     }
1379
1380     switch (state) {
1381       case START:
1382         if (isalnum(got_c)) {
1383           if (cur_var->len > 0) {
1384             if (got_val) {
1385               switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data)) {
1386
1387               case PREFS_SET_OK:
1388                 break;
1389
1390               case PREFS_SET_SYNTAX_ERR:
1391                 g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint);
1392                 break;
1393
1394               case PREFS_SET_NO_SUCH_PREF:
1395                 g_warning ("%s line %d: No such preference \"%s\" %s", pf_path,
1396                                 pline, cur_var->str, hint);
1397                 break;
1398
1399               case PREFS_SET_OBSOLETE:
1400                 /* We silently ignore attempts to set these; it's
1401                    probably not the user's fault that it's in there -
1402                    they may have saved preferences with a release that
1403                    supported them. */
1404                 break;
1405               }
1406             } else {
1407               g_warning ("%s line %d: Incomplete preference %s", pf_path, pline, hint);
1408             }
1409           }
1410           state      = IN_VAR;
1411           got_val    = FALSE;
1412           g_string_truncate(cur_var, 0);
1413           g_string_append_c(cur_var, (gchar) got_c);
1414           pline = fline;
1415         } else if (isspace(got_c) && cur_var->len > 0 && got_val) {
1416           state = PRE_VAL;
1417         } else if (got_c == '#') {
1418           state = IN_SKIP;
1419         } else {
1420           g_warning ("%s line %d: Malformed line %s", pf_path, fline, hint);
1421         }
1422         break;
1423       case IN_VAR:
1424         if (got_c != ':') {
1425           g_string_append_c(cur_var, (gchar) got_c);
1426         } else {
1427           state   = PRE_VAL;
1428           g_string_truncate(cur_val, 0);
1429           got_val = TRUE;
1430         }
1431         break;
1432       case PRE_VAL:
1433         if (!isspace(got_c)) {
1434           state = IN_VAL;
1435           g_string_append_c(cur_val, (gchar) got_c);
1436         }
1437         break;
1438       case IN_VAL:
1439         g_string_append_c(cur_val, (gchar) got_c);
1440         break;
1441     }
1442   }
1443   if (cur_var->len > 0) {
1444     if (got_val) {
1445       switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data)) {
1446
1447       case PREFS_SET_OK:
1448         break;
1449
1450       case PREFS_SET_SYNTAX_ERR:
1451         g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint);
1452         break;
1453
1454       case PREFS_SET_NO_SUCH_PREF:
1455         g_warning ("%s line %d: No such preference \"%s\" %s", pf_path,
1456                         pline, cur_var->str, hint);
1457         break;
1458
1459       case PREFS_SET_OBSOLETE:
1460         /* We silently ignore attempts to set these; it's probably not
1461            the user's fault that it's in there - they may have saved
1462            preferences with a release that supported it. */
1463         break;
1464       }
1465     } else {
1466       g_warning ("%s line %d: Incomplete preference %s", pf_path, pline, hint);
1467     }
1468   }
1469
1470   g_string_free(cur_val, TRUE);
1471   g_string_free(cur_var, TRUE);
1472
1473   if (ferror(pf))
1474     return errno;
1475   else
1476     return 0;
1477 }
1478
1479 /*
1480  * If we were handed a preference starting with "uat:", try to turn it into
1481  * a valid uat entry.
1482  */
1483 static gboolean
1484 prefs_set_uat_pref(char *uat_entry) {
1485         gchar *p, *colonp;
1486         uat_t *uat;
1487         gchar *err;
1488
1489         colonp = strchr(uat_entry, ':');
1490         if (colonp == NULL)
1491                 return FALSE;
1492
1493         p = colonp;
1494         *p++ = '\0';
1495
1496         /*
1497          * Skip over any white space (there probably won't be any, but
1498          * as we allow it in the preferences file, we might as well
1499          * allow it here).
1500          */
1501         while (isspace((guchar)*p))
1502                 p++;
1503         if (*p == '\0') {
1504                 /*
1505                  * Put the colon back, so if our caller uses, in an
1506                  * error message, the string they passed us, the message
1507                  * looks correct.
1508                  */
1509                 *colonp = ':';
1510                 return FALSE;
1511         }
1512
1513         uat = uat_find(uat_entry);
1514         *colonp = ':';
1515         if (uat == NULL) {
1516                 return FALSE;
1517         }
1518
1519         if (uat_load_str(uat, p, &err)) {
1520                 return TRUE;
1521         }
1522         return FALSE;
1523 }
1524
1525 /*
1526  * Given a string of the form "<pref name>:<pref value>", as might appear
1527  * as an argument to a "-o" option, parse it and set the preference in
1528  * question.  Return an indication of whether it succeeded or failed
1529  * in some fashion.
1530  */
1531 prefs_set_pref_e
1532 prefs_set_pref(char *prefarg)
1533 {
1534         gchar *p, *colonp;
1535         prefs_set_pref_e ret;
1536
1537         /*
1538          * Set the counters of "mgcp.{tcp,udp}.port" entries we've
1539          * seen to values that keep us from trying to interpret tham
1540          * as "mgcp.{tcp,udp}.gateway_port" or "mgcp.{tcp,udp}.callagent_port",
1541          * as, from the command line, we have no way of guessing which
1542          * the user had in mind.
1543          */
1544         mgcp_tcp_port_count = -1;
1545         mgcp_udp_port_count = -1;
1546
1547         colonp = strchr(prefarg, ':');
1548         if (colonp == NULL)
1549                 return PREFS_SET_SYNTAX_ERR;
1550
1551         p = colonp;
1552         *p++ = '\0';
1553
1554         /*
1555          * Skip over any white space (there probably won't be any, but
1556          * as we allow it in the preferences file, we might as well
1557          * allow it here).
1558          */
1559         while (isspace((guchar)*p))
1560                 p++;
1561         if (*p == '\0') {
1562                 /*
1563                  * Put the colon back, so if our caller uses, in an
1564                  * error message, the string they passed us, the message
1565                  * looks correct.
1566                  */
1567                 *colonp = ':';
1568                 return PREFS_SET_SYNTAX_ERR;
1569         }
1570         if (strcmp(prefarg, "uat")) {
1571                 ret = set_pref(prefarg, p, NULL);
1572         } else {
1573                 ret = prefs_set_uat_pref(p) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR;
1574         }
1575         *colonp = ':';  /* put the colon back */
1576         return ret;
1577 }
1578
1579 /*
1580  * Returns TRUE if the given device is hidden
1581  */
1582 gboolean
1583 prefs_is_capture_device_hidden(const char *name)
1584 {
1585         gchar *tok, *devices;
1586         size_t len;
1587
1588         if (prefs.capture_devices_hide && name) {
1589                 devices = g_strdup (prefs.capture_devices_hide);
1590                 len = strlen (name);
1591                 for (tok = strtok (devices, ","); tok; tok = strtok(NULL, ",")) {
1592                         if (strlen (tok) == len && strcmp (name, tok) == 0) {
1593                                 g_free (devices);
1594                                 return TRUE;
1595                         }
1596                 }
1597                 g_free (devices);
1598         }
1599
1600         return FALSE;
1601 }
1602
1603 #define PRS_PRINT_FMT                    "print.format"
1604 #define PRS_PRINT_DEST                   "print.destination"
1605 #define PRS_PRINT_FILE                   "print.file"
1606 #define PRS_PRINT_CMD                    "print.command"
1607 #define PRS_COL_FMT                      "column.format"
1608 #define PRS_STREAM_CL_FG                 "stream.client.fg"
1609 #define PRS_STREAM_CL_BG                 "stream.client.bg"
1610 #define PRS_STREAM_SR_FG                 "stream.server.fg"
1611 #define PRS_STREAM_SR_BG                 "stream.server.bg"
1612 #define PRS_GUI_SCROLLBAR_ON_RIGHT       "gui.scrollbar_on_right"
1613 #define PRS_GUI_PLIST_SEL_BROWSE         "gui.packet_list_sel_browse"
1614 #define PRS_GUI_PTREE_SEL_BROWSE         "gui.protocol_tree_sel_browse"
1615 #define PRS_GUI_ALTERN_COLORS            "gui.tree_view_altern_colors"
1616 #define PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR "gui.filter_toolbar_show_in_statusbar"
1617 #define PRS_GUI_PTREE_LINE_STYLE         "gui.protocol_tree_line_style"
1618 #define PRS_GUI_PTREE_EXPANDER_STYLE     "gui.protocol_tree_expander_style"
1619 #define PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE "gui.hex_dump_highlight_style"
1620 #define PRS_GUI_FONT_NAME_1              "gui.font_name"
1621 #define PRS_GUI_FONT_NAME_2              "gui.gtk2.font_name"
1622 #define PRS_GUI_MARKED_FG                "gui.marked_frame.fg"
1623 #define PRS_GUI_MARKED_BG                "gui.marked_frame.bg"
1624 #define PRS_GUI_COLORIZED_FG             "gui.colorized_frame.fg"
1625 #define PRS_GUI_COLORIZED_BG             "gui.colorized_frame.bg"
1626 #define PRS_GUI_CONSOLE_OPEN             "gui.console_open"
1627 #define PRS_GUI_FILEOPEN_STYLE           "gui.fileopen.style"
1628 #define PRS_GUI_RECENT_COUNT_MAX         "gui.recent_files_count.max"
1629 #define PRS_GUI_FILEOPEN_DIR             "gui.fileopen.dir"
1630 #define PRS_GUI_FILEOPEN_REMEMBERED_DIR  "gui.fileopen.remembered_dir"
1631 #define PRS_GUI_FILEOPEN_PREVIEW         "gui.fileopen.preview"
1632 #define PRS_GUI_ASK_UNSAVED              "gui.ask_unsaved"
1633 #define PRS_GUI_FIND_WRAP                "gui.find_wrap"
1634 #define PRS_GUI_USE_PREF_SAVE            "gui.use_pref_save"
1635 #define PRS_GUI_GEOMETRY_SAVE_POSITION   "gui.geometry.save.position"
1636 #define PRS_GUI_GEOMETRY_SAVE_SIZE       "gui.geometry.save.size"
1637 #define PRS_GUI_GEOMETRY_SAVE_MAXIMIZED  "gui.geometry.save.maximized"
1638 #define PRS_GUI_GEOMETRY_MAIN_X          "gui.geometry.main.x"
1639 #define PRS_GUI_GEOMETRY_MAIN_Y          "gui.geometry.main.y"
1640 #define PRS_GUI_GEOMETRY_MAIN_WIDTH      "gui.geometry.main.width"
1641 #define PRS_GUI_GEOMETRY_MAIN_HEIGHT     "gui.geometry.main.height"
1642 #define PRS_GUI_TOOLBAR_MAIN_SHOW        "gui.toolbar_main_show"
1643 #define PRS_GUI_TOOLBAR_MAIN_STYLE       "gui.toolbar_main_style"
1644 #define PRS_GUI_WEBBROWSER               "gui.webbrowser"
1645 #define PRS_GUI_WINDOW_TITLE             "gui.window_title"
1646 #define PRS_GUI_LAYOUT_TYPE              "gui.layout_type"
1647 #define PRS_GUI_LAYOUT_CONTENT_1         "gui.layout_content_1"
1648 #define PRS_GUI_LAYOUT_CONTENT_2         "gui.layout_content_2"
1649 #define PRS_GUI_LAYOUT_CONTENT_3         "gui.layout_content_3"
1650 #define PRS_CONSOLE_LOG_LEVEL            "console.log.level"
1651
1652 /*
1653  * This applies to more than just captures, so it's not "capture.name_resolve";
1654  * "capture.name_resolve" is supported on input for backwards compatibility.
1655  *
1656  * It's not a preference for a particular part of Wireshark, it's used all
1657  * over the place, so its name doesn't have two components.
1658  */
1659 #define PRS_NAME_RESOLVE "name_resolve"
1660 #define PRS_NAME_RESOLVE_CONCURRENCY "name_resolve_concurrency"
1661 #define PRS_CAP_NAME_RESOLVE "capture.name_resolve"
1662
1663 /*  values for the capture dialog box */
1664 #define PRS_CAP_DEVICE        "capture.device"
1665 #define PRS_CAP_DEVICES_DESCR "capture.devices_descr"
1666 #define PRS_CAP_DEVICES_HIDE  "capture.devices_hide"
1667 #define PRS_CAP_PROM_MODE     "capture.prom_mode"
1668 #define PRS_CAP_REAL_TIME     "capture.real_time_update"
1669 #define PRS_CAP_AUTO_SCROLL   "capture.auto_scroll"
1670 #define PRS_CAP_SHOW_INFO     "capture.show_info"
1671
1672 #define RED_COMPONENT(x)   (guint16) (((((x) >> 16) & 0xff) * 65535 / 255))
1673 #define GREEN_COMPONENT(x) (guint16) (((((x) >>  8) & 0xff) * 65535 / 255))
1674 #define BLUE_COMPONENT(x)  (guint16) ( (((x)        & 0xff) * 65535 / 255))
1675
1676 /*  values for the rtp player preferences dialog box */
1677 #define PRS_RTP_PLAYER_MAX_VISIBLE        "rtp_player.max_visible"
1678
1679 static const gchar *pr_formats[] = { "text", "postscript" };
1680 static const gchar *pr_dests[]   = { "command", "file" };
1681
1682 typedef struct {
1683   char    letter;
1684   guint32 value;
1685 } name_resolve_opt_t;
1686
1687 static name_resolve_opt_t name_resolve_opt[] = {
1688   { 'm', RESOLV_MAC },
1689   { 'n', RESOLV_NETWORK },
1690   { 't', RESOLV_TRANSPORT },
1691   { 'C', RESOLV_CONCURRENT },
1692 };
1693
1694 #define N_NAME_RESOLVE_OPT      (sizeof name_resolve_opt / sizeof name_resolve_opt[0])
1695
1696 static const char *
1697 name_resolve_to_string(guint32 name_resolve)
1698 {
1699   static char string[N_NAME_RESOLVE_OPT+1];
1700   char *p;
1701   unsigned int i;
1702   gboolean all_opts_set = TRUE;
1703
1704   if (name_resolve == RESOLV_NONE)
1705     return "FALSE";
1706   p = &string[0];
1707   for (i = 0; i < N_NAME_RESOLVE_OPT; i++) {
1708     if (name_resolve & name_resolve_opt[i].value)
1709       *p++ =  name_resolve_opt[i].letter;
1710     else
1711       all_opts_set = FALSE;
1712   }
1713   *p = '\0';
1714   if (all_opts_set)
1715     return "TRUE";
1716   return string;
1717 }
1718
1719 char
1720 string_to_name_resolve(char *string, guint32 *name_resolve)
1721 {
1722   char c;
1723   unsigned int i;
1724
1725   *name_resolve = 0;
1726   while ((c = *string++) != '\0') {
1727     for (i = 0; i < N_NAME_RESOLVE_OPT; i++) {
1728       if (c == name_resolve_opt[i].letter) {
1729         *name_resolve |= name_resolve_opt[i].value;
1730         break;
1731       }
1732     }
1733     if (i == N_NAME_RESOLVE_OPT) {
1734       /*
1735        * Unrecognized letter.
1736        */
1737       return c;
1738     }
1739   }
1740   return '\0';
1741 }
1742
1743 static prefs_set_pref_e
1744 set_pref(gchar *pref_name, gchar *value, void *private_data _U_)
1745 {
1746   GList    *col_l, *col_l_elt;
1747   gint      llen;
1748   fmt_data *cfmt;
1749   unsigned long int cval;
1750   guint    uval;
1751   gboolean bval;
1752   gint     enum_val;
1753   char     *p;
1754   gchar    *dotp, *last_dotp;
1755   module_t *module;
1756   pref_t   *pref;
1757   gboolean had_a_dot;
1758   const gchar *cust_format = col_format_to_string(COL_CUSTOM);
1759   int cust_format_len = strlen(cust_format);
1760
1761   if (strcmp(pref_name, PRS_PRINT_FMT) == 0) {
1762     if (strcmp(value, pr_formats[PR_FMT_TEXT]) == 0) {
1763       prefs.pr_format = PR_FMT_TEXT;
1764     } else if (strcmp(value, pr_formats[PR_FMT_PS]) == 0) {
1765       prefs.pr_format = PR_FMT_PS;
1766     } else {
1767       return PREFS_SET_SYNTAX_ERR;
1768     }
1769   } else if (strcmp(pref_name, PRS_PRINT_DEST) == 0) {
1770     if (strcmp(value, pr_dests[PR_DEST_CMD]) == 0) {
1771       prefs.pr_dest = PR_DEST_CMD;
1772     } else if (strcmp(value, pr_dests[PR_DEST_FILE]) == 0) {
1773       prefs.pr_dest = PR_DEST_FILE;
1774     } else {
1775       return PREFS_SET_SYNTAX_ERR;
1776     }
1777   } else if (strcmp(pref_name, PRS_PRINT_FILE) == 0) {
1778     if (prefs.pr_file) g_free(prefs.pr_file);
1779     prefs.pr_file = g_strdup(value);
1780   } else if (strcmp(pref_name, PRS_PRINT_CMD) == 0) {
1781     if (prefs.pr_cmd) g_free(prefs.pr_cmd);
1782     prefs.pr_cmd = g_strdup(value);
1783   } else if (strcmp(pref_name, PRS_COL_FMT) == 0) {
1784     col_l = get_string_list(value);
1785     if (col_l == NULL)
1786       return PREFS_SET_SYNTAX_ERR;
1787     if ((g_list_length(col_l) % 2) != 0) {
1788       /* A title didn't have a matching format.  */
1789       clear_string_list(col_l);
1790       return PREFS_SET_SYNTAX_ERR;
1791     }
1792     /* Check to make sure all column formats are valid.  */
1793     col_l_elt = g_list_first(col_l);
1794     while(col_l_elt) {
1795       /* Make sure the title isn't empty.  */
1796       if (strcmp(col_l_elt->data, "") == 0) {
1797         /* It is.  */
1798         clear_string_list(col_l);
1799         return PREFS_SET_SYNTAX_ERR;
1800       }
1801
1802       /* Go past the title.  */
1803       col_l_elt = col_l_elt->next;
1804
1805       /* Check the format.  */
1806       if (strncmp(col_l_elt->data, cust_format, cust_format_len) != 0) {
1807         if (get_column_format_from_str(col_l_elt->data) == -1) {
1808           /* It's not a valid column format.  */
1809           clear_string_list(col_l);
1810           return PREFS_SET_SYNTAX_ERR;
1811         }
1812       }
1813
1814       /* Go past the format.  */
1815       col_l_elt = col_l_elt->next;
1816     }
1817     free_col_info(&prefs);
1818     prefs.col_list = NULL;
1819     llen             = g_list_length(col_l);
1820     prefs.num_cols   = llen / 2;
1821     col_l_elt = g_list_first(col_l);
1822     while(col_l_elt) {
1823       cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
1824       cfmt->title    = g_strdup(col_l_elt->data);
1825       col_l_elt      = col_l_elt->next;
1826       if (strncmp(col_l_elt->data, cust_format, cust_format_len) == 0) {
1827         gchar *fmt     = g_strdup(col_l_elt->data);
1828         cfmt->fmt      = g_strdup(cust_format);
1829         cfmt->custom_field = g_strdup(&fmt[cust_format_len+1]);  /* add 1 for ':' */
1830         g_free (fmt);
1831       } else {
1832         cfmt->fmt      = g_strdup(col_l_elt->data);
1833         cfmt->custom_field = NULL;
1834       }
1835       col_l_elt      = col_l_elt->next;
1836       prefs.col_list = g_list_append(prefs.col_list, cfmt);
1837     }
1838     clear_string_list(col_l);
1839   } else if (strcmp(pref_name, PRS_STREAM_CL_FG) == 0) {
1840     cval = strtoul(value, NULL, 16);
1841     prefs.st_client_fg.pixel = 0;
1842     prefs.st_client_fg.red   = RED_COMPONENT(cval);
1843     prefs.st_client_fg.green = GREEN_COMPONENT(cval);
1844     prefs.st_client_fg.blue  = BLUE_COMPONENT(cval);
1845   } else if (strcmp(pref_name, PRS_STREAM_CL_BG) == 0) {
1846     cval = strtoul(value, NULL, 16);
1847     prefs.st_client_bg.pixel = 0;
1848     prefs.st_client_bg.red   = RED_COMPONENT(cval);
1849     prefs.st_client_bg.green = GREEN_COMPONENT(cval);
1850     prefs.st_client_bg.blue  = BLUE_COMPONENT(cval);
1851   } else if (strcmp(pref_name, PRS_STREAM_SR_FG) == 0) {
1852     cval = strtoul(value, NULL, 16);
1853     prefs.st_server_fg.pixel = 0;
1854     prefs.st_server_fg.red   = RED_COMPONENT(cval);
1855     prefs.st_server_fg.green = GREEN_COMPONENT(cval);
1856     prefs.st_server_fg.blue  = BLUE_COMPONENT(cval);
1857   } else if (strcmp(pref_name, PRS_STREAM_SR_BG) == 0) {
1858     cval = strtoul(value, NULL, 16);
1859     prefs.st_server_bg.pixel = 0;
1860     prefs.st_server_bg.red   = RED_COMPONENT(cval);
1861     prefs.st_server_bg.green = GREEN_COMPONENT(cval);
1862     prefs.st_server_bg.blue  = BLUE_COMPONENT(cval);
1863   } else if (strcmp(pref_name, PRS_GUI_SCROLLBAR_ON_RIGHT) == 0) {
1864     if (g_ascii_strcasecmp(value, "true") == 0) {
1865             prefs.gui_scrollbar_on_right = TRUE;
1866     }
1867     else {
1868             prefs.gui_scrollbar_on_right = FALSE;
1869     }
1870   } else if (strcmp(pref_name, PRS_GUI_PLIST_SEL_BROWSE) == 0) {
1871     if (g_ascii_strcasecmp(value, "true") == 0) {
1872             prefs.gui_plist_sel_browse = TRUE;
1873     }
1874     else {
1875             prefs.gui_plist_sel_browse = FALSE;
1876     }
1877   } else if (strcmp(pref_name, PRS_GUI_PTREE_SEL_BROWSE) == 0) {
1878     if (g_ascii_strcasecmp(value, "true") == 0) {
1879             prefs.gui_ptree_sel_browse = TRUE;
1880     }
1881     else {
1882             prefs.gui_ptree_sel_browse = FALSE;
1883     }
1884   } else if (strcmp(pref_name, PRS_GUI_ALTERN_COLORS) == 0) {
1885     if (g_ascii_strcasecmp(value, "true") == 0) {
1886             prefs.gui_altern_colors = TRUE;
1887     }
1888     else {
1889             prefs.gui_altern_colors = FALSE;
1890     }
1891   } else if (strcmp(pref_name, PRS_GUI_PTREE_LINE_STYLE) == 0) {
1892     prefs.gui_ptree_line_style =
1893         find_index_from_string_array(value, gui_ptree_line_style_text, 0);
1894   } else if (strcmp(pref_name, PRS_GUI_PTREE_EXPANDER_STYLE) == 0) {
1895     prefs.gui_ptree_expander_style =
1896         find_index_from_string_array(value, gui_ptree_expander_style_text, 1);
1897   } else if (strcmp(pref_name, PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE) == 0) {
1898     prefs.gui_hex_dump_highlight_style =
1899         find_index_from_string_array(value, gui_hex_dump_highlight_style_text, 1);
1900   } else if (strcmp(pref_name, PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR) == 0) {
1901     if (g_ascii_strcasecmp(value, "true") == 0) {
1902             prefs.filter_toolbar_show_in_statusbar = TRUE;
1903     }
1904     else {
1905             prefs.filter_toolbar_show_in_statusbar = FALSE;
1906     }
1907   } else if (strcmp(pref_name, PRS_GUI_TOOLBAR_MAIN_SHOW) == 0) {
1908     /* obsoleted by recent setting */
1909   } else if (strcmp(pref_name, PRS_GUI_TOOLBAR_MAIN_STYLE) == 0) {
1910     /* see toolbar.c for details, "icons only" is default */
1911         prefs.gui_toolbar_main_style =
1912             find_index_from_string_array(value, gui_toolbar_style_text,
1913                                      TB_STYLE_ICONS);
1914   } else if (strcmp(pref_name, PRS_GUI_FONT_NAME_1) == 0) {
1915     /* GTK1 font name obsolete */
1916   } else if (strcmp(pref_name, PRS_GUI_FONT_NAME_2) == 0) {
1917     if (prefs.gui_font_name != NULL)
1918       g_free(prefs.gui_font_name);
1919     prefs.gui_font_name = g_strdup(value);
1920   } else if (strcmp(pref_name, PRS_GUI_MARKED_FG) == 0) {
1921     cval = strtoul(value, NULL, 16);
1922     prefs.gui_marked_fg.pixel = 0;
1923     prefs.gui_marked_fg.red   = RED_COMPONENT(cval);
1924     prefs.gui_marked_fg.green = GREEN_COMPONENT(cval);
1925     prefs.gui_marked_fg.blue  = BLUE_COMPONENT(cval);
1926   } else if (strcmp(pref_name, PRS_GUI_MARKED_BG) == 0) {
1927     cval = strtoul(value, NULL, 16);
1928     prefs.gui_marked_bg.pixel = 0;
1929     prefs.gui_marked_bg.red   = RED_COMPONENT(cval);
1930     prefs.gui_marked_bg.green = GREEN_COMPONENT(cval);
1931     prefs.gui_marked_bg.blue  = BLUE_COMPONENT(cval);
1932   } else if (strcmp(pref_name, PRS_GUI_COLORIZED_FG) == 0) {
1933     if (prefs.gui_colorized_fg != NULL)
1934       g_free(prefs.gui_colorized_fg);
1935     prefs.gui_colorized_fg = g_strdup(value);
1936   } else if (strcmp(pref_name, PRS_GUI_COLORIZED_BG) == 0) {
1937     if (prefs.gui_colorized_bg != NULL)
1938       g_free(prefs.gui_colorized_bg);
1939     prefs.gui_colorized_bg = g_strdup(value);
1940   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_POSITION) == 0) {
1941     if (g_ascii_strcasecmp(value, "true") == 0) {
1942             prefs.gui_geometry_save_position = TRUE;
1943     }
1944     else {
1945             prefs.gui_geometry_save_position = FALSE;
1946     }
1947   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_SIZE) == 0) {
1948     if (g_ascii_strcasecmp(value, "true") == 0) {
1949             prefs.gui_geometry_save_size = TRUE;
1950     }
1951     else {
1952             prefs.gui_geometry_save_size = FALSE;
1953     }
1954   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_MAXIMIZED) == 0) {
1955     if (g_ascii_strcasecmp(value, "true") == 0) {
1956             prefs.gui_geometry_save_maximized = TRUE;
1957     }
1958     else {
1959             prefs.gui_geometry_save_maximized = FALSE;
1960     }
1961   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_X) == 0) {         /* deprecated */
1962   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_Y) == 0) {         /* deprecated */
1963   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_WIDTH) == 0) {     /* deprecated */
1964   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {    /* deprecated */
1965   } else if (strcmp(pref_name, PRS_GUI_CONSOLE_OPEN) == 0) {
1966     prefs.gui_console_open =
1967         find_index_from_string_array(value, gui_console_open_text,
1968                                      console_open_never);
1969   } else if (strcmp(pref_name, PRS_GUI_RECENT_COUNT_MAX) == 0) {
1970     prefs.gui_recent_files_count_max = strtoul(value, NULL, 10);
1971     if (prefs.gui_recent_files_count_max == 0) {
1972       /* We really should put up a dialog box here ... */
1973       prefs.gui_recent_files_count_max = 10;
1974     }
1975   } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_STYLE) == 0) {
1976     prefs.gui_fileopen_style =
1977         find_index_from_string_array(value, gui_fileopen_style_text,
1978                                      FO_STYLE_LAST_OPENED);
1979   } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_DIR) == 0) {
1980     if (prefs.gui_fileopen_dir != NULL)
1981       g_free(prefs.gui_fileopen_dir);
1982     prefs.gui_fileopen_dir = g_strdup(value);
1983   } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_REMEMBERED_DIR) == 0) { /* deprecated */
1984   } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_PREVIEW) == 0) {
1985     prefs.gui_fileopen_preview = strtoul(value, NULL, 10);
1986   } else if (strcmp(pref_name, PRS_GUI_ASK_UNSAVED) == 0) {
1987     if (g_ascii_strcasecmp(value, "true") == 0) {
1988             prefs.gui_ask_unsaved = TRUE;
1989     }
1990     else {
1991             prefs.gui_ask_unsaved = FALSE;
1992     }
1993   } else if (strcmp(pref_name, PRS_GUI_FIND_WRAP) == 0) {
1994     if (g_ascii_strcasecmp(value, "true") == 0) {
1995             prefs.gui_find_wrap = TRUE;
1996     }
1997     else {
1998             prefs.gui_find_wrap = FALSE;
1999     }
2000   } else if (strcmp(pref_name, PRS_GUI_USE_PREF_SAVE) == 0) {
2001     if (g_ascii_strcasecmp(value, "true") == 0) {
2002             prefs.gui_use_pref_save = TRUE;
2003     }
2004     else {
2005             prefs.gui_use_pref_save = FALSE;
2006     }
2007   } else if (strcmp(pref_name, PRS_GUI_WEBBROWSER) == 0) {
2008     g_free(prefs.gui_webbrowser);
2009     prefs.gui_webbrowser = g_strdup(value);
2010   } else if (strcmp(pref_name, PRS_GUI_WINDOW_TITLE) == 0) {
2011     if (prefs.gui_window_title != NULL)
2012       g_free(prefs.gui_window_title);
2013     prefs.gui_window_title = g_strdup(value);
2014   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_TYPE) == 0) {
2015     prefs.gui_layout_type = strtoul(value, NULL, 10);
2016     if (prefs.gui_layout_type == layout_unused ||
2017         prefs.gui_layout_type >= layout_type_max) {
2018       /* XXX - report an error?  It's not a syntax error - we'd need to
2019          add a way of reporting a *semantic* error. */
2020       prefs.gui_layout_type = layout_type_5;
2021     }
2022   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_1) == 0) {
2023     prefs.gui_layout_content_1 =
2024         find_index_from_string_array(value, gui_layout_content_text, 0);
2025   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_2) == 0) {
2026     prefs.gui_layout_content_2 =
2027         find_index_from_string_array(value, gui_layout_content_text, 0);
2028   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_3) == 0) {
2029     prefs.gui_layout_content_3 =
2030         find_index_from_string_array(value, gui_layout_content_text, 0);
2031   } else if (strcmp(pref_name, PRS_CONSOLE_LOG_LEVEL) == 0) {
2032     prefs.console_log_level = strtoul(value, NULL, 10);
2033
2034 /* handle the capture options */
2035   } else if (strcmp(pref_name, PRS_CAP_DEVICE) == 0) {
2036     if (prefs.capture_device != NULL)
2037       g_free(prefs.capture_device);
2038     prefs.capture_device = g_strdup(value);
2039   } else if (strcmp(pref_name, PRS_CAP_DEVICES_DESCR) == 0) {
2040     if (prefs.capture_devices_descr != NULL)
2041       g_free(prefs.capture_devices_descr);
2042     prefs.capture_devices_descr = g_strdup(value);
2043   } else if (strcmp(pref_name, PRS_CAP_DEVICES_HIDE) == 0) {
2044     if (prefs.capture_devices_hide != NULL)
2045       g_free(prefs.capture_devices_hide);
2046     prefs.capture_devices_hide = g_strdup(value);
2047   } else if (strcmp(pref_name, PRS_CAP_PROM_MODE) == 0) {
2048     prefs.capture_prom_mode = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE);
2049   } else if (strcmp(pref_name, PRS_CAP_REAL_TIME) == 0) {
2050     prefs.capture_real_time = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE);
2051   } else if (strcmp(pref_name, PRS_CAP_AUTO_SCROLL) == 0) {
2052     prefs.capture_auto_scroll = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE);
2053   } else if (strcmp(pref_name, PRS_CAP_SHOW_INFO) == 0) {
2054     prefs.capture_show_info = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE);
2055
2056 /* handle the global options */
2057   } else if (strcmp(pref_name, PRS_NAME_RESOLVE) == 0 ||
2058              strcmp(pref_name, PRS_CAP_NAME_RESOLVE) == 0) {
2059     /*
2060      * "TRUE" and "FALSE", for backwards compatibility, are synonyms for
2061      * RESOLV_ALL and RESOLV_NONE.
2062      *
2063      * Otherwise, we treat it as a list of name types we want to resolve.
2064      */
2065     if (g_ascii_strcasecmp(value, "true") == 0)
2066       prefs.name_resolve = RESOLV_ALL;
2067     else if (g_ascii_strcasecmp(value, "false") == 0)
2068       prefs.name_resolve = RESOLV_NONE;
2069     else {
2070       prefs.name_resolve = RESOLV_NONE; /* start out with none set */
2071       if (string_to_name_resolve(value, &prefs.name_resolve) != '\0')
2072         return PREFS_SET_SYNTAX_ERR;
2073     }
2074   } else if (strcmp(pref_name, PRS_NAME_RESOLVE_CONCURRENCY) == 0) {
2075     prefs.name_resolve_concurrency = strtol(value, NULL, 10);
2076   } else if (strcmp(pref_name, PRS_RTP_PLAYER_MAX_VISIBLE) == 0) {
2077     prefs.rtp_player_max_visible = strtol(value, NULL, 10);
2078   } else {
2079     /* To which module does this preference belong? */
2080     module = NULL;
2081     last_dotp = pref_name;
2082     had_a_dot = FALSE;
2083     while (!module) {
2084         dotp = strchr(last_dotp, '.');
2085         if (dotp == NULL) {
2086             if (had_a_dot) {
2087               /* no such module */
2088               return PREFS_SET_NO_SUCH_PREF;
2089             }
2090             else {
2091               /* no ".", so no module/name separator */
2092               return PREFS_SET_SYNTAX_ERR;
2093             }
2094         }
2095         else {
2096             had_a_dot = TRUE;
2097         }
2098         *dotp = '\0';           /* separate module and preference name */
2099         module = prefs_find_module(pref_name);
2100
2101         /*
2102          * XXX - "Diameter" rather than "diameter" was used in earlier
2103          * versions of Wireshark; if we didn't find the module, and its name
2104          * was "Diameter", look for "diameter" instead.
2105          *
2106          * In addition, the BEEP protocol used to be the BXXP protocol,
2107          * so if we didn't find the module, and its name was "bxxp",
2108          * look for "beep" instead.
2109          *
2110          * Also, the preferences for GTP v0 and v1 were combined under
2111          * a single "gtp" heading, and the preferences for SMPP were
2112          * moved to "smpp-gsm-sms" and then moved to "gsm-sms-ud".
2113          * However, SMPP now has its own preferences, so we just map
2114          * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below.
2115          *
2116          * We also renamed "dcp" to "dccp".
2117          */
2118         if (module == NULL) {
2119           if (strcmp(pref_name, "Diameter") == 0)
2120             module = prefs_find_module("diameter");
2121           else if (strcmp(pref_name, "bxxp") == 0)
2122             module = prefs_find_module("beep");
2123           else if (strcmp(pref_name, "gtpv0") == 0 ||
2124                    strcmp(pref_name, "gtpv1") == 0)
2125             module = prefs_find_module("gtp");
2126           else if (strcmp(pref_name, "smpp-gsm-sms") == 0)
2127             module = prefs_find_module("gsm-sms-ud");
2128           else if (strcmp(pref_name, "dcp") == 0)
2129             module = prefs_find_module("dccp");
2130         }
2131         *dotp = '.';            /* put the preference string back */
2132         dotp++;                 /* skip past separator to preference name */
2133         last_dotp = dotp;
2134     }
2135
2136     pref = find_preference(module, dotp);
2137
2138     if (pref == NULL) {
2139       if (strcmp(module->name, "mgcp") == 0) {
2140         /*
2141          * XXX - "mgcp.display raw text toggle" and "mgcp.display dissect tree"
2142          * rather than "mgcp.display_raw_text" and "mgcp.display_dissect_tree"
2143          * were used in earlier versions of Wireshark; if we didn't find the
2144          * preference, it was an MGCP preference, and its name was
2145          * "display raw text toggle" or "display dissect tree", look for
2146          * "display_raw_text" or "display_dissect_tree" instead.
2147          *
2148          * "mgcp.tcp.port" and "mgcp.udp.port" are harder to handle, as both
2149          * the gateway and callagent ports were given those names; we interpret
2150          * the first as "mgcp.{tcp,udp}.gateway_port" and the second as
2151          * "mgcp.{tcp,udp}.callagent_port", as that's the order in which
2152          * they were registered by the MCCP dissector and thus that's the
2153          * order in which they were written to the preferences file.  (If
2154          * we're not reading the preferences file, but are handling stuff
2155          * from a "-o" command-line option, we have no clue which the user
2156          * had in mind - they should have used "mgcp.{tcp,udp}.gateway_port"
2157          * or "mgcp.{tcp,udp}.callagent_port" instead.)
2158          */
2159         if (strcmp(dotp, "display raw text toggle") == 0)
2160           pref = find_preference(module, "display_raw_text");
2161         else if (strcmp(dotp, "display dissect tree") == 0)
2162           pref = find_preference(module, "display_dissect_tree");
2163         else if (strcmp(dotp, "tcp.port") == 0) {
2164           mgcp_tcp_port_count++;
2165           if (mgcp_tcp_port_count == 1) {
2166             /* It's the first one */
2167             pref = find_preference(module, "tcp.gateway_port");
2168           } else if (mgcp_tcp_port_count == 2) {
2169             /* It's the second one */
2170             pref = find_preference(module, "tcp.callagent_port");
2171           }
2172           /* Otherwise it's from the command line, and we don't bother
2173              mapping it. */
2174         } else if (strcmp(dotp, "udp.port") == 0) {
2175           mgcp_udp_port_count++;
2176           if (mgcp_udp_port_count == 1) {
2177             /* It's the first one */
2178             pref = find_preference(module, "udp.gateway_port");
2179           } else if (mgcp_udp_port_count == 2) {
2180             /* It's the second one */
2181             pref = find_preference(module, "udp.callagent_port");
2182           }
2183           /* Otherwise it's from the command line, and we don't bother
2184              mapping it. */
2185         }
2186       } else if (strcmp(module->name, "smb") == 0) {
2187         /* Handle old names for SMB preferences. */
2188         if (strcmp(dotp, "smb.trans.reassembly") == 0)
2189           pref = find_preference(module, "trans_reassembly");
2190         else if (strcmp(dotp, "smb.dcerpc.reassembly") == 0)
2191           pref = find_preference(module, "dcerpc_reassembly");
2192       } else if (strcmp(module->name, "ndmp") == 0) {
2193         /* Handle old names for NDMP preferences. */
2194         if (strcmp(dotp, "ndmp.desegment") == 0)
2195           pref = find_preference(module, "desegment");
2196       } else if (strcmp(module->name, "diameter") == 0) {
2197         /* Handle old names for Diameter preferences. */
2198         if (strcmp(dotp, "diameter.desegment") == 0)
2199           pref = find_preference(module, "desegment");
2200       } else if (strcmp(module->name, "pcli") == 0) {
2201         /* Handle old names for PCLI preferences. */
2202         if (strcmp(dotp, "pcli.udp_port") == 0)
2203           pref = find_preference(module, "udp_port");
2204       } else if (strcmp(module->name, "artnet") == 0) {
2205         /* Handle old names for ARTNET preferences. */
2206         if (strcmp(dotp, "artnet.udp_port") == 0)
2207           pref = find_preference(module, "udp_port");
2208       } else if (strcmp(module->name, "mapi") == 0) {
2209         /* Handle old names for MAPI preferences. */
2210         if (strcmp(dotp, "mapi_decrypt") == 0)
2211           pref = find_preference(module, "decrypt");
2212       } else if (strcmp(module->name, "fc") == 0) {
2213         /* Handle old names for Fibre Channel preferences. */
2214         if (strcmp(dotp, "reassemble_fc") == 0)
2215           pref = find_preference(module, "reassemble");
2216         else if (strcmp(dotp, "fc_max_frame_size") == 0)
2217           pref = find_preference(module, "max_frame_size");
2218       } else if (strcmp(module->name, "fcip") == 0) {
2219         /* Handle old names for Fibre Channel-over-IP preferences. */
2220         if (strcmp(dotp, "desegment_fcip_messages") == 0)
2221           pref = find_preference(module, "desegment");
2222         else if (strcmp(dotp, "fcip_port") == 0)
2223           pref = find_preference(module, "target_port");
2224       } else if (strcmp(module->name, "gtp") == 0) {
2225         /* Handle old names for GTP preferences. */
2226         if (strcmp(dotp, "gtpv0_port") == 0)
2227           pref = find_preference(module, "v0_port");
2228         else if (strcmp(dotp, "gtpv1c_port") == 0)
2229           pref = find_preference(module, "v1c_port");
2230         else if (strcmp(dotp, "gtpv1u_port") == 0)
2231           pref = find_preference(module, "v1u_port");
2232         else if (strcmp(dotp, "gtp_dissect_tpdu") == 0)
2233           pref = find_preference(module, "dissect_tpdu");
2234         else if (strcmp(dotp, "gtpv0_dissect_cdr_as") == 0)
2235           pref = find_preference(module, "v0_dissect_cdr_as");
2236         else if (strcmp(dotp, "gtpv0_check_etsi") == 0)
2237           pref = find_preference(module, "v0_check_etsi");
2238         else if (strcmp(dotp, "gtpv1_check_etsi") == 0)
2239           pref = find_preference(module, "v1_check_etsi");
2240       } else if (strcmp(module->name, "ip") == 0) {
2241         /* Handle old names for IP preferences. */
2242         if (strcmp(dotp, "ip_summary_in_tree") == 0)
2243           pref = find_preference(module, "summary_in_tree");
2244       } else if (strcmp(module->name, "iscsi") == 0) {
2245         /* Handle old names for iSCSI preferences. */
2246         if (strcmp(dotp, "iscsi_port") == 0)
2247           pref = find_preference(module, "target_port");
2248       } else if (strcmp(module->name, "lmp") == 0) {
2249         /* Handle old names for LMP preferences. */
2250         if (strcmp(dotp, "lmp_version") == 0)
2251           pref = find_preference(module, "version");
2252       } else if (strcmp(module->name, "mtp3") == 0) {
2253         /* Handle old names for MTP3 preferences. */
2254         if (strcmp(dotp, "mtp3_standard") == 0)
2255           pref = find_preference(module, "standard");
2256         else if (strcmp(dotp, "net_addr_format") == 0)
2257           pref = find_preference(module, "addr_format");
2258       } else if (strcmp(module->name, "nlm") == 0) {
2259         /* Handle old names for NLM preferences. */
2260         if (strcmp(dotp, "nlm_msg_res_matching") == 0)
2261           pref = find_preference(module, "msg_res_matching");
2262       } else if (strcmp(module->name, "ppp") == 0) {
2263         /* Handle old names for PPP preferences. */
2264         if (strcmp(dotp, "ppp_fcs") == 0)
2265           pref = find_preference(module, "fcs_type");
2266         else if (strcmp(dotp, "ppp_vj") == 0)
2267           pref = find_preference(module, "decompress_vj");
2268       } else if (strcmp(module->name, "rsvp") == 0) {
2269         /* Handle old names for RSVP preferences. */
2270         if (strcmp(dotp, "rsvp_process_bundle") == 0)
2271           pref = find_preference(module, "process_bundle");
2272       } else if (strcmp(module->name, "tcp") == 0) {
2273         /* Handle old names for TCP preferences. */
2274         if (strcmp(dotp, "tcp_summary_in_tree") == 0)
2275           pref = find_preference(module, "summary_in_tree");
2276         else if (strcmp(dotp, "tcp_analyze_sequence_numbers") == 0)
2277           pref = find_preference(module, "analyze_sequence_numbers");
2278         else if (strcmp(dotp, "tcp_relative_sequence_numbers") == 0)
2279           pref = find_preference(module, "relative_sequence_numbers");
2280       } else if (strcmp(module->name, "udp") == 0) {
2281         /* Handle old names for UDP preferences. */
2282         if (strcmp(dotp, "udp_summary_in_tree") == 0)
2283           pref = find_preference(module, "summary_in_tree");
2284       } else if (strcmp(module->name, "ndps") == 0) {
2285         /* Handle old names for NDPS preferences. */
2286         if (strcmp(dotp, "desegment_ndps") == 0)
2287           pref = find_preference(module, "desegment_tcp");
2288       } else if (strcmp(module->name, "http") == 0) {
2289         /* Handle old names for HTTP preferences. */
2290         if (strcmp(dotp, "desegment_http_headers") == 0)
2291           pref = find_preference(module, "desegment_headers");
2292         else if (strcmp(dotp, "desegment_http_body") == 0)
2293           pref = find_preference(module, "desegment_body");
2294       } else if (strcmp(module->name, "smpp") == 0) {
2295         /* Handle preferences that moved from SMPP. */
2296         module_t *new_module = prefs_find_module("gsm-sms-ud");
2297         if(new_module){
2298           if (strcmp(dotp, "port_number_udh_means_wsp") == 0)
2299             pref = find_preference(new_module, "port_number_udh_means_wsp");
2300           else if (strcmp(dotp, "try_dissect_1st_fragment") == 0)
2301             pref = find_preference(new_module, "try_dissect_1st_fragment");
2302         }
2303       } else if (strcmp(module->name, "asn1") == 0) {
2304         /* Handle old generic ASN.1 preferences (it's not really a
2305            rename, as the new preferences support multiple ports,
2306            but we might as well copy them over). */
2307         if (strcmp(dotp, "tcp_port") == 0)
2308           pref = find_preference(module, "tcp_ports");
2309         else if (strcmp(dotp, "udp_port") == 0)
2310           pref = find_preference(module, "udp_ports");
2311         else if (strcmp(dotp, "sctp_port") == 0)
2312           pref = find_preference(module, "sctp_ports");
2313       } else if (strcmp(module->name, "llcgprs") == 0) {
2314         if (strcmp(dotp, "ignore_cipher_bit") == 0)
2315           pref = find_preference(module, "autodetect_cipher_bit");
2316       }
2317     }
2318     if (pref == NULL)
2319       return PREFS_SET_NO_SUCH_PREF;    /* no such preference */
2320
2321     switch (pref->type) {
2322
2323     case PREF_UINT:
2324       uval = strtoul(value, &p, pref->info.base);
2325       if (p == value || *p != '\0')
2326         return PREFS_SET_SYNTAX_ERR;    /* number was bad */
2327       if (*pref->varp.uint != uval) {
2328         module->prefs_changed = TRUE;
2329         *pref->varp.uint = uval;
2330       }
2331       break;
2332
2333     case PREF_BOOL:
2334       /* XXX - give an error if it's neither "true" nor "false"? */
2335       if (g_ascii_strcasecmp(value, "true") == 0)
2336         bval = TRUE;
2337       else
2338         bval = FALSE;
2339       if (*pref->varp.boolp != bval) {
2340         module->prefs_changed = TRUE;
2341         *pref->varp.boolp = bval;
2342       }
2343       break;
2344
2345     case PREF_ENUM:
2346       /* XXX - give an error if it doesn't match? */
2347       enum_val = find_val_for_string(value,
2348                                         pref->info.enum_info.enumvals, 1);
2349       if (*pref->varp.enump != enum_val) {
2350         module->prefs_changed = TRUE;
2351         *pref->varp.enump = enum_val;
2352       }
2353       break;
2354
2355     case PREF_STRING:
2356       if (strcmp(*pref->varp.string, value) != 0) {
2357         module->prefs_changed = TRUE;
2358         g_free((void *)*pref->varp.string);
2359         *pref->varp.string = g_strdup(value);
2360       }
2361       break;
2362
2363     case PREF_RANGE:
2364     {
2365       range_t *newrange;
2366
2367       if (range_convert_str(&newrange, value, pref->info.max_value) !=
2368           CVT_NO_ERROR) {
2369         /* XXX - distinguish between CVT_SYNTAX_ERROR and
2370            CVT_NUMBER_TOO_BIG */
2371         return PREFS_SET_SYNTAX_ERR;    /* number was bad */
2372       }
2373
2374       if (!ranges_are_equal(*pref->varp.range, newrange)) {
2375         module->prefs_changed = TRUE;
2376         g_free(*pref->varp.range);
2377         *pref->varp.range = newrange;
2378       } else {
2379         g_free (newrange);
2380       }
2381       break;
2382     }
2383
2384     case PREF_STATIC_TEXT:
2385     case PREF_UAT:
2386     {
2387       break;
2388     }
2389
2390     case PREF_OBSOLETE:
2391       return PREFS_SET_OBSOLETE;        /* no such preference any more */
2392     }
2393   }
2394
2395   return PREFS_SET_OK;
2396 }
2397
2398 typedef struct {
2399         module_t *module;
2400         FILE    *pf;
2401 } write_pref_arg_t;
2402
2403 /*
2404  * Write out a single preference.
2405  */
2406 static void
2407 write_pref(gpointer data, gpointer user_data)
2408 {
2409         pref_t *pref = data;
2410         write_pref_arg_t *arg = user_data;
2411         const enum_val_t *enum_valp;
2412         const char *val_string;
2413
2414         if (pref->type == PREF_OBSOLETE) {
2415                 /*
2416                  * This preference is no longer supported; it's not a
2417                  * real preference, so we don't write it out (i.e., we
2418                  * treat it as if it weren't found in the list of
2419                  * preferences, and we weren't called in the first place).
2420                  */
2421                 return;
2422         }
2423
2424         fprintf(arg->pf, "\n# %s\n", pref->description);
2425
2426         switch (pref->type) {
2427
2428         case PREF_UINT:
2429                 switch (pref->info.base) {
2430
2431                 case 10:
2432                         fprintf(arg->pf, "# A decimal number.\n");
2433                         fprintf(arg->pf, "%s.%s: %u\n", arg->module->name,
2434                             pref->name, *pref->varp.uint);
2435                         break;
2436
2437                 case 8:
2438                         fprintf(arg->pf, "# An octal number.\n");
2439                         fprintf(arg->pf, "%s.%s: %#o\n", arg->module->name,
2440                             pref->name, *pref->varp.uint);
2441                         break;
2442
2443                 case 16:
2444                         fprintf(arg->pf, "# A hexadecimal number.\n");
2445                         fprintf(arg->pf, "%s.%s: %#x\n", arg->module->name,
2446                             pref->name, *pref->varp.uint);
2447                         break;
2448                 }
2449                 break;
2450
2451         case PREF_BOOL:
2452                 fprintf(arg->pf, "# TRUE or FALSE (case-insensitive).\n");
2453                 fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
2454                     *pref->varp.boolp ? "TRUE" : "FALSE");
2455                 break;
2456
2457         case PREF_ENUM:
2458                 /*
2459                  * For now, we save the "description" value, so that if we
2460                  * save the preferences older versions of Wireshark can at
2461                  * least read preferences that they supported; we support
2462                  * either the short name or the description when reading
2463                  * the preferences file or a "-o" option.
2464                  */
2465                 fprintf(arg->pf, "# One of: ");
2466                 enum_valp = pref->info.enum_info.enumvals;
2467                 val_string = NULL;
2468                 while (enum_valp->name != NULL) {
2469                         if (enum_valp->value == *pref->varp.enump)
2470                                 val_string = enum_valp->description;
2471                         fprintf(arg->pf, "%s", enum_valp->description);
2472                         enum_valp++;
2473                         if (enum_valp->name == NULL)
2474                                 fprintf(arg->pf, "\n");
2475                         else
2476                                 fprintf(arg->pf, ", ");
2477                 }
2478                 fprintf(arg->pf, "# (case-insensitive).\n");
2479                 fprintf(arg->pf, "%s.%s: %s\n", arg->module->name,
2480                     pref->name, val_string);
2481                 break;
2482
2483         case PREF_STRING:
2484                 fprintf(arg->pf, "# A string.\n");
2485                 fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
2486                     *pref->varp.string);
2487                 break;
2488
2489         case PREF_RANGE:
2490         {
2491                 char *range_string;
2492
2493                 range_string = range_convert_range(*pref->varp.range);
2494                 fprintf(arg->pf, "# A string denoting an positive integer range (e.g., \"1-20,30-40\").\n");
2495                 fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
2496                         range_string);
2497                 break;
2498         }
2499
2500         case PREF_STATIC_TEXT:
2501         case PREF_UAT:
2502         {
2503                 /* Nothing to do */
2504                 break;
2505         }
2506
2507         case PREF_OBSOLETE:
2508                 g_assert_not_reached();
2509                 break;
2510         }
2511 }
2512
2513 static gboolean
2514 write_module_prefs(void *value, void *data)
2515 {
2516         write_pref_arg_t arg;
2517
2518         arg.module = value;
2519         arg.pf = data;
2520         g_list_foreach(arg.module->prefs, write_pref, &arg);
2521         return FALSE;
2522 }
2523
2524 /* Write out "prefs" to the user's preferences file, and return 0.
2525
2526    If the preferences file path is NULL, write to stdout.
2527
2528    If we got an error, stuff a pointer to the path of the preferences file
2529    into "*pf_path_return", and return the errno. */
2530 int
2531 write_prefs(char **pf_path_return)
2532 {
2533   char        *pf_path;
2534   FILE        *pf;
2535   GList       *clp, *col_l;
2536   fmt_data    *cfmt;
2537   const gchar *cust_format = col_format_to_string(COL_CUSTOM);
2538
2539   /* Needed for "-G defaultprefs" */
2540   init_prefs();
2541
2542   /* To do:
2543    * - Split output lines longer than MAX_VAL_LEN
2544    * - Create a function for the preference directory check/creation
2545    *   so that duplication can be avoided with filter.c
2546    */
2547
2548   if (pf_path_return != NULL) {
2549     pf_path = get_persconffile_path(PF_NAME, TRUE, TRUE);
2550     if ((pf = eth_fopen(pf_path, "w")) == NULL) {
2551       *pf_path_return = pf_path;
2552       return errno;
2553     }
2554   } else {
2555     pf = stdout;
2556   }
2557
2558   fputs("# Configuration file for Wireshark " VERSION ".\n"
2559     "#\n"
2560     "# This file is regenerated each time preferences are saved within\n"
2561     "# Wireshark.  Making manual changes should be safe, however.\n", pf);
2562
2563   fprintf (pf, "\n######## User Interface ########\n");
2564
2565   fprintf(pf, "\n# Vertical scrollbars should be on right side?\n");
2566   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2567   fprintf(pf, PRS_GUI_SCROLLBAR_ON_RIGHT ": %s\n",
2568                   prefs.gui_scrollbar_on_right == TRUE ? "TRUE" : "FALSE");
2569
2570   fprintf(pf, "\n# Packet-list selection bar can be used to browse w/o selecting?\n");
2571   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2572   fprintf(pf, PRS_GUI_PLIST_SEL_BROWSE ": %s\n",
2573                   prefs.gui_plist_sel_browse == TRUE ? "TRUE" : "FALSE");
2574
2575   fprintf(pf, "\n# Protocol-tree selection bar can be used to browse w/o selecting?\n");
2576   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2577   fprintf(pf, PRS_GUI_PTREE_SEL_BROWSE ": %s\n",
2578                   prefs.gui_ptree_sel_browse == TRUE ? "TRUE" : "FALSE");
2579
2580   fprintf(pf, "\n# Alternating colors in TreeViews?\n");
2581   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2582   fprintf(pf, PRS_GUI_ALTERN_COLORS ": %s\n",
2583                   prefs.gui_altern_colors == TRUE ? "TRUE" : "FALSE");
2584
2585   fprintf(pf, "\n# Place filter toolbar inside the statusbar?\n");
2586   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2587   fprintf(pf, PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR ": %s\n",
2588                  prefs.filter_toolbar_show_in_statusbar == TRUE ? "TRUE" : "FALSE");
2589
2590   fprintf(pf, "\n# Protocol-tree line style.\n");
2591   fprintf(pf, "# One of: NONE, SOLID, DOTTED, TABBED\n");
2592   fprintf(pf, PRS_GUI_PTREE_LINE_STYLE ": %s\n",
2593           gui_ptree_line_style_text[prefs.gui_ptree_line_style]);
2594
2595   fprintf(pf, "\n# Protocol-tree expander style.\n");
2596   fprintf(pf, "# One of: NONE, SQUARE, TRIANGLE, CIRCULAR\n");
2597   fprintf(pf, PRS_GUI_PTREE_EXPANDER_STYLE ": %s\n",
2598                   gui_ptree_expander_style_text[prefs.gui_ptree_expander_style]);
2599
2600   fprintf(pf, "\n# Hex dump highlight style.\n");
2601   fprintf(pf, "# One of: BOLD, INVERSE\n");
2602   fprintf(pf, PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE ": %s\n",
2603                   gui_hex_dump_highlight_style_text[prefs.gui_hex_dump_highlight_style]);
2604
2605   fprintf(pf, "\n# Main Toolbar style.\n");
2606   fprintf(pf, "# One of: ICONS, TEXT, BOTH\n");
2607   fprintf(pf, PRS_GUI_TOOLBAR_MAIN_STYLE ": %s\n",
2608                   gui_toolbar_style_text[prefs.gui_toolbar_main_style]);
2609
2610   fprintf(pf, "\n# Save window position at exit?\n");
2611   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2612   fprintf(pf, PRS_GUI_GEOMETRY_SAVE_POSITION ": %s\n",
2613                   prefs.gui_geometry_save_position == TRUE ? "TRUE" : "FALSE");
2614
2615   fprintf(pf, "\n# Save window size at exit?\n");
2616   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2617   fprintf(pf, PRS_GUI_GEOMETRY_SAVE_SIZE ": %s\n",
2618                   prefs.gui_geometry_save_size == TRUE ? "TRUE" : "FALSE");
2619
2620   fprintf(pf, "\n# Save window maximized state at exit (GTK2 only)?\n");
2621   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2622   fprintf(pf, PRS_GUI_GEOMETRY_SAVE_MAXIMIZED ": %s\n",
2623                   prefs.gui_geometry_save_maximized == TRUE ? "TRUE" : "FALSE");
2624
2625   fprintf(pf, "\n# Open a console window (WIN32 only)?\n");
2626   fprintf(pf, "# One of: NEVER, AUTOMATIC, ALWAYS\n");
2627   fprintf(pf, PRS_GUI_CONSOLE_OPEN ": %s\n",
2628                   gui_console_open_text[prefs.gui_console_open]);
2629
2630   fprintf(pf, "\n# The max. number of items in the open recent files list.\n");
2631   fprintf(pf, "# A decimal number.\n");
2632   fprintf(pf, PRS_GUI_RECENT_COUNT_MAX ": %d\n",
2633                   prefs.gui_recent_files_count_max);
2634
2635   fprintf(pf, "\n# Where to start the File Open dialog box.\n");
2636   fprintf(pf, "# One of: LAST_OPENED, SPECIFIED\n");
2637   fprintf(pf, PRS_GUI_FILEOPEN_STYLE ": %s\n",
2638                   gui_fileopen_style_text[prefs.gui_fileopen_style]);
2639
2640   if (prefs.gui_fileopen_dir != NULL) {
2641     fprintf(pf, "\n# Directory to start in when opening File Open dialog.\n");
2642     fprintf(pf, PRS_GUI_FILEOPEN_DIR ": %s\n",
2643                   prefs.gui_fileopen_dir);
2644   }
2645
2646   fprintf(pf, "\n# The preview timeout in the File Open dialog.\n");
2647   fprintf(pf, "# A decimal number (in seconds).\n");
2648   fprintf(pf, PRS_GUI_FILEOPEN_PREVIEW ": %d\n",
2649                   prefs.gui_fileopen_preview);
2650
2651   fprintf(pf, "\n# Ask to save unsaved capture files?\n");
2652   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2653   fprintf(pf, PRS_GUI_ASK_UNSAVED ": %s\n",
2654                   prefs.gui_ask_unsaved == TRUE ? "TRUE" : "FALSE");
2655
2656   fprintf(pf, "\n# Wrap to beginning/end of file during search?\n");
2657   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2658   fprintf(pf, PRS_GUI_FIND_WRAP ": %s\n",
2659                   prefs.gui_find_wrap == TRUE ? "TRUE" : "FALSE");
2660
2661   fprintf(pf, "\n# Settings dialogs use a save button?\n");
2662   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2663   fprintf(pf, PRS_GUI_USE_PREF_SAVE ": %s\n",
2664                   prefs.gui_use_pref_save == TRUE ? "TRUE" : "FALSE");
2665
2666   fprintf(pf, "\n# The path to the webbrowser.\n");
2667   fprintf(pf, "# Ex: mozilla %%s\n");
2668   fprintf(pf, PRS_GUI_WEBBROWSER ": %s\n", prefs.gui_webbrowser);
2669
2670   fprintf(pf, "\n# Custom window title. (Prepended to existing titles.)\n");
2671   fprintf(pf, PRS_GUI_WINDOW_TITLE ": %s\n",
2672               prefs.gui_window_title);
2673
2674   fprintf (pf, "\n######## User Interface: Layout ########\n");
2675
2676   fprintf(pf, "\n# Layout type (1-6).\n");
2677   fprintf(pf, PRS_GUI_LAYOUT_TYPE ": %d\n",
2678                   prefs.gui_layout_type);
2679
2680   fprintf(pf, "\n# Layout content of the panes (1-3).\n");
2681   fprintf(pf, "# One of: NONE, PLIST, PDETAILS, PBYTES\n");
2682   fprintf(pf, PRS_GUI_LAYOUT_CONTENT_1 ": %s\n",
2683                   gui_layout_content_text[prefs.gui_layout_content_1]);
2684   fprintf(pf, PRS_GUI_LAYOUT_CONTENT_2 ": %s\n",
2685                   gui_layout_content_text[prefs.gui_layout_content_2]);
2686   fprintf(pf, PRS_GUI_LAYOUT_CONTENT_3 ": %s\n",
2687                   gui_layout_content_text[prefs.gui_layout_content_3]);
2688
2689   fprintf (pf, "\n######## User Interface: Columns ########\n");
2690
2691   clp = prefs.col_list;
2692   col_l = NULL;
2693   while (clp) {
2694     cfmt = (fmt_data *) clp->data;
2695     col_l = g_list_append(col_l, cfmt->title);
2696     if ((strcmp(cfmt->fmt, cust_format) == 0) && (cfmt->custom_field)) {
2697       gchar *fmt = g_strdup_printf("%s:%s", cfmt->fmt, cfmt->custom_field);
2698       col_l = g_list_append(col_l, fmt);
2699     } else {
2700       col_l = g_list_append(col_l, cfmt->fmt);
2701     }
2702     clp = clp->next;
2703   }
2704   fprintf (pf, "\n# Packet list column format.\n");
2705   fprintf (pf, "# Each pair of strings consists of a column title and its format.\n");
2706   fprintf (pf, "%s: %s\n", PRS_COL_FMT, put_string_list(col_l));
2707   /* This frees the list of strings, but not the strings to which it
2708      refers; that's what we want, as we haven't copied those strings,
2709      we just referred to them.  */
2710   g_list_free(col_l);
2711
2712   fprintf (pf, "\n######## User Interface: Font ########\n");
2713
2714   fprintf(pf, "\n# Font name for packet list, protocol tree, and hex dump panes.\n");
2715   fprintf(pf, PRS_GUI_FONT_NAME_2 ": %s\n", prefs.gui_font_name);
2716
2717   fprintf (pf, "\n######## User Interface: Colors ########\n");
2718
2719   fprintf (pf, "\n# Color preferences for a marked frame.\n");
2720   fprintf (pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n");
2721   fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_MARKED_FG,
2722     (prefs.gui_marked_fg.red * 255 / 65535),
2723     (prefs.gui_marked_fg.green * 255 / 65535),
2724     (prefs.gui_marked_fg.blue * 255 / 65535));
2725   fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_MARKED_BG,
2726     (prefs.gui_marked_bg.red * 255 / 65535),
2727     (prefs.gui_marked_bg.green * 255 / 65535),
2728     (prefs.gui_marked_bg.blue * 255 / 65535));
2729
2730   /* Don't write the colors of the 10 easy-access-colorfilters to the preferences
2731    * file until the colors can be changed in the GUI. Currently this is not really
2732    * possible since the STOCK-icons for these colors are hardcoded.
2733    *
2734    * XXX Find a way to change the colors of the STOCK-icons on the fly and then
2735    *     add these 10 colors to the list of colors that can be changed through
2736    *     the preferences.
2737    *
2738   fprintf (pf, "%s: %s\n", PRS_GUI_COLORIZED_FG, prefs.gui_colorized_fg);
2739   fprintf (pf, "%s: %s\n", PRS_GUI_COLORIZED_BG, prefs.gui_colorized_bg);
2740   */
2741
2742   fprintf (pf, "\n# TCP stream window color preferences.\n");
2743   fprintf (pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n");
2744   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_CL_FG,
2745     (prefs.st_client_fg.red * 255 / 65535),
2746     (prefs.st_client_fg.green * 255 / 65535),
2747     (prefs.st_client_fg.blue * 255 / 65535));
2748   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_CL_BG,
2749     (prefs.st_client_bg.red * 255 / 65535),
2750     (prefs.st_client_bg.green * 255 / 65535),
2751     (prefs.st_client_bg.blue * 255 / 65535));
2752   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_SR_FG,
2753     (prefs.st_server_fg.red * 255 / 65535),
2754     (prefs.st_server_fg.green * 255 / 65535),
2755     (prefs.st_server_fg.blue * 255 / 65535));
2756   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_SR_BG,
2757     (prefs.st_server_bg.red * 255 / 65535),
2758     (prefs.st_server_bg.green * 255 / 65535),
2759     (prefs.st_server_bg.blue * 255 / 65535));
2760
2761   fprintf(pf, "\n######## Console: logging level ########\n");
2762   fprintf(pf, "# (debugging only, not in the Preferences dialog)\n");
2763   fprintf(pf, "# A bitmask of glib log levels:\n"
2764           "# G_LOG_LEVEL_ERROR    = 4\n"
2765           "# G_LOG_LEVEL_CRITICAL = 8\n"
2766           "# G_LOG_LEVEL_WARNING  = 16\n"
2767           "# G_LOG_LEVEL_MESSAGE  = 32\n"
2768           "# G_LOG_LEVEL_INFO     = 64\n"
2769           "# G_LOG_LEVEL_DEBUG    = 128\n");
2770
2771   fprintf(pf, PRS_CONSOLE_LOG_LEVEL ": %u\n",
2772           prefs.console_log_level);
2773
2774   fprintf(pf, "\n####### Capture ########\n");
2775
2776   if (prefs.capture_device != NULL) {
2777     fprintf(pf, "\n# Default capture device\n");
2778     fprintf(pf, PRS_CAP_DEVICE ": %s\n", prefs.capture_device);
2779   }
2780
2781   if (prefs.capture_devices_descr != NULL) {
2782     fprintf(pf, "\n# Interface descriptions.\n");
2783     fprintf(pf, "# Ex: eth0(eth0 descr),eth1(eth1 descr),...\n");
2784     fprintf(pf, PRS_CAP_DEVICES_DESCR ": %s\n", prefs.capture_devices_descr);
2785   }
2786
2787   if (prefs.capture_devices_hide != NULL) {
2788     fprintf(pf, "\n# Hide interface?\n");
2789     fprintf(pf, "# Ex: eth0,eth3,...\n");
2790     fprintf(pf, PRS_CAP_DEVICES_HIDE ": %s\n", prefs.capture_devices_hide);
2791   }
2792
2793   fprintf(pf, "\n# Capture in promiscuous mode?\n");
2794   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2795   fprintf(pf, PRS_CAP_PROM_MODE ": %s\n",
2796                   prefs.capture_prom_mode == TRUE ? "TRUE" : "FALSE");
2797
2798   fprintf(pf, "\n# Update packet list in real time during capture?\n");
2799   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2800   fprintf(pf, PRS_CAP_REAL_TIME ": %s\n",
2801                   prefs.capture_real_time == TRUE ? "TRUE" : "FALSE");
2802
2803   fprintf(pf, "\n# Scroll packet list during capture?\n");
2804   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2805   fprintf(pf, PRS_CAP_AUTO_SCROLL ": %s\n",
2806                   prefs.capture_auto_scroll == TRUE ? "TRUE" : "FALSE");
2807
2808   fprintf(pf, "\n# Show capture info dialog while capturing?\n");
2809   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2810   fprintf(pf, PRS_CAP_SHOW_INFO ": %s\n",
2811                   prefs.capture_show_info == TRUE ? "TRUE" : "FALSE");
2812
2813   fprintf (pf, "\n######## Printing ########\n");
2814
2815   fprintf (pf, "\n# Can be one of \"text\" or \"postscript\".\n"
2816     "print.format: %s\n", pr_formats[prefs.pr_format]);
2817
2818   fprintf (pf, "\n# Can be one of \"command\" or \"file\".\n"
2819     "print.destination: %s\n", pr_dests[prefs.pr_dest]);
2820
2821   fprintf (pf, "\n# This is the file that gets written to when the "
2822     "destination is set to \"file\"\n"
2823     "%s: %s\n", PRS_PRINT_FILE, prefs.pr_file);
2824
2825   fprintf (pf, "\n# Output gets piped to this command when the destination "
2826     "is set to \"command\"\n"
2827     "%s: %s\n", PRS_PRINT_CMD, prefs.pr_cmd);
2828
2829   fprintf(pf, "\n####### Name Resolution ########\n");
2830
2831   fprintf(pf, "\n# Resolve addresses to names?\n");
2832   fprintf(pf, "# TRUE or FALSE (case-insensitive), or a list of address types to resolve.\n");
2833   fprintf(pf, PRS_NAME_RESOLVE ": %s\n",
2834                   name_resolve_to_string(prefs.name_resolve));
2835
2836   fprintf(pf, "\n# Name resolution concurrency.\n");
2837   fprintf(pf, "# A decimal number.\n");
2838   fprintf(pf, PRS_NAME_RESOLVE_CONCURRENCY ": %d\n",
2839                   prefs.name_resolve_concurrency);
2840
2841   fprintf(pf, "\n####### RTP Player ########\n");
2842
2843   fprintf(pf, "\n# Maximum visible channels in RTP Player window.\n");
2844   fprintf(pf, "# An integer value greater than 0.\n");
2845   fprintf(pf, PRS_RTP_PLAYER_MAX_VISIBLE ": %d\n",
2846                   prefs.rtp_player_max_visible);
2847
2848   fprintf(pf, "\n####### Protocols ########\n");
2849
2850   pe_tree_foreach(prefs_modules, write_module_prefs, pf);
2851
2852   fclose(pf);
2853
2854   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
2855      an error indication, or maybe write to a new preferences file and
2856      rename that file on top of the old one only if there are not I/O
2857      errors. */
2858   return 0;
2859 }
2860
2861 /* Copy a set of preferences. */
2862 void
2863 copy_prefs(e_prefs *dest, e_prefs *src)
2864 {
2865   fmt_data *src_cfmt, *dest_cfmt;
2866   GList *entry;
2867
2868   dest->pr_format = src->pr_format;
2869   dest->pr_dest = src->pr_dest;
2870   dest->pr_file = g_strdup(src->pr_file);
2871   dest->pr_cmd = g_strdup(src->pr_cmd);
2872   dest->col_list = NULL;
2873   for (entry = src->col_list; entry != NULL; entry = g_list_next(entry)) {
2874     src_cfmt = entry->data;
2875     dest_cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
2876     dest_cfmt->title = g_strdup(src_cfmt->title);
2877     dest_cfmt->fmt = g_strdup(src_cfmt->fmt);
2878     if (src_cfmt->custom_field) {
2879       dest_cfmt->custom_field = g_strdup(src_cfmt->custom_field);
2880     } else {
2881       dest_cfmt->custom_field = NULL;
2882     }
2883     dest->col_list = g_list_append(dest->col_list, dest_cfmt);
2884   }
2885   dest->num_cols = src->num_cols;
2886   dest->st_client_fg = src->st_client_fg;
2887   dest->st_client_bg = src->st_client_bg;
2888   dest->st_server_fg = src->st_server_fg;
2889   dest->st_server_bg = src->st_server_bg;
2890   dest->gui_scrollbar_on_right = src->gui_scrollbar_on_right;
2891   dest->gui_plist_sel_browse = src->gui_plist_sel_browse;
2892   dest->gui_ptree_sel_browse = src->gui_ptree_sel_browse;
2893   dest->gui_altern_colors = src->gui_altern_colors;
2894   dest->filter_toolbar_show_in_statusbar = src->filter_toolbar_show_in_statusbar;
2895   dest->gui_ptree_line_style = src->gui_ptree_line_style;
2896   dest->gui_ptree_expander_style = src->gui_ptree_expander_style;
2897   dest->gui_hex_dump_highlight_style = src->gui_hex_dump_highlight_style;
2898   dest->gui_toolbar_main_style = src->gui_toolbar_main_style;
2899   dest->gui_fileopen_dir = g_strdup(src->gui_fileopen_dir);
2900   dest->gui_console_open = src->gui_console_open;
2901   dest->gui_fileopen_style = src->gui_fileopen_style;
2902   dest->gui_fileopen_preview = src->gui_fileopen_preview;
2903   dest->gui_ask_unsaved = src->gui_ask_unsaved;
2904   dest->gui_find_wrap = src->gui_find_wrap;
2905   dest->gui_use_pref_save = src->gui_use_pref_save;
2906   dest->gui_layout_type = src->gui_layout_type;
2907   dest->gui_layout_content_1 = src->gui_layout_content_1;
2908   dest->gui_layout_content_2 = src->gui_layout_content_2;
2909   dest->gui_layout_content_3 = src->gui_layout_content_3;
2910   dest->gui_font_name = g_strdup(src->gui_font_name);
2911   dest->gui_marked_fg = src->gui_marked_fg;
2912   dest->gui_marked_bg = src->gui_marked_bg;
2913   dest->gui_geometry_save_position = src->gui_geometry_save_position;
2914   dest->gui_geometry_save_size = src->gui_geometry_save_size;
2915   dest->gui_geometry_save_maximized = src->gui_geometry_save_maximized;
2916   dest->gui_webbrowser = g_strdup(src->gui_webbrowser);
2917   dest->gui_window_title = g_strdup(src->gui_window_title);
2918   dest->console_log_level = src->console_log_level;
2919 /*  values for the capture dialog box */
2920   dest->capture_device = g_strdup(src->capture_device);
2921   dest->capture_devices_descr = g_strdup(src->capture_devices_descr);
2922   dest->capture_devices_hide = g_strdup(src->capture_devices_hide);
2923   dest->capture_prom_mode = src->capture_prom_mode;
2924   dest->capture_real_time = src->capture_real_time;
2925   dest->capture_auto_scroll = src->capture_auto_scroll;
2926   dest->capture_show_info = src->capture_show_info;
2927   dest->name_resolve = src->name_resolve;
2928   dest->name_resolve_concurrency = src->name_resolve_concurrency;
2929
2930 }
2931
2932 /* Free a set of preferences. */
2933 void
2934 free_prefs(e_prefs *pr)
2935 {
2936   if (pr->pr_file != NULL) {
2937     g_free(pr->pr_file);
2938     pr->pr_file = NULL;
2939   }
2940   if (pr->pr_cmd != NULL) {
2941     g_free(pr->pr_cmd);
2942     pr->pr_cmd = NULL;
2943   }
2944   free_col_info(pr);
2945   if (pr->gui_font_name != NULL) {
2946     g_free(pr->gui_font_name);
2947     pr->gui_font_name = NULL;
2948   }
2949   if (pr->gui_fileopen_dir != NULL) {
2950     g_free(pr->gui_fileopen_dir);
2951     pr->gui_fileopen_dir = NULL;
2952   }
2953   g_free(pr->gui_webbrowser);
2954   pr->gui_webbrowser = NULL;
2955   if (pr->gui_window_title != NULL) {
2956     g_free(pr->gui_window_title);
2957     pr->gui_window_title = NULL;
2958   }
2959   if (pr->capture_device != NULL) {
2960     g_free(pr->capture_device);
2961     pr->capture_device = NULL;
2962   }
2963   if (pr->capture_devices_descr != NULL) {
2964     g_free(pr->capture_devices_descr);
2965     pr->capture_devices_descr = NULL;
2966   }
2967   if (pr->capture_devices_hide != NULL) {
2968     g_free(pr->capture_devices_hide);
2969     pr->capture_devices_hide = NULL;
2970   }
2971 }
2972
2973 static void
2974 free_col_info(e_prefs *pr)
2975 {
2976   fmt_data *cfmt;
2977
2978   while (pr->col_list != NULL) {
2979     cfmt = pr->col_list->data;
2980     g_free(cfmt->title);
2981     g_free(cfmt->fmt);
2982     if (cfmt->custom_field) {
2983       g_free(cfmt->custom_field);
2984     }
2985     g_free(cfmt);
2986     pr->col_list = g_list_remove_link(pr->col_list, pr->col_list);
2987   }
2988   g_list_free(pr->col_list);
2989   pr->col_list = NULL;
2990 }
2991
2992