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