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