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