New protocol: PKCS#1 (rfc2313 pplus some extra oid's)
[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/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_webbrowser             = g_strdup("mozilla %s");
1016     prefs.gui_layout_type            = layout_type_5;
1017     prefs.gui_layout_content_1       = layout_pane_content_plist;
1018     prefs.gui_layout_content_2       = layout_pane_content_pdetails;
1019     prefs.gui_layout_content_3       = layout_pane_content_pbytes;
1020
1021 /* set the default values for the capture dialog box */
1022     prefs.capture_device           = NULL;
1023     prefs.capture_devices_descr    = NULL;
1024     prefs.capture_devices_hide     = NULL;
1025     prefs.capture_prom_mode        = TRUE;
1026     prefs.capture_real_time        = FALSE;
1027     prefs.capture_auto_scroll      = FALSE;
1028     prefs.capture_show_info        = TRUE;
1029     prefs.name_resolve             = RESOLV_ALL ^ RESOLV_NETWORK;
1030     prefs.name_resolve_concurrency = 500;
1031   }
1032
1033   /* Construct the pathname of the global preferences file. */
1034   if (! gpf_path)
1035     gpf_path = get_datafile_path(GPF_NAME);
1036
1037   /* Read the global preferences file, if it exists. */
1038   *gpf_path_return = NULL;
1039   if ((pf = fopen(gpf_path, "r")) != NULL) {
1040     /*
1041      * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
1042      * seen.
1043      */
1044     mgcp_tcp_port_count = 0;
1045     mgcp_udp_port_count = 0;
1046
1047     /* We succeeded in opening it; read it. */
1048     err = read_prefs_file(gpf_path, pf, set_pref);
1049     if (err != 0) {
1050       /* We had an error reading the file; return the errno and the
1051          pathname, so our caller can report the error. */
1052       *gpf_errno_return = 0;
1053       *gpf_read_errno_return = err;
1054       *gpf_path_return = gpf_path;
1055     }
1056     fclose(pf);
1057   } else {
1058     /* We failed to open it.  If we failed for some reason other than
1059        "it doesn't exist", return the errno and the pathname, so our
1060        caller can report the error. */
1061     if (errno != ENOENT) {
1062       *gpf_errno_return = errno;
1063       *gpf_read_errno_return = 0;
1064       *gpf_path_return = gpf_path;
1065     }
1066   }
1067
1068   /* Construct the pathname of the user's preferences file. */
1069   pf_path = get_persconffile_path(PF_NAME, FALSE);
1070
1071   /* Read the user's preferences file, if it exists. */
1072   *pf_path_return = NULL;
1073   if ((pf = fopen(pf_path, "r")) != NULL) {
1074     /*
1075      * Start out the counters of "mgcp.{tcp,udp}.port" entries we've
1076      * seen.
1077      */
1078     mgcp_tcp_port_count = 0;
1079     mgcp_udp_port_count = 0;
1080
1081     /* We succeeded in opening it; read it. */
1082     err = read_prefs_file(pf_path, pf, set_pref);
1083     if (err != 0) {
1084       /* We had an error reading the file; return the errno and the
1085          pathname, so our caller can report the error. */
1086       *pf_errno_return = 0;
1087       *pf_read_errno_return = err;
1088       *pf_path_return = pf_path;
1089     } else
1090       g_free(pf_path);
1091     fclose(pf);
1092   } else {
1093     /* We failed to open it.  If we failed for some reason other than
1094        "it doesn't exist", return the errno and the pathname, so our
1095        caller can report the error. */
1096     if (errno != ENOENT) {
1097       *pf_errno_return = errno;
1098       *pf_read_errno_return = 0;
1099       *pf_path_return = pf_path;
1100     }
1101   }
1102
1103   return &prefs;
1104 }
1105
1106 /* read the preferences file (or similiar) and call the callback 
1107  * function to set each key/value pair found */
1108 int
1109 read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fct)
1110 {
1111   enum { START, IN_VAR, PRE_VAL, IN_VAL, IN_SKIP };
1112   gchar     cur_var[MAX_VAR_LEN], cur_val[MAX_VAL_LEN];
1113   int       got_c, state = START;
1114   gboolean  got_val = FALSE;
1115   gint      var_len = 0, val_len = 0, fline = 1, pline = 1;
1116   gchar     hint[] = "(saving your preferences once should remove this warning)";
1117
1118
1119   while ((got_c = getc(pf)) != EOF) {
1120     if (got_c == '\n') {
1121       state = START;
1122       fline++;
1123       continue;
1124     }
1125     if (var_len >= MAX_VAR_LEN) {
1126       g_warning ("%s line %d: Variable too long %s", pf_path, fline, hint);
1127       state = IN_SKIP;
1128       var_len = 0;
1129       continue;
1130     }
1131     if (val_len >= MAX_VAL_LEN) {
1132       g_warning ("%s line %d: Value too long %s", pf_path, fline, hint);
1133       state = IN_SKIP;
1134       var_len = 0;
1135       continue;
1136     }
1137
1138     switch (state) {
1139       case START:
1140         if (isalnum(got_c)) {
1141           if (var_len > 0) {
1142             if (got_val) {
1143               cur_var[var_len] = '\0';
1144               cur_val[val_len] = '\0';
1145               switch (pref_set_pair_fct(cur_var, cur_val)) {
1146
1147               case PREFS_SET_SYNTAX_ERR:
1148                 g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint);
1149                 break;
1150
1151               case PREFS_SET_NO_SUCH_PREF:
1152                 g_warning ("%s line %d: No such preference \"%s\" %s", pf_path,
1153                                 pline, cur_var, hint);
1154                 break;
1155
1156               case PREFS_SET_OBSOLETE:
1157                 /* We silently ignore attempts to set these; it's
1158                    probably not the user's fault that it's in there -
1159                    they may have saved preferences with a release that
1160                    supported them. */
1161                 break;
1162               }
1163             } else {
1164               g_warning ("%s line %d: Incomplete preference %s", pf_path, pline, hint);
1165             }
1166           }
1167           state      = IN_VAR;
1168           got_val    = FALSE;
1169           cur_var[0] = got_c;
1170           var_len    = 1;
1171           pline = fline;
1172         } else if (isspace(got_c) && var_len > 0 && got_val) {
1173           state = PRE_VAL;
1174         } else if (got_c == '#') {
1175           state = IN_SKIP;
1176         } else {
1177           g_warning ("%s line %d: Malformed line %s", pf_path, fline, hint);
1178         }
1179         break;
1180       case IN_VAR:
1181         if (got_c != ':') {
1182           cur_var[var_len] = got_c;
1183           var_len++;
1184         } else {
1185           state   = PRE_VAL;
1186           val_len = 0;
1187           got_val = TRUE;
1188         }
1189         break;
1190       case PRE_VAL:
1191         if (!isspace(got_c)) {
1192           state = IN_VAL;
1193           cur_val[val_len] = got_c;
1194           val_len++;
1195         }
1196         break;
1197       case IN_VAL:
1198         if (got_c != '#')  {
1199           cur_val[val_len] = got_c;
1200           val_len++;
1201         } else {
1202           while (isspace((guchar)cur_val[val_len]) && val_len > 0)
1203             val_len--;
1204           state = IN_SKIP;
1205         }
1206         break;
1207     }
1208   }
1209   if (var_len > 0) {
1210     if (got_val) {
1211       cur_var[var_len] = '\0';
1212       cur_val[val_len] = '\0';
1213       switch (pref_set_pair_fct(cur_var, cur_val)) {
1214
1215       case PREFS_SET_SYNTAX_ERR:
1216         g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint);
1217         break;
1218
1219       case PREFS_SET_NO_SUCH_PREF:
1220         g_warning ("%s line %d: No such preference \"%s\" %s", pf_path,
1221                         pline, cur_var, hint);
1222         break;
1223
1224       case PREFS_SET_OBSOLETE:
1225         /* We silently ignore attempts to set these; it's probably not
1226            the user's fault that it's in there - they may have saved
1227            preferences with a release that supported it. */
1228         break;
1229       }
1230     } else {
1231       g_warning ("%s line %d: Incomplete preference %s", pf_path, pline, hint);
1232     }
1233   }
1234   if (ferror(pf))
1235     return errno;
1236   else
1237     return 0;
1238 }
1239
1240 /*
1241  * Given a string of the form "<pref name>:<pref value>", as might appear
1242  * as an argument to a "-o" option, parse it and set the preference in
1243  * question.  Return an indication of whether it succeeded or failed
1244  * in some fashion.
1245  */
1246 int
1247 prefs_set_pref(char *prefarg)
1248 {
1249         guchar *p, *colonp;
1250         int ret;
1251
1252         /*
1253          * Set the counters of "mgcp.{tcp,udp}.port" entries we've
1254          * seen to values that keep us from trying to interpret tham
1255          * as "mgcp.{tcp,udp}.gateway_port" or "mgcp.{tcp,udp}.callagent_port",
1256          * as, from the command line, we have no way of guessing which
1257          * the user had in mind.
1258          */
1259         mgcp_tcp_port_count = -1;
1260         mgcp_udp_port_count = -1;
1261
1262         colonp = strchr(prefarg, ':');
1263         if (colonp == NULL)
1264                 return PREFS_SET_SYNTAX_ERR;
1265
1266         p = colonp;
1267         *p++ = '\0';
1268
1269         /*
1270          * Skip over any white space (there probably won't be any, but
1271          * as we allow it in the preferences file, we might as well
1272          * allow it here).
1273          */
1274         while (isspace(*p))
1275                 p++;
1276         if (*p == '\0') {
1277                 /*
1278                  * Put the colon back, so if our caller uses, in an
1279                  * error message, the string they passed us, the message
1280                  * looks correct.
1281                  */
1282                 *colonp = ':';
1283                 return PREFS_SET_SYNTAX_ERR;
1284         }
1285
1286         ret = set_pref(prefarg, p);
1287         *colonp = ':';  /* put the colon back */
1288         return ret;
1289 }
1290
1291 #define PRS_PRINT_FMT                    "print.format"
1292 #define PRS_PRINT_DEST                   "print.destination"
1293 #define PRS_PRINT_FILE                   "print.file"
1294 #define PRS_PRINT_CMD                    "print.command"
1295 #define PRS_COL_FMT                      "column.format"
1296 #define PRS_STREAM_CL_FG                 "stream.client.fg"
1297 #define PRS_STREAM_CL_BG                 "stream.client.bg"
1298 #define PRS_STREAM_SR_FG                 "stream.server.fg"
1299 #define PRS_STREAM_SR_BG                 "stream.server.bg"
1300 #define PRS_GUI_SCROLLBAR_ON_RIGHT       "gui.scrollbar_on_right"
1301 #define PRS_GUI_PLIST_SEL_BROWSE         "gui.packet_list_sel_browse"
1302 #define PRS_GUI_PTREE_SEL_BROWSE         "gui.protocol_tree_sel_browse"
1303 #define PRS_GUI_ALTERN_COLORS            "gui.tree_view_altern_colors"
1304 #define PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR "gui.filter_toolbar_show_in_statusbar"
1305 #define PRS_GUI_PTREE_LINE_STYLE         "gui.protocol_tree_line_style"
1306 #define PRS_GUI_PTREE_EXPANDER_STYLE     "gui.protocol_tree_expander_style"
1307 #define PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE "gui.hex_dump_highlight_style"
1308 #define PRS_GUI_FONT_NAME_1              "gui.font_name"
1309 #define PRS_GUI_FONT_NAME_2              "gui.gtk2.font_name"
1310 #define PRS_GUI_MARKED_FG                "gui.marked_frame.fg"
1311 #define PRS_GUI_MARKED_BG                "gui.marked_frame.bg"
1312 #define PRS_GUI_CONSOLE_OPEN             "gui.console_open"
1313 #define PRS_GUI_FILEOPEN_STYLE           "gui.fileopen.style"
1314 #define PRS_GUI_RECENT_COUNT_MAX         "gui.recent_files_count.max"
1315 #define PRS_GUI_FILEOPEN_DIR             "gui.fileopen.dir"
1316 #define PRS_GUI_FILEOPEN_REMEMBERED_DIR  "gui.fileopen.remembered_dir"
1317 #define PRS_GUI_ASK_UNSAVED              "gui.ask_unsaved"
1318 #define PRS_GUI_GEOMETRY_SAVE_POSITION   "gui.geometry.save.position"
1319 #define PRS_GUI_GEOMETRY_SAVE_SIZE       "gui.geometry.save.size"
1320 #define PRS_GUI_GEOMETRY_SAVE_MAXIMIZED  "gui.geometry.save.maximized"
1321 #define PRS_GUI_GEOMETRY_MAIN_X          "gui.geometry.main.x"
1322 #define PRS_GUI_GEOMETRY_MAIN_Y          "gui.geometry.main.y"
1323 #define PRS_GUI_GEOMETRY_MAIN_WIDTH      "gui.geometry.main.width"
1324 #define PRS_GUI_GEOMETRY_MAIN_HEIGHT     "gui.geometry.main.height"
1325 #define PRS_GUI_TOOLBAR_MAIN_SHOW        "gui.toolbar_main_show"
1326 #define PRS_GUI_TOOLBAR_MAIN_STYLE       "gui.toolbar_main_style"
1327 #define PRS_GUI_WEBBROWSER               "gui.webbrowser"
1328 #define PRS_GUI_LAYOUT_TYPE              "gui.layout_type"
1329 #define PRS_GUI_LAYOUT_CONTENT_1         "gui.layout_content_1"
1330 #define PRS_GUI_LAYOUT_CONTENT_2         "gui.layout_content_2"
1331 #define PRS_GUI_LAYOUT_CONTENT_3         "gui.layout_content_3"
1332
1333 /*
1334  * This applies to more than just captures, so it's not "capture.name_resolve";
1335  * "capture.name_resolve" is supported on input for backwards compatibility.
1336  *
1337  * It's not a preference for a particular part of Ethereal, it's used all
1338  * over the place, so its name doesn't have two components.
1339  */
1340 #define PRS_NAME_RESOLVE "name_resolve"
1341 #define PRS_NAME_RESOLVE_CONCURRENCY "name_resolve_concurrency"
1342 #define PRS_CAP_NAME_RESOLVE "capture.name_resolve"
1343
1344 /*  values for the capture dialog box */
1345 #define PRS_CAP_DEVICE        "capture.device"
1346 #define PRS_CAP_DEVICES_DESCR "capture.devices_descr"
1347 #define PRS_CAP_DEVICES_HIDE  "capture.devices_hide"
1348 #define PRS_CAP_PROM_MODE     "capture.prom_mode"
1349 #define PRS_CAP_REAL_TIME     "capture.real_time_update"
1350 #define PRS_CAP_AUTO_SCROLL   "capture.auto_scroll"
1351 #define PRS_CAP_SHOW_INFO     "capture.show_info"
1352
1353 #define RED_COMPONENT(x)   (guint16) (((((x) >> 16) & 0xff) * 65535 / 255))
1354 #define GREEN_COMPONENT(x) (guint16) (((((x) >>  8) & 0xff) * 65535 / 255))
1355 #define BLUE_COMPONENT(x)  (guint16) ( (((x)        & 0xff) * 65535 / 255))
1356
1357 static gchar *pr_formats[] = { "text", "postscript" };
1358 static gchar *pr_dests[]   = { "command", "file" };
1359
1360 typedef struct {
1361   char    letter;
1362   guint32 value;
1363 } name_resolve_opt_t;
1364
1365 static name_resolve_opt_t name_resolve_opt[] = {
1366   { 'm', RESOLV_MAC },
1367   { 'n', RESOLV_NETWORK },
1368   { 't', RESOLV_TRANSPORT },
1369   { 'C', RESOLV_CONCURRENT },
1370 };
1371
1372 #define N_NAME_RESOLVE_OPT      (sizeof name_resolve_opt / sizeof name_resolve_opt[0])
1373
1374 static char *
1375 name_resolve_to_string(guint32 name_resolve)
1376 {
1377   static char string[N_NAME_RESOLVE_OPT+1];
1378   char *p;
1379   unsigned int i;
1380   gboolean all_opts_set = TRUE;
1381
1382   if (name_resolve == RESOLV_NONE)
1383     return "FALSE";
1384   p = &string[0];
1385   for (i = 0; i < N_NAME_RESOLVE_OPT; i++) {
1386     if (name_resolve & name_resolve_opt[i].value)
1387       *p++ =  name_resolve_opt[i].letter;
1388     else
1389       all_opts_set = FALSE;
1390   }
1391   *p = '\0';
1392   if (all_opts_set)
1393     return "TRUE";
1394   return string;
1395 }
1396
1397 char
1398 string_to_name_resolve(char *string, guint32 *name_resolve)
1399 {
1400   char c;
1401   unsigned int i;
1402
1403   *name_resolve = 0;
1404   while ((c = *string++) != '\0') {
1405     for (i = 0; i < N_NAME_RESOLVE_OPT; i++) {
1406       if (c == name_resolve_opt[i].letter) {
1407         *name_resolve |= name_resolve_opt[i].value;
1408         break;
1409       }
1410     }
1411     if (i == N_NAME_RESOLVE_OPT) {
1412       /*
1413        * Unrecognized letter.
1414        */
1415       return c;
1416     }
1417   }
1418   return '\0';
1419 }
1420
1421 static int
1422 set_pref(gchar *pref_name, gchar *value)
1423 {
1424   GList    *col_l, *col_l_elt;
1425   gint      llen;
1426   fmt_data *cfmt;
1427   unsigned long int cval;
1428   guint    uval;
1429   gboolean bval;
1430   gint     enum_val;
1431   char     *p;
1432   gchar    *dotp, *last_dotp;
1433   module_t *module;
1434   pref_t   *pref;
1435   gboolean had_a_dot;
1436
1437   if (strcmp(pref_name, PRS_PRINT_FMT) == 0) {
1438     if (strcmp(value, pr_formats[PR_FMT_TEXT]) == 0) {
1439       prefs.pr_format = PR_FMT_TEXT;
1440     } else if (strcmp(value, pr_formats[PR_FMT_PS]) == 0) {
1441       prefs.pr_format = PR_FMT_PS;
1442     } else {
1443       return PREFS_SET_SYNTAX_ERR;
1444     }
1445   } else if (strcmp(pref_name, PRS_PRINT_DEST) == 0) {
1446     if (strcmp(value, pr_dests[PR_DEST_CMD]) == 0) {
1447       prefs.pr_dest = PR_DEST_CMD;
1448     } else if (strcmp(value, pr_dests[PR_DEST_FILE]) == 0) {
1449       prefs.pr_dest = PR_DEST_FILE;
1450     } else {
1451       return PREFS_SET_SYNTAX_ERR;
1452     }
1453   } else if (strcmp(pref_name, PRS_PRINT_FILE) == 0) {
1454     if (prefs.pr_file) g_free(prefs.pr_file);
1455     prefs.pr_file = g_strdup(value);
1456   } else if (strcmp(pref_name, PRS_PRINT_CMD) == 0) {
1457     if (prefs.pr_cmd) g_free(prefs.pr_cmd);
1458     prefs.pr_cmd = g_strdup(value);
1459   } else if (strcmp(pref_name, PRS_COL_FMT) == 0) {
1460     col_l = get_string_list(value);
1461     if (col_l == NULL)
1462       return PREFS_SET_SYNTAX_ERR;
1463     if ((g_list_length(col_l) % 2) != 0) {
1464       /* A title didn't have a matching format.  */
1465       clear_string_list(col_l);
1466       return PREFS_SET_SYNTAX_ERR;
1467     }
1468     /* Check to make sure all column formats are valid.  */
1469     col_l_elt = g_list_first(col_l);
1470     while(col_l_elt) {
1471       /* Make sure the title isn't empty.  */
1472       if (strcmp(col_l_elt->data, "") == 0) {
1473         /* It is.  */
1474         clear_string_list(col_l);
1475         return PREFS_SET_SYNTAX_ERR;
1476       }
1477
1478       /* Go past the title.  */
1479       col_l_elt = col_l_elt->next;
1480
1481       /* Check the format.  */
1482       if (get_column_format_from_str(col_l_elt->data) == -1) {
1483         /* It's not a valid column format.  */
1484         clear_string_list(col_l);
1485         return PREFS_SET_SYNTAX_ERR;
1486       }
1487
1488       /* Go past the format.  */
1489       col_l_elt = col_l_elt->next;
1490     }
1491     free_col_info(&prefs);
1492     prefs.col_list = NULL;
1493     llen             = g_list_length(col_l);
1494     prefs.num_cols   = llen / 2;
1495     col_l_elt = g_list_first(col_l);
1496     while(col_l_elt) {
1497       cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
1498       cfmt->title    = g_strdup(col_l_elt->data);
1499       col_l_elt      = col_l_elt->next;
1500       cfmt->fmt      = g_strdup(col_l_elt->data);
1501       col_l_elt      = col_l_elt->next;
1502       prefs.col_list = g_list_append(prefs.col_list, cfmt);
1503     }
1504     clear_string_list(col_l);
1505   } else if (strcmp(pref_name, PRS_STREAM_CL_FG) == 0) {
1506     cval = strtoul(value, NULL, 16);
1507     prefs.st_client_fg.pixel = 0;
1508     prefs.st_client_fg.red   = RED_COMPONENT(cval);
1509     prefs.st_client_fg.green = GREEN_COMPONENT(cval);
1510     prefs.st_client_fg.blue  = BLUE_COMPONENT(cval);
1511   } else if (strcmp(pref_name, PRS_STREAM_CL_BG) == 0) {
1512     cval = strtoul(value, NULL, 16);
1513     prefs.st_client_bg.pixel = 0;
1514     prefs.st_client_bg.red   = RED_COMPONENT(cval);
1515     prefs.st_client_bg.green = GREEN_COMPONENT(cval);
1516     prefs.st_client_bg.blue  = BLUE_COMPONENT(cval);
1517   } else if (strcmp(pref_name, PRS_STREAM_SR_FG) == 0) {
1518     cval = strtoul(value, NULL, 16);
1519     prefs.st_server_fg.pixel = 0;
1520     prefs.st_server_fg.red   = RED_COMPONENT(cval);
1521     prefs.st_server_fg.green = GREEN_COMPONENT(cval);
1522     prefs.st_server_fg.blue  = BLUE_COMPONENT(cval);
1523   } else if (strcmp(pref_name, PRS_STREAM_SR_BG) == 0) {
1524     cval = strtoul(value, NULL, 16);
1525     prefs.st_server_bg.pixel = 0;
1526     prefs.st_server_bg.red   = RED_COMPONENT(cval);
1527     prefs.st_server_bg.green = GREEN_COMPONENT(cval);
1528     prefs.st_server_bg.blue  = BLUE_COMPONENT(cval);
1529   } else if (strcmp(pref_name, PRS_GUI_SCROLLBAR_ON_RIGHT) == 0) {
1530     if (strcasecmp(value, "true") == 0) {
1531             prefs.gui_scrollbar_on_right = TRUE;
1532     }
1533     else {
1534             prefs.gui_scrollbar_on_right = FALSE;
1535     }
1536   } else if (strcmp(pref_name, PRS_GUI_PLIST_SEL_BROWSE) == 0) {
1537     if (strcasecmp(value, "true") == 0) {
1538             prefs.gui_plist_sel_browse = TRUE;
1539     }
1540     else {
1541             prefs.gui_plist_sel_browse = FALSE;
1542     }
1543   } else if (strcmp(pref_name, PRS_GUI_PTREE_SEL_BROWSE) == 0) {
1544     if (strcasecmp(value, "true") == 0) {
1545             prefs.gui_ptree_sel_browse = TRUE;
1546     }
1547     else {
1548             prefs.gui_ptree_sel_browse = FALSE;
1549     }
1550   } else if (strcmp(pref_name, PRS_GUI_ALTERN_COLORS) == 0) {
1551     if (strcasecmp(value, "true") == 0) {
1552             prefs.gui_altern_colors = TRUE;
1553     }
1554     else {
1555             prefs.gui_altern_colors = FALSE;
1556     }
1557   } else if (strcmp(pref_name, PRS_GUI_PTREE_LINE_STYLE) == 0) {
1558     prefs.gui_ptree_line_style =
1559         find_index_from_string_array(value, gui_ptree_line_style_text, 0);
1560   } else if (strcmp(pref_name, PRS_GUI_PTREE_EXPANDER_STYLE) == 0) {
1561     prefs.gui_ptree_expander_style =
1562         find_index_from_string_array(value, gui_ptree_expander_style_text, 1);
1563   } else if (strcmp(pref_name, PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE) == 0) {
1564     prefs.gui_hex_dump_highlight_style =
1565         find_index_from_string_array(value, gui_hex_dump_highlight_style_text, 1);
1566   } else if (strcmp(pref_name, PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR) == 0) {
1567     if (strcasecmp(value, "true") == 0) {
1568             prefs.filter_toolbar_show_in_statusbar = TRUE;
1569     }
1570     else {
1571             prefs.filter_toolbar_show_in_statusbar = FALSE;
1572     }
1573   } else if (strcmp(pref_name, PRS_GUI_TOOLBAR_MAIN_SHOW) == 0) {
1574     /* obsoleted by recent setting */
1575   } else if (strcmp(pref_name, PRS_GUI_TOOLBAR_MAIN_STYLE) == 0) {
1576     /* see toolbar.c for details, "icons only" is default */
1577         prefs.gui_toolbar_main_style =
1578             find_index_from_string_array(value, gui_toolbar_style_text,
1579                                      TB_STYLE_ICONS);
1580   } else if (strcmp(pref_name, PRS_GUI_FONT_NAME_1) == 0) {
1581     if (prefs.gui_font_name1 != NULL)
1582       g_free(prefs.gui_font_name1);
1583     prefs.gui_font_name1 = g_strdup(value);
1584   } else if (strcmp(pref_name, PRS_GUI_FONT_NAME_2) == 0) {
1585     if (prefs.gui_font_name2 != NULL)
1586       g_free(prefs.gui_font_name2);
1587     prefs.gui_font_name2 = g_strdup(value);
1588   } else if (strcmp(pref_name, PRS_GUI_MARKED_FG) == 0) {
1589     cval = strtoul(value, NULL, 16);
1590     prefs.gui_marked_fg.pixel = 0;
1591     prefs.gui_marked_fg.red   = RED_COMPONENT(cval);
1592     prefs.gui_marked_fg.green = GREEN_COMPONENT(cval);
1593     prefs.gui_marked_fg.blue  = BLUE_COMPONENT(cval);
1594   } else if (strcmp(pref_name, PRS_GUI_MARKED_BG) == 0) {
1595     cval = strtoul(value, NULL, 16);
1596     prefs.gui_marked_bg.pixel = 0;
1597     prefs.gui_marked_bg.red   = RED_COMPONENT(cval);
1598     prefs.gui_marked_bg.green = GREEN_COMPONENT(cval);
1599     prefs.gui_marked_bg.blue  = BLUE_COMPONENT(cval);
1600   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_POSITION) == 0) {
1601     if (strcasecmp(value, "true") == 0) {
1602             prefs.gui_geometry_save_position = TRUE;
1603     }
1604     else {
1605             prefs.gui_geometry_save_position = FALSE;
1606     }
1607   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_SIZE) == 0) {
1608     if (strcasecmp(value, "true") == 0) {
1609             prefs.gui_geometry_save_size = TRUE;
1610     }
1611     else {
1612             prefs.gui_geometry_save_size = FALSE;
1613     }
1614   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_MAXIMIZED) == 0) {
1615     if (strcasecmp(value, "true") == 0) {
1616             prefs.gui_geometry_save_maximized = TRUE;
1617     }
1618     else {
1619             prefs.gui_geometry_save_maximized = FALSE;
1620     }
1621   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_X) == 0) {         /* deprecated */
1622   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_Y) == 0) {         /* deprecated */
1623   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_WIDTH) == 0) {     /* deprecated */
1624   } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_HEIGHT) == 0) {    /* deprecated */
1625   } else if (strcmp(pref_name, PRS_GUI_CONSOLE_OPEN) == 0) {
1626     prefs.gui_console_open =
1627         find_index_from_string_array(value, gui_console_open_text,
1628                                      console_open_never);
1629   } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_STYLE) == 0) {
1630     prefs.gui_fileopen_style =
1631         find_index_from_string_array(value, gui_fileopen_style_text,
1632                                      FO_STYLE_LAST_OPENED);
1633   } else if (strcmp(pref_name, PRS_GUI_RECENT_COUNT_MAX) == 0) {
1634     prefs.gui_recent_files_count_max = strtoul(value, NULL, 10);
1635     if (prefs.gui_recent_files_count_max == 0) {
1636       /* We really should put up a dialog box here ... */
1637       prefs.gui_recent_files_count_max = 10;
1638     }
1639   } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_DIR) == 0) {
1640     if (prefs.gui_fileopen_dir != NULL)
1641       g_free(prefs.gui_fileopen_dir);
1642     prefs.gui_fileopen_dir = g_strdup(value);
1643   } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_REMEMBERED_DIR) == 0) { /* deprecated */
1644
1645   } else if (strcmp(pref_name, PRS_GUI_ASK_UNSAVED) == 0) {
1646     if (strcasecmp(value, "true") == 0) {
1647             prefs.gui_ask_unsaved = TRUE;
1648     }
1649     else {
1650             prefs.gui_ask_unsaved = FALSE;
1651     }
1652   } else if (strcmp(pref_name, PRS_GUI_WEBBROWSER) == 0) {
1653     g_free(prefs.gui_webbrowser);
1654     prefs.gui_webbrowser = g_strdup(value);
1655   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_TYPE) == 0) {
1656     prefs.gui_layout_type = strtoul(value, NULL, 10);
1657     if (prefs.gui_layout_type == layout_unused ||
1658         prefs.gui_layout_type >= layout_type_max) {
1659       /* XXX - report an error?  It's not a syntax error - we'd need to
1660          add a way of reporting a *semantic* error. */
1661       prefs.gui_layout_type = layout_type_5;
1662     }
1663   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_1) == 0) {
1664     prefs.gui_layout_content_1 =
1665         find_index_from_string_array(value, gui_layout_content_text, 0);
1666   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_2) == 0) {
1667     prefs.gui_layout_content_2 =
1668         find_index_from_string_array(value, gui_layout_content_text, 0);
1669   } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_3) == 0) {
1670     prefs.gui_layout_content_3 =
1671         find_index_from_string_array(value, gui_layout_content_text, 0);
1672
1673 /* handle the capture options */
1674   } else if (strcmp(pref_name, PRS_CAP_DEVICE) == 0) {
1675     if (prefs.capture_device != NULL)
1676       g_free(prefs.capture_device);
1677     prefs.capture_device = g_strdup(value);
1678   } else if (strcmp(pref_name, PRS_CAP_DEVICES_DESCR) == 0) {
1679     if (prefs.capture_devices_descr != NULL)
1680       g_free(prefs.capture_devices_descr);
1681     prefs.capture_devices_descr = g_strdup(value);
1682   } else if (strcmp(pref_name, PRS_CAP_DEVICES_HIDE) == 0) {
1683     if (prefs.capture_devices_hide != NULL)
1684       g_free(prefs.capture_devices_hide);
1685     prefs.capture_devices_hide = g_strdup(value);
1686   } else if (strcmp(pref_name, PRS_CAP_PROM_MODE) == 0) {
1687     prefs.capture_prom_mode = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
1688   } else if (strcmp(pref_name, PRS_CAP_REAL_TIME) == 0) {
1689     prefs.capture_real_time = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
1690   } else if (strcmp(pref_name, PRS_CAP_AUTO_SCROLL) == 0) {
1691     prefs.capture_auto_scroll = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
1692   } else if (strcmp(pref_name, PRS_CAP_SHOW_INFO) == 0) {
1693     prefs.capture_show_info = ((strcasecmp(value, "true") == 0)?TRUE:FALSE);
1694
1695 /* handle the global options */
1696   } else if (strcmp(pref_name, PRS_NAME_RESOLVE) == 0 ||
1697              strcmp(pref_name, PRS_CAP_NAME_RESOLVE) == 0) {
1698     /*
1699      * "TRUE" and "FALSE", for backwards compatibility, are synonyms for
1700      * RESOLV_ALL and RESOLV_NONE.
1701      *
1702      * Otherwise, we treat it as a list of name types we want to resolve.
1703      */
1704     if (strcasecmp(value, "true") == 0)
1705       prefs.name_resolve = RESOLV_ALL;
1706     else if (strcasecmp(value, "false") == 0)
1707       prefs.name_resolve = RESOLV_NONE;
1708     else {
1709       prefs.name_resolve = RESOLV_NONE; /* start out with none set */
1710       if (string_to_name_resolve(value, &prefs.name_resolve) != '\0')
1711         return PREFS_SET_SYNTAX_ERR;
1712     }
1713   } else if (strcmp(pref_name, PRS_NAME_RESOLVE_CONCURRENCY) == 0) {
1714     prefs.name_resolve_concurrency = strtol(value, NULL, 10);
1715   } else {
1716     /* To which module does this preference belong? */
1717     module = NULL;
1718     last_dotp = pref_name;
1719     had_a_dot = FALSE;
1720     while (!module) {
1721         dotp = strchr(last_dotp, '.');
1722         if (dotp == NULL) {
1723             if (had_a_dot) {
1724               /* no such module */
1725               return PREFS_SET_NO_SUCH_PREF;
1726             }
1727             else {
1728               /* no ".", so no module/name separator */
1729               return PREFS_SET_SYNTAX_ERR;
1730             }
1731         }
1732         else {
1733             had_a_dot = TRUE;
1734         }
1735         *dotp = '\0';           /* separate module and preference name */
1736         module = find_module(pref_name);
1737
1738         /*
1739          * XXX - "Diameter" rather than "diameter" was used in earlier
1740          * versions of Ethereal; if we didn't find the module, and its name
1741          * was "Diameter", look for "diameter" instead.
1742          *
1743          * In addition, the BEEP protocol used to be the BXXP protocol,
1744          * so if we didn't find the module, and its name was "bxxp",
1745          * look for "beep" instead.
1746          *
1747          * Also, the preferences for GTP v0 and v1 were combined under
1748          * a single "gtp" heading, and the preferences for SMPP were
1749          * moved to "smpp-gsm-sms" and then moved to "gsm-sms-ud".
1750          * However, SMPP now has its own preferences, so we just map
1751          * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below.
1752          */
1753         if (module == NULL) {
1754           if (strcmp(pref_name, "Diameter") == 0)
1755             module = find_module("diameter");
1756           else if (strcmp(pref_name, "bxxp") == 0)
1757             module = find_module("beep");
1758           else if (strcmp(pref_name, "gtpv0") == 0 ||
1759                    strcmp(pref_name, "gtpv1") == 0)
1760             module = find_module("gtp");
1761           else if (strcmp(pref_name, "smpp-gsm-sms") == 0)
1762             module = find_module("gsm-sms-ud");
1763         }
1764         *dotp = '.';            /* put the preference string back */
1765         dotp++;                 /* skip past separator to preference name */
1766         last_dotp = dotp;
1767     }
1768
1769     pref = find_preference(module, dotp);
1770
1771     if (pref == NULL) {
1772       if (strcmp(module->name, "mgcp") == 0) {
1773         /*
1774          * XXX - "mgcp.display raw text toggle" and "mgcp.display dissect tree"
1775          * rather than "mgcp.display_raw_text" and "mgcp.display_dissect_tree"
1776          * were used in earlier versions of Ethereal; if we didn't find the
1777          * preference, it was an MGCP preference, and its name was
1778          * "display raw text toggle" or "display dissect tree", look for
1779          * "display_raw_text" or "display_dissect_tree" instead.
1780          *
1781          * "mgcp.tcp.port" and "mgcp.udp.port" are harder to handle, as both
1782          * the gateway and callagent ports were given those names; we interpret
1783          * the first as "mgcp.{tcp,udp}.gateway_port" and the second as
1784          * "mgcp.{tcp,udp}.callagent_port", as that's the order in which
1785          * they were registered by the MCCP dissector and thus that's the
1786          * order in which they were written to the preferences file.  (If
1787          * we're not reading the preferences file, but are handling stuff
1788          * from a "-o" command-line option, we have no clue which the user
1789          * had in mind - they should have used "mgcp.{tcp,udp}.gateway_port"
1790          * or "mgcp.{tcp,udp}.callagent_port" instead.)
1791          */
1792         if (strcmp(dotp, "display raw text toggle") == 0)
1793           pref = find_preference(module, "display_raw_text");
1794         else if (strcmp(dotp, "display dissect tree") == 0)
1795           pref = find_preference(module, "display_dissect_tree");
1796         else if (strcmp(dotp, "tcp.port") == 0) {
1797           mgcp_tcp_port_count++;
1798           if (mgcp_tcp_port_count == 1) {
1799             /* It's the first one */
1800             pref = find_preference(module, "tcp.gateway_port");
1801           } else if (mgcp_tcp_port_count == 2) {
1802             /* It's the second one */
1803             pref = find_preference(module, "tcp.callagent_port");
1804           }
1805           /* Otherwise it's from the command line, and we don't bother
1806              mapping it. */
1807         } else if (strcmp(dotp, "udp.port") == 0) {
1808           mgcp_udp_port_count++;
1809           if (mgcp_udp_port_count == 1) {
1810             /* It's the first one */
1811             pref = find_preference(module, "udp.gateway_port");
1812           } else if (mgcp_udp_port_count == 2) {
1813             /* It's the second one */
1814             pref = find_preference(module, "udp.callagent_port");
1815           }
1816           /* Otherwise it's from the command line, and we don't bother
1817              mapping it. */
1818         }
1819       } else if (strcmp(module->name, "smb") == 0) {
1820         /* Handle old names for SMB preferences. */
1821         if (strcmp(dotp, "smb.trans.reassembly") == 0)
1822           pref = find_preference(module, "trans_reassembly");
1823         else if (strcmp(dotp, "smb.dcerpc.reassembly") == 0)
1824           pref = find_preference(module, "dcerpc_reassembly");
1825       } else if (strcmp(module->name, "ndmp") == 0) {
1826         /* Handle old names for NDMP preferences. */
1827         if (strcmp(dotp, "ndmp.desegment") == 0)
1828           pref = find_preference(module, "desegment");
1829       } else if (strcmp(module->name, "diameter") == 0) {
1830         /* Handle old names for Diameter preferences. */
1831         if (strcmp(dotp, "diameter.desegment") == 0)
1832           pref = find_preference(module, "desegment");
1833       } else if (strcmp(module->name, "pcli") == 0) {
1834         /* Handle old names for PCLI preferences. */
1835         if (strcmp(dotp, "pcli.udp_port") == 0)
1836           pref = find_preference(module, "udp_port");
1837       } else if (strcmp(module->name, "artnet") == 0) {
1838         /* Handle old names for ARTNET preferences. */
1839         if (strcmp(dotp, "artnet.udp_port") == 0)
1840           pref = find_preference(module, "udp_port");
1841       } else if (strcmp(module->name, "mapi") == 0) {
1842         /* Handle old names for MAPI preferences. */
1843         if (strcmp(dotp, "mapi_decrypt") == 0)
1844           pref = find_preference(module, "decrypt");
1845       } else if (strcmp(module->name, "fc") == 0) {
1846         /* Handle old names for Fibre Channel preferences. */
1847         if (strcmp(dotp, "reassemble_fc") == 0)
1848           pref = find_preference(module, "reassemble");
1849         else if (strcmp(dotp, "fc_max_frame_size") == 0)
1850           pref = find_preference(module, "max_frame_size");
1851       } else if (strcmp(module->name, "fcip") == 0) {
1852         /* Handle old names for Fibre Channel-over-IP preferences. */
1853         if (strcmp(dotp, "desegment_fcip_messages") == 0)
1854           pref = find_preference(module, "desegment");
1855         else if (strcmp(dotp, "fcip_port") == 0)
1856           pref = find_preference(module, "target_port");
1857       } else if (strcmp(module->name, "gtp") == 0) {
1858         /* Handle old names for GTP preferences. */
1859         if (strcmp(dotp, "gtpv0_port") == 0)
1860           pref = find_preference(module, "v0_port");
1861         else if (strcmp(dotp, "gtpv1c_port") == 0)
1862           pref = find_preference(module, "v1c_port");
1863         else if (strcmp(dotp, "gtpv1u_port") == 0)
1864           pref = find_preference(module, "v1u_port");
1865         else if (strcmp(dotp, "gtp_dissect_tpdu") == 0)
1866           pref = find_preference(module, "dissect_tpdu");
1867         else if (strcmp(dotp, "gtpv0_dissect_cdr_as") == 0)
1868           pref = find_preference(module, "v0_dissect_cdr_as");
1869         else if (strcmp(dotp, "gtpv0_check_etsi") == 0)
1870           pref = find_preference(module, "v0_check_etsi");
1871         else if (strcmp(dotp, "gtpv1_check_etsi") == 0)
1872           pref = find_preference(module, "v1_check_etsi");
1873       } else if (strcmp(module->name, "ip") == 0) {
1874         /* Handle old names for IP preferences. */
1875         if (strcmp(dotp, "ip_summary_in_tree") == 0)
1876           pref = find_preference(module, "summary_in_tree");
1877       } else if (strcmp(module->name, "iscsi") == 0) {
1878         /* Handle old names for iSCSI preferences. */
1879         if (strcmp(dotp, "iscsi_port") == 0)
1880           pref = find_preference(module, "target_port");
1881       } else if (strcmp(module->name, "lmp") == 0) {
1882         /* Handle old names for LMP preferences. */
1883         if (strcmp(dotp, "lmp_version") == 0)
1884           pref = find_preference(module, "version");
1885       } else if (strcmp(module->name, "mtp3") == 0) {
1886         /* Handle old names for MTP3 preferences. */
1887         if (strcmp(dotp, "mtp3_standard") == 0)
1888           pref = find_preference(module, "standard");
1889       } else if (strcmp(module->name, "nlm") == 0) {
1890         /* Handle old names for NLM preferences. */
1891         if (strcmp(dotp, "nlm_msg_res_matching") == 0)
1892           pref = find_preference(module, "msg_res_matching");
1893       } else if (strcmp(module->name, "ppp") == 0) {
1894         /* Handle old names for PPP preferences. */
1895         if (strcmp(dotp, "ppp_fcs") == 0)
1896           pref = find_preference(module, "fcs_type");
1897         else if (strcmp(dotp, "ppp_vj") == 0)
1898           pref = find_preference(module, "decompress_vj");
1899       } else if (strcmp(module->name, "rsvp") == 0) {
1900         /* Handle old names for RSVP preferences. */
1901         if (strcmp(dotp, "rsvp_process_bundle") == 0)
1902           pref = find_preference(module, "process_bundle");
1903       } else if (strcmp(module->name, "tcp") == 0) {
1904         /* Handle old names for TCP preferences. */
1905         if (strcmp(dotp, "tcp_summary_in_tree") == 0)
1906           pref = find_preference(module, "summary_in_tree");
1907         else if (strcmp(dotp, "tcp_analyze_sequence_numbers") == 0)
1908           pref = find_preference(module, "analyze_sequence_numbers");
1909         else if (strcmp(dotp, "tcp_relative_sequence_numbers") == 0)
1910           pref = find_preference(module, "relative_sequence_numbers");
1911       } else if (strcmp(module->name, "udp") == 0) {
1912         /* Handle old names for UDP preferences. */
1913         if (strcmp(dotp, "udp_summary_in_tree") == 0)
1914           pref = find_preference(module, "summary_in_tree");
1915       } else if (strcmp(module->name, "ndps") == 0) {
1916         /* Handle old names for NDPS preferences. */
1917         if (strcmp(dotp, "desegment_ndps") == 0)
1918           pref = find_preference(module, "desegment_tcp");
1919       } else if (strcmp(module->name, "http") == 0) {
1920         /* Handle old names for HTTP preferences. */
1921         if (strcmp(dotp, "desegment_http_headers") == 0)
1922           pref = find_preference(module, "desegment_headers");
1923         else if (strcmp(dotp, "desegment_http_body") == 0)
1924           pref = find_preference(module, "desegment_body");
1925       } else if (strcmp(module->name, "smpp") == 0) {
1926         /* Handle preferences that moved from SMPP. */
1927         module_t *new_module = find_module("gsm-sms-ud");
1928         if (strcmp(dotp, "port_number_udh_means_wsp") == 0)
1929           pref = find_preference(new_module, "port_number_udh_means_wsp");
1930         else if (strcmp(dotp, "try_dissect_1st_fragment") == 0)
1931           pref = find_preference(new_module, "try_dissect_1st_fragment");
1932       }
1933     }
1934     if (pref == NULL)
1935       return PREFS_SET_NO_SUCH_PREF;    /* no such preference */
1936
1937     switch (pref->type) {
1938
1939     case PREF_UINT:
1940       uval = strtoul(value, &p, pref->info.base);
1941       if (p == value || *p != '\0')
1942         return PREFS_SET_SYNTAX_ERR;    /* number was bad */
1943       if (*pref->varp.uint != uval) {
1944         module->prefs_changed = TRUE;
1945         *pref->varp.uint = uval;
1946       }
1947       break;
1948
1949     case PREF_BOOL:
1950       /* XXX - give an error if it's neither "true" nor "false"? */
1951       if (strcasecmp(value, "true") == 0)
1952         bval = TRUE;
1953       else
1954         bval = FALSE;
1955       if (*pref->varp.boolp != bval) {
1956         module->prefs_changed = TRUE;
1957         *pref->varp.boolp = bval;
1958       }
1959       break;
1960
1961     case PREF_ENUM:
1962       /* XXX - give an error if it doesn't match? */
1963       enum_val = find_val_for_string(value,
1964                                         pref->info.enum_info.enumvals, 1);
1965       if (*pref->varp.enump != enum_val) {
1966         module->prefs_changed = TRUE;
1967         *pref->varp.enump = enum_val;
1968       }
1969       break;
1970
1971     case PREF_STRING:
1972       if (strcmp(*pref->varp.string, value) != 0) {
1973         module->prefs_changed = TRUE;
1974         g_free(*pref->varp.string);
1975         *pref->varp.string = g_strdup(value);
1976       }
1977       break;
1978
1979     case PREF_OBSOLETE:
1980       return PREFS_SET_OBSOLETE;        /* no such preference any more */
1981     }
1982   }
1983
1984   return PREFS_SET_OK;
1985 }
1986
1987 typedef struct {
1988         module_t *module;
1989         FILE    *pf;
1990 } write_pref_arg_t;
1991
1992 /*
1993  * Write out a single preference.
1994  */
1995 static void
1996 write_pref(gpointer data, gpointer user_data)
1997 {
1998         pref_t *pref = data;
1999         write_pref_arg_t *arg = user_data;
2000         const enum_val_t *enum_valp;
2001         const char *val_string;
2002
2003         if (pref->type == PREF_OBSOLETE) {
2004                 /*
2005                  * This preference is no longer supported; it's not a
2006                  * real preference, so we don't write it out (i.e., we
2007                  * treat it as if it weren't found in the list of
2008                  * preferences, and we weren't called in the first place).
2009                  */
2010                 return;
2011         }
2012
2013         fprintf(arg->pf, "\n# %s\n", pref->description);
2014
2015         switch (pref->type) {
2016
2017         case PREF_UINT:
2018                 switch (pref->info.base) {
2019
2020                 case 10:
2021                         fprintf(arg->pf, "# A decimal number.\n");
2022                         fprintf(arg->pf, "%s.%s: %u\n", arg->module->name,
2023                             pref->name, *pref->varp.uint);
2024                         break;
2025
2026                 case 8:
2027                         fprintf(arg->pf, "# An octal number.\n");
2028                         fprintf(arg->pf, "%s.%s: %#o\n", arg->module->name,
2029                             pref->name, *pref->varp.uint);
2030                         break;
2031
2032                 case 16:
2033                         fprintf(arg->pf, "# A hexadecimal number.\n");
2034                         fprintf(arg->pf, "%s.%s: %#x\n", arg->module->name,
2035                             pref->name, *pref->varp.uint);
2036                         break;
2037                 }
2038                 break;
2039
2040         case PREF_BOOL:
2041                 fprintf(arg->pf, "# TRUE or FALSE (case-insensitive).\n");
2042                 fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
2043                     *pref->varp.boolp ? "TRUE" : "FALSE");
2044                 break;
2045
2046         case PREF_ENUM:
2047                 /*
2048                  * For now, we save the "description" value, so that if we
2049                  * save the preferences older versions of Ethereal can at
2050                  * least read preferences that they supported; we support
2051                  * either the short name or the description when reading
2052                  * the preferences file or a "-o" option.
2053                  */
2054                 fprintf(arg->pf, "# One of: ");
2055                 enum_valp = pref->info.enum_info.enumvals;
2056                 val_string = NULL;
2057                 while (enum_valp->name != NULL) {
2058                         if (enum_valp->value == *pref->varp.enump)
2059                                 val_string = enum_valp->description;
2060                         fprintf(arg->pf, "%s", enum_valp->description);
2061                         enum_valp++;
2062                         if (enum_valp->name == NULL)
2063                                 fprintf(arg->pf, "\n");
2064                         else
2065                                 fprintf(arg->pf, ", ");
2066                 }
2067                 fprintf(arg->pf, "# (case-insensitive).\n");
2068                 fprintf(arg->pf, "%s.%s: %s\n", arg->module->name,
2069                     pref->name, val_string);
2070                 break;
2071
2072         case PREF_STRING:
2073                 fprintf(arg->pf, "# A string.\n");
2074                 fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name,
2075                     *pref->varp.string);
2076                 break;
2077
2078         case PREF_OBSOLETE:
2079                 g_assert_not_reached();
2080                 break;
2081         }
2082 }
2083
2084 static void
2085 write_module_prefs(gpointer data, gpointer user_data)
2086 {
2087         write_pref_arg_t arg;
2088
2089         arg.module = data;
2090         arg.pf = user_data;
2091         g_list_foreach(arg.module->prefs, write_pref, &arg);
2092 }
2093
2094 /* Write out "prefs" to the user's preferences file, and return 0.
2095
2096    If we got an error, stuff a pointer to the path of the preferences file
2097    into "*pf_path_return", and return the errno. */
2098 int
2099 write_prefs(char **pf_path_return)
2100 {
2101   char        *pf_path;
2102   FILE        *pf;
2103   GList       *clp, *col_l;
2104   fmt_data    *cfmt;
2105
2106   /* To do:
2107    * - Split output lines longer than MAX_VAL_LEN
2108    * - Create a function for the preference directory check/creation
2109    *   so that duplication can be avoided with filter.c
2110    */
2111
2112   pf_path = get_persconffile_path(PF_NAME, TRUE);
2113   if ((pf = fopen(pf_path, "w")) == NULL) {
2114     *pf_path_return = pf_path;
2115     return errno;
2116   }
2117
2118   fputs("# Configuration file for Ethereal " VERSION ".\n"
2119     "#\n"
2120     "# This file is regenerated each time preferences are saved within\n"
2121     "# Ethereal.  Making manual changes should be safe, however.\n", pf);
2122
2123   fprintf (pf, "\n######## User Interface ########\n");
2124   
2125   fprintf(pf, "\n# Vertical scrollbars should be on right side?\n");
2126   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2127   fprintf(pf, PRS_GUI_SCROLLBAR_ON_RIGHT ": %s\n",
2128                   prefs.gui_scrollbar_on_right == TRUE ? "TRUE" : "FALSE");
2129
2130   fprintf(pf, "\n# Packet-list selection bar can be used to browse w/o selecting?\n");
2131   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2132   fprintf(pf, PRS_GUI_PLIST_SEL_BROWSE ": %s\n",
2133                   prefs.gui_plist_sel_browse == TRUE ? "TRUE" : "FALSE");
2134
2135   fprintf(pf, "\n# Protocol-tree selection bar can be used to browse w/o selecting?\n");
2136   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2137   fprintf(pf, PRS_GUI_PTREE_SEL_BROWSE ": %s\n",
2138                   prefs.gui_ptree_sel_browse == TRUE ? "TRUE" : "FALSE");
2139
2140   fprintf(pf, "\n# Alternating colors in TreeViews?\n");
2141   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2142   fprintf(pf, PRS_GUI_ALTERN_COLORS ": %s\n",
2143                   prefs.gui_altern_colors == TRUE ? "TRUE" : "FALSE");
2144
2145   fprintf(pf, "\n# Place filter toolbar inside the statusbar?\n");
2146   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2147   fprintf(pf, PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR ": %s\n",
2148                  prefs.filter_toolbar_show_in_statusbar == TRUE ? "TRUE" : "FALSE");
2149
2150   fprintf(pf, "\n# Protocol-tree line style.\n");
2151   fprintf(pf, "# One of: NONE, SOLID, DOTTED, TABBED\n");
2152   fprintf(pf, PRS_GUI_PTREE_LINE_STYLE ": %s\n",
2153           gui_ptree_line_style_text[prefs.gui_ptree_line_style]);
2154
2155   fprintf(pf, "\n# Protocol-tree expander style.\n");
2156   fprintf(pf, "# One of: NONE, SQUARE, TRIANGLE, CIRCULAR\n");
2157   fprintf(pf, PRS_GUI_PTREE_EXPANDER_STYLE ": %s\n",
2158                   gui_ptree_expander_style_text[prefs.gui_ptree_expander_style]);
2159
2160   fprintf(pf, "\n# Hex dump highlight style.\n");
2161   fprintf(pf, "# One of: BOLD, INVERSE\n");
2162   fprintf(pf, PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE ": %s\n",
2163                   gui_hex_dump_highlight_style_text[prefs.gui_hex_dump_highlight_style]);
2164
2165   fprintf(pf, "\n# Main Toolbar style.\n");
2166   fprintf(pf, "# One of: ICONS, TEXT, BOTH\n");
2167   fprintf(pf, PRS_GUI_TOOLBAR_MAIN_STYLE ": %s\n",
2168                   gui_toolbar_style_text[prefs.gui_toolbar_main_style]);
2169
2170   fprintf(pf, "\n# Save window position at exit?\n");
2171   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2172   fprintf(pf, PRS_GUI_GEOMETRY_SAVE_POSITION ": %s\n",
2173                   prefs.gui_geometry_save_position == TRUE ? "TRUE" : "FALSE");
2174
2175   fprintf(pf, "\n# Save window size at exit?\n");
2176   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2177   fprintf(pf, PRS_GUI_GEOMETRY_SAVE_SIZE ": %s\n",
2178                   prefs.gui_geometry_save_size == TRUE ? "TRUE" : "FALSE");
2179                   
2180   fprintf(pf, "\n# Save window maximized state at exit (GTK2 only)?\n");
2181   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2182   fprintf(pf, PRS_GUI_GEOMETRY_SAVE_MAXIMIZED ": %s\n",
2183                   prefs.gui_geometry_save_maximized == TRUE ? "TRUE" : "FALSE");
2184                   
2185   fprintf(pf, "\n# Open a console window (WIN32 only)?\n");
2186   fprintf(pf, "# One of: NEVER, AUTOMATIC, ALWAYS\n");
2187   fprintf(pf, PRS_GUI_CONSOLE_OPEN ": %s\n",
2188                   gui_console_open_text[prefs.gui_console_open]);
2189
2190   fprintf(pf, "\n# Where to start the File Open dialog box.\n");
2191   fprintf(pf, "# One of: LAST_OPENED, SPECIFIED\n");
2192   fprintf(pf, PRS_GUI_FILEOPEN_STYLE ": %s\n",
2193                   gui_fileopen_style_text[prefs.gui_fileopen_style]);
2194
2195   fprintf(pf, PRS_GUI_RECENT_COUNT_MAX ": %d\n",
2196                   prefs.gui_recent_files_count_max);
2197
2198   if (prefs.gui_fileopen_dir != NULL) {
2199     fprintf(pf, "\n# Directory to start in when opening File Open dialog.\n");
2200     fprintf(pf, PRS_GUI_FILEOPEN_DIR ": %s\n",
2201                   prefs.gui_fileopen_dir);
2202   }
2203                   
2204   fprintf(pf, "\n# Ask to save unsaved capture files?\n");
2205   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2206   fprintf(pf, PRS_GUI_ASK_UNSAVED ": %s\n",
2207                   prefs.gui_ask_unsaved == TRUE ? "TRUE" : "FALSE");                  
2208
2209   fprintf(pf, "\n# The path to the webbrowser.\n");
2210   fprintf(pf, "# Ex: mozilla %%s\n");
2211   fprintf(pf, PRS_GUI_WEBBROWSER ": %s\n", prefs.gui_webbrowser);
2212
2213   fprintf (pf, "\n######## User Interface: Layout ########\n");
2214
2215   fprintf(pf, "\n# Layout type (1-6).\n");
2216   fprintf(pf, PRS_GUI_LAYOUT_TYPE ": %d\n",
2217                   prefs.gui_layout_type);
2218
2219   fprintf(pf, "\n# Layout content of the panes (1-3).\n");
2220   fprintf(pf, "# One of: NONE, PLIST, PDETAILS, PBYTES\n");
2221   fprintf(pf, PRS_GUI_LAYOUT_CONTENT_1 ": %s\n",
2222                   gui_layout_content_text[prefs.gui_layout_content_1]);
2223   fprintf(pf, PRS_GUI_LAYOUT_CONTENT_2 ": %s\n",
2224                   gui_layout_content_text[prefs.gui_layout_content_2]);
2225   fprintf(pf, PRS_GUI_LAYOUT_CONTENT_3 ": %s\n",
2226                   gui_layout_content_text[prefs.gui_layout_content_3]);
2227
2228   fprintf (pf, "\n######## User Interface: Columns ########\n");
2229   
2230   clp = prefs.col_list;
2231   col_l = NULL;
2232   while (clp) {
2233     cfmt = (fmt_data *) clp->data;
2234     col_l = g_list_append(col_l, cfmt->title);
2235     col_l = g_list_append(col_l, cfmt->fmt);
2236     clp = clp->next;
2237   }
2238   fprintf (pf, "\n# Packet list column format.\n");
2239   fprintf (pf, "# Each pair of strings consists of a column title and its format.\n");
2240   fprintf (pf, "%s: %s\n", PRS_COL_FMT, put_string_list(col_l));
2241   /* This frees the list of strings, but not the strings to which it
2242      refers; that's what we want, as we haven't copied those strings,
2243      we just referred to them.  */
2244   g_list_free(col_l);
2245
2246   fprintf (pf, "\n######## User Interface: Font ########\n");
2247
2248   fprintf(pf, "\n# Font name for packet list, protocol tree, and hex dump panes (GTK version 1).\n");
2249   fprintf(pf, PRS_GUI_FONT_NAME_1 ": %s\n", prefs.gui_font_name1);
2250
2251   fprintf(pf, "\n# Font name for packet list, protocol tree, and hex dump panes (GTK version 2).\n");
2252   fprintf(pf, PRS_GUI_FONT_NAME_2 ": %s\n", prefs.gui_font_name2);
2253
2254   fprintf (pf, "\n######## User Interface: Colors ########\n");
2255
2256   fprintf (pf, "\n# Color preferences for a marked frame.\n");
2257   fprintf (pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n");
2258   fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_MARKED_FG,
2259     (prefs.gui_marked_fg.red * 255 / 65535),
2260     (prefs.gui_marked_fg.green * 255 / 65535),
2261     (prefs.gui_marked_fg.blue * 255 / 65535));
2262   fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_MARKED_BG,
2263     (prefs.gui_marked_bg.red * 255 / 65535),
2264     (prefs.gui_marked_bg.green * 255 / 65535),
2265     (prefs.gui_marked_bg.blue * 255 / 65535));
2266
2267   fprintf (pf, "\n# TCP stream window color preferences.\n");
2268   fprintf (pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n");
2269   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_CL_FG,
2270     (prefs.st_client_fg.red * 255 / 65535),
2271     (prefs.st_client_fg.green * 255 / 65535),
2272     (prefs.st_client_fg.blue * 255 / 65535));
2273   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_CL_BG,
2274     (prefs.st_client_bg.red * 255 / 65535),
2275     (prefs.st_client_bg.green * 255 / 65535),
2276     (prefs.st_client_bg.blue * 255 / 65535));
2277   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_SR_FG,
2278     (prefs.st_server_fg.red * 255 / 65535),
2279     (prefs.st_server_fg.green * 255 / 65535),
2280     (prefs.st_server_fg.blue * 255 / 65535));
2281   fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_SR_BG,
2282     (prefs.st_server_bg.red * 255 / 65535),
2283     (prefs.st_server_bg.green * 255 / 65535),
2284     (prefs.st_server_bg.blue * 255 / 65535));
2285
2286   fprintf(pf, "\n####### Capture ########\n");
2287   
2288   if (prefs.capture_device != NULL) {
2289     fprintf(pf, "\n# Default capture device\n");
2290     fprintf(pf, PRS_CAP_DEVICE ": %s\n", prefs.capture_device);
2291   }
2292
2293   if (prefs.capture_devices_descr != NULL) {
2294     fprintf(pf, "\n# Interface descriptions.\n");
2295     fprintf(pf, "# Ex: eth0(eth0 descr),eth1(eth1 descr),...\n");
2296     fprintf(pf, PRS_CAP_DEVICES_DESCR ": %s\n", prefs.capture_devices_descr);
2297   }
2298
2299   if (prefs.capture_devices_hide != NULL) {
2300     fprintf(pf, "\n# Hide interface?\n");
2301     fprintf(pf, "# Ex: eth0,eth3,...\n");
2302     fprintf(pf, PRS_CAP_DEVICES_HIDE ": %s\n", prefs.capture_devices_hide);
2303   }
2304
2305   fprintf(pf, "\n# Capture in promiscuous mode?\n");
2306   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2307   fprintf(pf, PRS_CAP_PROM_MODE ": %s\n",
2308                   prefs.capture_prom_mode == TRUE ? "TRUE" : "FALSE");
2309
2310   fprintf(pf, "\n# Update packet list in real time during capture?\n");
2311   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2312   fprintf(pf, PRS_CAP_REAL_TIME ": %s\n",
2313                   prefs.capture_real_time == TRUE ? "TRUE" : "FALSE");
2314
2315   fprintf(pf, "\n# Scroll packet list during capture?\n");
2316   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2317   fprintf(pf, PRS_CAP_AUTO_SCROLL ": %s\n",
2318                   prefs.capture_auto_scroll == TRUE ? "TRUE" : "FALSE");
2319
2320   fprintf(pf, "\n# Show capture info dialog while capturing?\n");
2321   fprintf(pf, "# TRUE or FALSE (case-insensitive).\n");
2322   fprintf(pf, PRS_CAP_SHOW_INFO ": %s\n",
2323                   prefs.capture_show_info == TRUE ? "TRUE" : "FALSE");
2324
2325   fprintf (pf, "\n######## Printing ########\n");
2326
2327   fprintf (pf, "\n# Can be one of \"text\" or \"postscript\".\n"
2328     "print.format: %s\n", pr_formats[prefs.pr_format]);
2329
2330   fprintf (pf, "\n# Can be one of \"command\" or \"file\".\n"
2331     "print.destination: %s\n", pr_dests[prefs.pr_dest]);
2332
2333   fprintf (pf, "\n# This is the file that gets written to when the "
2334     "destination is set to \"file\"\n"
2335     "%s: %s\n", PRS_PRINT_FILE, prefs.pr_file);
2336
2337   fprintf (pf, "\n# Output gets piped to this command when the destination "
2338     "is set to \"command\"\n"
2339     "%s: %s\n", PRS_PRINT_CMD, prefs.pr_cmd);
2340
2341   fprintf(pf, "\n####### Name Resolution ########\n");
2342   
2343   fprintf(pf, "\n# Resolve addresses to names?\n");
2344   fprintf(pf, "# TRUE or FALSE (case-insensitive), or a list of address types to resolve.\n");
2345   fprintf(pf, PRS_NAME_RESOLVE ": %s\n",
2346                   name_resolve_to_string(prefs.name_resolve));
2347
2348   fprintf(pf, "\n# Name resolution concurrency.\n");
2349   fprintf(pf, "# A decimal number.\n");
2350   fprintf(pf, PRS_NAME_RESOLVE_CONCURRENCY ": %d\n",
2351                   prefs.name_resolve_concurrency);
2352
2353   fprintf(pf, "\n####### Protocols ########\n");
2354
2355   g_list_foreach(modules, write_module_prefs, pf);
2356
2357   fclose(pf);
2358
2359   /* XXX - catch I/O errors (e.g. "ran out of disk space") and return
2360      an error indication, or maybe write to a new preferences file and
2361      rename that file on top of the old one only if there are not I/O
2362      errors. */
2363   return 0;
2364 }
2365
2366 /* Copy a set of preferences. */
2367 void
2368 copy_prefs(e_prefs *dest, e_prefs *src)
2369 {
2370   fmt_data *src_cfmt, *dest_cfmt;
2371   GList *entry;
2372
2373   dest->pr_format = src->pr_format;
2374   dest->pr_dest = src->pr_dest;
2375   dest->pr_file = g_strdup(src->pr_file);
2376   dest->pr_cmd = g_strdup(src->pr_cmd);
2377   dest->col_list = NULL;
2378   for (entry = src->col_list; entry != NULL; entry = g_list_next(entry)) {
2379     src_cfmt = entry->data;
2380     dest_cfmt = (fmt_data *) g_malloc(sizeof(fmt_data));
2381     dest_cfmt->title = g_strdup(src_cfmt->title);
2382     dest_cfmt->fmt = g_strdup(src_cfmt->fmt);
2383     dest->col_list = g_list_append(dest->col_list, dest_cfmt);
2384   }
2385   dest->num_cols = src->num_cols;
2386   dest->st_client_fg = src->st_client_fg;
2387   dest->st_client_bg = src->st_client_bg;
2388   dest->st_server_fg = src->st_server_fg;
2389   dest->st_server_bg = src->st_server_bg;
2390   dest->gui_scrollbar_on_right = src->gui_scrollbar_on_right;
2391   dest->gui_plist_sel_browse = src->gui_plist_sel_browse;
2392   dest->gui_ptree_sel_browse = src->gui_ptree_sel_browse;
2393   dest->gui_altern_colors = src->gui_altern_colors;
2394   dest->filter_toolbar_show_in_statusbar = src->filter_toolbar_show_in_statusbar;
2395   dest->gui_ptree_line_style = src->gui_ptree_line_style;
2396   dest->gui_ptree_expander_style = src->gui_ptree_expander_style;
2397   dest->gui_hex_dump_highlight_style = src->gui_hex_dump_highlight_style;
2398   dest->gui_toolbar_main_style = src->gui_toolbar_main_style;
2399   dest->gui_fileopen_dir = g_strdup(src->gui_fileopen_dir);
2400   dest->gui_console_open = src->gui_console_open;
2401   dest->gui_fileopen_style = src->gui_fileopen_style;
2402   dest->gui_ask_unsaved = src->gui_ask_unsaved;
2403   dest->gui_layout_type = src->gui_layout_type;
2404   dest->gui_layout_content_1 = src->gui_layout_content_1;
2405   dest->gui_layout_content_2 = src->gui_layout_content_2;
2406   dest->gui_layout_content_3 = src->gui_layout_content_3;
2407   dest->gui_font_name1 = g_strdup(src->gui_font_name1);
2408   dest->gui_font_name2 = g_strdup(src->gui_font_name2);
2409   dest->gui_marked_fg = src->gui_marked_fg;
2410   dest->gui_marked_bg = src->gui_marked_bg;
2411   dest->gui_geometry_save_position = src->gui_geometry_save_position;
2412   dest->gui_geometry_save_size = src->gui_geometry_save_size;
2413   dest->gui_geometry_save_maximized = src->gui_geometry_save_maximized;
2414   dest->gui_webbrowser = g_strdup(src->gui_webbrowser);
2415 /*  values for the capture dialog box */
2416   dest->capture_device = g_strdup(src->capture_device);
2417   dest->capture_devices_descr = g_strdup(src->capture_devices_descr);
2418   dest->capture_devices_hide = g_strdup(src->capture_devices_hide);
2419   dest->capture_prom_mode = src->capture_prom_mode;
2420   dest->capture_real_time = src->capture_real_time;
2421   dest->capture_auto_scroll = src->capture_auto_scroll;
2422   dest->capture_show_info = src->capture_show_info;
2423   dest->name_resolve = src->name_resolve;
2424   dest->name_resolve_concurrency = src->name_resolve_concurrency;
2425
2426 }
2427
2428 /* Free a set of preferences. */
2429 void
2430 free_prefs(e_prefs *pr)
2431 {
2432   if (pr->pr_file != NULL) {
2433     g_free(pr->pr_file);
2434     pr->pr_file = NULL;
2435   }
2436   if (pr->pr_cmd != NULL) {
2437     g_free(pr->pr_cmd);
2438     pr->pr_cmd = NULL;
2439   }
2440   free_col_info(pr);
2441   if (pr->gui_font_name1 != NULL) {
2442     g_free(pr->gui_font_name1);
2443     pr->gui_font_name1 = NULL;
2444   }
2445   if (pr->gui_font_name2 != NULL) {
2446     g_free(pr->gui_font_name2);
2447     pr->gui_font_name2 = NULL;
2448   }
2449   if (pr->gui_fileopen_dir != NULL) {
2450     g_free(pr->gui_fileopen_dir);
2451     pr->gui_fileopen_dir = NULL;
2452   }
2453   g_free(pr->gui_webbrowser);
2454   pr->gui_webbrowser = NULL;
2455   if (pr->capture_device != NULL) {
2456     g_free(pr->capture_device);
2457     pr->capture_device = NULL;
2458   }
2459   if (pr->capture_devices_descr != NULL) {
2460     g_free(pr->capture_devices_descr);
2461     pr->capture_devices_descr = NULL;
2462   }
2463   if (pr->capture_devices_hide != NULL) {
2464     g_free(pr->capture_devices_hide);
2465     pr->capture_devices_hide = NULL;
2466   }
2467 }
2468
2469 static void
2470 free_col_info(e_prefs *pr)
2471 {
2472   fmt_data *cfmt;
2473
2474   while (pr->col_list != NULL) {
2475     cfmt = pr->col_list->data;
2476     g_free(cfmt->title);
2477     g_free(cfmt->fmt);
2478     g_free(cfmt);
2479     pr->col_list = g_list_remove_link(pr->col_list, pr->col_list);
2480   }
2481   g_list_free(pr->col_list);
2482   pr->col_list = NULL;
2483 }