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