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