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