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