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