/epan/prefs.c
C | 4657 lines | 3812 code | 369 blank | 476 comment | 223 complexity | 9b7d8c0299a094ae5c3b50a131d948b7 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /* prefs.c
- * Routines for handling preferences
- *
- * $Id$
- *
- * Wireshark - Network traffic analyzer
- * By Gerald Combs <gerald@wireshark.org>
- * Copyright 1998 Gerald Combs
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #include "config.h"
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <glib.h>
- #include <stdio.h>
- #include <epan/filesystem.h>
- #include <epan/address.h>
- #include <epan/addr_resolv.h>
- #include <epan/oids.h>
- #ifdef HAVE_GEOIP
- #include <epan/geoip_db.h>
- #endif
- #include <epan/packet.h>
- #include <epan/prefs.h>
- #include <epan/proto.h>
- #include <epan/strutil.h>
- #include <epan/column.h>
- #include "print.h"
- #include <wsutil/file_util.h>
- #include <epan/prefs-int.h>
- #include <epan/uat-int.h>
- #include "epan/filter_expressions.h"
- #include "epan/wmem/wmem.h"
- /* Internal functions */
- static module_t *find_subtree(module_t *parent, const char *tilte);
- static module_t *prefs_register_module_or_subtree(module_t *parent,
- const char *name, const char *title, const char *description, gboolean is_subtree,
- void (*apply_cb)(void), gboolean use_gui);
- static prefs_set_pref_e set_pref(gchar*, const gchar*, void *, gboolean);
- static char * join_string_list(GList *);
- static void free_col_info(GList *);
- static void pre_init_prefs(void);
- static gboolean prefs_is_column_visible(const gchar *cols_hidden, fmt_data *cfmt);
- static gboolean parse_column_format(fmt_data *cfmt, const char *fmt);
- static void try_convert_to_custom_column(gpointer *el_data);
- #define PF_NAME "preferences"
- #define OLD_GPF_NAME "wireshark.conf" /* old name for global preferences file */
- static gboolean prefs_initialized = FALSE;
- static gboolean prefs_pre_initialized = FALSE;
- static gchar *gpf_path = NULL;
- static gchar *cols_hidden_list = NULL;
- /*
- * XXX - variables to allow us to attempt to interpret the first
- * "mgcp.{tcp,udp}.port" in a preferences file as
- * "mgcp.{tcp,udp}.gateway_port" and the second as
- * "mgcp.{tcp,udp}.callagent_port".
- */
- static int mgcp_tcp_port_count;
- static int mgcp_udp_port_count;
- e_prefs prefs;
- static const enum_val_t gui_ptree_line_style[] = {
- {"NONE", "NONE", 0},
- {"SOLID", "SOLID", 1},
- {"DOTTED", "DOTTED", 2},
- {"TABBED", "TABBED", 3},
- {NULL, NULL, -1}
- };
- static const enum_val_t gui_ptree_expander_style[] = {
- {"NONE", "NONE", 0},
- {"SQUARE", "SQUARE", 1},
- {"TRIANGLE", "TRIANGLE", 2},
- {"CIRCULAR", "CIRCULAR", 3},
- {NULL, NULL, -1}
- };
- static const enum_val_t gui_hex_dump_highlight_style[] = {
- {"BOLD", "BOLD", 0},
- {"INVERSE", "INVERSE", 1},
- {NULL, NULL, -1}
- };
- static const enum_val_t gui_console_open_type[] = {
- {"NEVER", "NEVER", console_open_never},
- {"AUTOMATIC", "AUTOMATIC", console_open_auto},
- {"ALWAYS", "ALWAYS", console_open_always},
- {NULL, NULL, -1}
- };
- static const enum_val_t gui_version_placement_type[] = {
- {"WELCOME", "WELCOME", version_welcome_only},
- {"TITLE", "TITLE", version_title_only},
- {"BOTH", "BOTH", version_both},
- {"NEITHER", "NEITHER", version_neither},
- {NULL, NULL, -1}
- };
- static const enum_val_t gui_fileopen_style[] = {
- {"LAST_OPENED", "LAST_OPENED", 0},
- {"SPECIFIED", "SPECIFIED", 1},
- {NULL, NULL, -1}
- };
- /* GTK knows of two ways representing "both", vertical and horizontal aligned.
- * as this may not work on other guis, we use only "both" in general here */
- static const enum_val_t gui_toolbar_style[] = {
- {"ICONS", "ICONS", 0},
- {"TEXT", "TEXT", 1},
- {"BOTH", "BOTH", 2},
- {NULL, NULL, -1}
- };
- static const enum_val_t gui_layout_content[] = {
- {"NONE", "NONE", 0},
- {"PLIST", "PLIST", 1},
- {"PDETAILS", "PDETAILS", 2},
- {"PBYTES", "PBYTES", 3},
- {NULL, NULL, -1}
- };
- static const enum_val_t gui_update_channel[] = {
- {"DEVELOPMENT", "DEVELOPMENT", UPDATE_CHANNEL_DEVELOPMENT},
- {"STABLE", "STABLE", UPDATE_CHANNEL_STABLE},
- {NULL, NULL, -1}
- };
- #if defined(HAVE_PCAP_CREATE)
- /* Can set monitor mode and buffer size. */
- static gint num_capture_cols = 7;
- static const gchar *capture_cols[7] = {
- "INTERFACE",
- "LINK",
- "PMODE",
- "SNAPLEN",
- "MONITOR",
- "BUFFER",
- "FILTER"
- };
- #define CAPTURE_COL_TYPE_DESCRIPTION \
- "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, MONITOR, BUFFER, FILTER\n"
- #elif defined(_WIN32) && !defined (HAVE_PCAP_CREATE)
- /* Can set buffer size but not monitor mode. */
- static gint num_capture_cols = 6;
- static const gchar *capture_cols[6] = {
- "INTERFACE",
- "LINK",
- "PMODE",
- "SNAPLEN",
- "BUFFER",
- "FILTER"
- };
- #define CAPTURE_COL_TYPE_DESCRIPTION \
- "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, BUFFER, FILTER\n"
- #else
- /* Can neither set buffer size nor monitor mode. */
- static gint num_capture_cols = 5;
- static const gchar *capture_cols[5] = {
- "INTERFACE",
- "LINK",
- "PMODE",
- "SNAPLEN",
- "FILTER"
- };
- #define CAPTURE_COL_TYPE_DESCRIPTION \
- "Possible values: INTERFACE, LINK, PMODE, SNAPLEN, FILTER\n"
- #endif
- /*
- * List of all modules with preference settings.
- */
- static wmem_tree_t *prefs_modules = NULL;
- /*
- * List of all modules that should show up at the top level of the
- * tree in the preference dialog box.
- */
- static wmem_tree_t *prefs_top_level_modules = NULL;
- /** Sets up memory used by proto routines. Called at program startup */
- void
- prefs_init(void)
- {
- prefs_modules = wmem_tree_new(wmem_epan_scope());
- prefs_top_level_modules = wmem_tree_new(wmem_epan_scope());
- }
- static void
- free_pref(gpointer data, gpointer user_data _U_)
- {
- pref_t *pref = (pref_t *)data;
- switch (pref->type) {
- case PREF_OBSOLETE:
- case PREF_BOOL:
- case PREF_ENUM:
- case PREF_UINT:
- case PREF_STATIC_TEXT:
- case PREF_UAT:
- case PREF_COLOR:
- break;
- case PREF_STRING:
- case PREF_FILENAME:
- case PREF_DIRNAME:
- g_free((char *)*pref->varp.string);
- *pref->varp.string = NULL;
- g_free(pref->default_val.string);
- pref->default_val.string = NULL;
- break;
- case PREF_RANGE:
- g_free(*pref->varp.range);
- *pref->varp.range = NULL;
- g_free(pref->default_val.range);
- pref->default_val.range = NULL;
- break;
- case PREF_CUSTOM:
- if (strcmp(pref->name, "columns") == 0)
- pref->stashed_val.boolval = TRUE;
- pref->custom_cbs.free_cb(pref);
- break;
- }
- g_free(pref);
- }
- static guint
- free_module_prefs(module_t *module, gpointer data _U_)
- {
- if (module->prefs) {
- g_list_foreach(module->prefs, free_pref, NULL);
- g_list_free(module->prefs);
- }
- module->prefs = NULL;
- module->numprefs = 0;
- if (module->submodules) {
- prefs_modules_foreach_submodules(module, free_module_prefs, NULL);
- }
- /* We don't free the actual module: its submodules pointer points to
- a wmem_tree and the module itself is stored in a wmem_tree
- */
- return 0;
- }
- /** Frees memory used by proto routines. Called at program shutdown */
- void
- prefs_cleanup(void)
- {
- /* This isn't strictly necessary since we're exiting anyway, but let's
- * do what clean up we can.
- */
- prefs_modules_foreach(free_module_prefs, NULL);
- }
- /*
- * Register a module that will have preferences.
- * Specify the module under which to register it or NULL to register it
- * at the top level, the name used for the module in the preferences file,
- * the title used in the tab for it in a preferences dialog box, and a
- * routine to call back when we apply the preferences.
- */
- module_t *
- prefs_register_module(module_t *parent, const char *name, const char *title,
- const char *description, void (*apply_cb)(void),
- const gboolean use_gui)
- {
- return prefs_register_module_or_subtree(parent, name, title, description,
- FALSE, apply_cb, use_gui);
- }
- /*
- * Register a subtree that will have modules under it.
- * Specify the module under which to register it or NULL to register it
- * at the top level and the title used in the tab for it in a preferences
- * dialog box.
- */
- module_t *
- prefs_register_subtree(module_t *parent, const char *title, const char *description,
- void (*apply_cb)(void))
- {
- return prefs_register_module_or_subtree(parent, NULL, title, description,
- TRUE, apply_cb,
- parent ? parent->use_gui : FALSE);
- }
- static module_t *
- prefs_register_module_or_subtree(module_t *parent, const char *name,
- const char *title, const char *description,
- gboolean is_subtree, void (*apply_cb)(void),
- gboolean use_gui)
- {
- module_t *module;
- const char *p;
- guchar c;
- /* this module may have been created as a subtree item previously */
- if ((module = find_subtree(parent, title))) {
- /* the module is currently a subtree */
- module->name = name;
- module->apply_cb = apply_cb;
- module->description = description;
- if (prefs_find_module(name) == NULL) {
- wmem_tree_insert_string(prefs_modules, name, module,
- WMEM_TREE_STRING_NOCASE);
- }
- return module;
- }
- module = wmem_new(wmem_epan_scope(), module_t);
- module->name = name;
- module->title = title;
- module->description = description;
- module->apply_cb = apply_cb;
- module->prefs = NULL; /* no preferences, to start */
- module->parent = parent;
- module->submodules = NULL; /* no submodules, to start */
- module->numprefs = 0;
- module->prefs_changed = FALSE;
- module->obsolete = FALSE;
- module->use_gui = use_gui;
- /*
- * Do we have a module name?
- */
- if (name != NULL) {
- /*
- * Yes.
- * Make sure that only lower-case ASCII letters, numbers,
- * underscores, hyphens, and dots appear in the name.
- *
- * Crash if there is, as that's an error in the code;
- * you can make the title a nice string with capitalization,
- * white space, punctuation, etc., but the name can be used
- * on the command line, and shouldn't require quoting,
- * shifting, etc.
- */
- for (p = name; (c = *p) != '\0'; p++)
- g_assert(isascii(c) &&
- (islower(c) || isdigit(c) || c == '_' ||
- c == '-' || c == '.'));
- /*
- * Make sure there's not already a module with that
- * name. Crash if there is, as that's an error in the
- * code, and the code has to be fixed not to register
- * more than one module with the same name.
- *
- * We search the list of all modules; the subtree stuff
- * doesn't require preferences in subtrees to have names
- * that reflect the subtree they're in (that would require
- * protocol preferences to have a bogus "protocol.", or
- * something such as that, to be added to all their names).
- */
- g_assert(prefs_find_module(name) == NULL);
- /*
- * Insert this module in the list of all modules.
- */
- wmem_tree_insert_string(prefs_modules, name, module, WMEM_TREE_STRING_NOCASE);
- } else {
- /*
- * This has no name, just a title; check to make sure it's a
- * subtree, and crash if it's not.
- */
- g_assert(is_subtree);
- }
- /*
- * Insert this module into the appropriate place in the display
- * tree.
- */
- if (parent == NULL) {
- /*
- * It goes at the top.
- */
- wmem_tree_insert_string(prefs_top_level_modules, title, module, WMEM_TREE_STRING_NOCASE);
- } else {
- /*
- * It goes into the list for this module.
- */
- if (parent->submodules == NULL)
- parent->submodules = wmem_tree_new(wmem_epan_scope());
- wmem_tree_insert_string(parent->submodules, title, module, WMEM_TREE_STRING_NOCASE);
- }
- return module;
- }
- /*
- * Register that a protocol has preferences.
- */
- module_t *protocols_module = NULL;
- module_t *
- prefs_register_protocol(int id, void (*apply_cb)(void))
- {
- protocol_t *protocol;
- /*
- * Have we yet created the "Protocols" subtree?
- */
- if (protocols_module == NULL) {
- /*
- * No. Register Protocols subtree as well as any preferences
- * for non-dissector modules.
- */
- prefs_register_modules();
- }
- protocol = find_protocol_by_id(id);
- return prefs_register_module(protocols_module,
- proto_get_protocol_filter_name(id),
- proto_get_protocol_short_name(protocol),
- proto_get_protocol_name(id), apply_cb, TRUE);
- }
- module_t *
- prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(void))
- {
- protocol_t *protocol;
- module_t *subtree_module;
- module_t *new_module;
- char *sep = NULL, *ptr = NULL, *orig = NULL;
- /*
- * Have we yet created the "Protocols" subtree?
- * XXX - can we just do this by registering Protocols/{subtree}?
- * If not, why not?
- */
- if (protocols_module == NULL) {
- /*
- * No. Register Protocols subtree as well as any preferences
- * for non-dissector modules.
- */
- prefs_register_modules();
- }
- subtree_module = protocols_module;
- if (subtree) {
- /* take a copy of the buffer, orig keeps a base pointer while ptr
- * walks through the string */
- orig = ptr = g_strdup(subtree);
- while (ptr && *ptr) {
- if ((sep = strchr(ptr, '/')))
- *sep++ = '\0';
- if (!(new_module = find_subtree(subtree_module, ptr))) {
- /*
- * There's no such module; create it, with the description
- * being the name (if it's later registered explicitly
- * with a description, that will override it).
- */
- ptr = wmem_strdup(wmem_epan_scope(), ptr),
- new_module = prefs_register_subtree(subtree_module, ptr, ptr, NULL);
- }
- subtree_module = new_module;
- ptr = sep;
- }
- g_free(orig);
- }
- protocol = find_protocol_by_id(id);
- return prefs_register_module(subtree_module,
- proto_get_protocol_filter_name(id),
- proto_get_protocol_short_name(protocol),
- proto_get_protocol_name(id), apply_cb, TRUE);
- }
- /*
- * Register that a protocol used to have preferences but no longer does,
- * by creating an "obsolete" module for it.
- */
- module_t *
- prefs_register_protocol_obsolete(int id)
- {
- module_t *module;
- protocol_t *protocol;
- /*
- * Have we yet created the "Protocols" subtree?
- */
- if (protocols_module == NULL) {
- /*
- * No. Register Protocols subtree as well as any preferences
- * for non-dissector modules.
- */
- prefs_register_modules();
- }
- protocol = find_protocol_by_id(id);
- module = prefs_register_module(protocols_module,
- proto_get_protocol_filter_name(id),
- proto_get_protocol_short_name(protocol),
- proto_get_protocol_name(id), NULL, TRUE);
- module->obsolete = TRUE;
- return module;
- }
- /*
- * Register that a statistical tap has preferences.
- *
- * "name" is a name for the tap to use on the command line with "-o"
- * and in preference files.
- *
- * "title" is a short human-readable name for the tap.
- *
- * "description" is a longer human-readable description of the tap.
- */
- module_t *stats_module = NULL;
- module_t *
- prefs_register_stat(const char *name, const char *title,
- const char *description, void (*apply_cb)(void))
- {
- /*
- * Have we yet created the "Statistics" subtree?
- */
- if (stats_module == NULL) {
- /*
- * No. Register Statistics subtree as well as any preferences
- * for non-dissector modules.
- */
- prefs_register_modules();
- }
- return prefs_register_module(stats_module, name, title, description,
- apply_cb, TRUE);
- }
- module_t *
- prefs_find_module(const char *name)
- {
- return (module_t *)wmem_tree_lookup_string(prefs_modules, name, WMEM_TREE_STRING_NOCASE);
- }
- static module_t *
- find_subtree(module_t *parent, const char *name)
- {
- return (module_t *)wmem_tree_lookup_string(parent ? parent->submodules : prefs_top_level_modules, name, WMEM_TREE_STRING_NOCASE);
- }
- /*
- * Call a callback function, with a specified argument, for each module
- * in a list of modules. If the list is NULL, searches the top-level
- * list in the display tree of modules. If any callback returns a
- * non-zero value, we stop and return that value, otherwise we
- * return 0.
- *
- * Ignores "obsolete" modules; their sole purpose is to allow old
- * preferences for dissectors that no longer have preferences to be
- * silently ignored in preference files. Does not ignore subtrees,
- * as this can be used when walking the display tree of modules.
- */
- typedef struct {
- module_cb callback;
- gpointer user_data;
- guint ret;
- } call_foreach_t;
- static gboolean
- call_foreach_cb(void *value, void *data)
- {
- module_t *module = (module_t*)value;
- call_foreach_t *call_data = (call_foreach_t*)data;
- if (!module->obsolete)
- call_data->ret = (*call_data->callback)(module, call_data->user_data);
- return (call_data->ret != 0);
- }
- static guint
- prefs_module_list_foreach(wmem_tree_t *module_list, module_cb callback,
- gpointer user_data)
- {
- call_foreach_t call_data;
- if (module_list == NULL)
- module_list = prefs_top_level_modules;
- call_data.callback = callback;
- call_data.user_data = user_data;
- call_data.ret = 0;
- wmem_tree_foreach(module_list, call_foreach_cb, &call_data);
- return call_data.ret;
- }
- /*
- * Returns TRUE if module has any submodules
- */
- gboolean
- prefs_module_has_submodules(module_t *module)
- {
- if (module->submodules == NULL) {
- return FALSE;
- }
- if (wmem_tree_is_empty(module->submodules)) {
- return FALSE;
- }
- return TRUE;
- }
- /*
- * Call a callback function, with a specified argument, for each module
- * in the list of all modules. (This list does not include subtrees.)
- *
- * Ignores "obsolete" modules; their sole purpose is to allow old
- * preferences for dissectors that no longer have preferences to be
- * silently ignored in preference files.
- */
- guint
- prefs_modules_foreach(module_cb callback, gpointer user_data)
- {
- return prefs_module_list_foreach(prefs_modules, callback, user_data);
- }
- /*
- * Call a callback function, with a specified argument, for each submodule
- * of specified modules. If the module is NULL, goes through the top-level
- * list in the display tree of modules.
- *
- * Ignores "obsolete" modules; their sole purpose is to allow old
- * preferences for dissectors that no longer have preferences to be
- * silently ignored in preference files. Does not ignore subtrees,
- * as this can be used when walking the display tree of modules.
- */
- guint
- prefs_modules_foreach_submodules(module_t *module, module_cb callback,
- gpointer user_data)
- {
- return prefs_module_list_foreach((module)?module->submodules:prefs_top_level_modules, callback, user_data);
- }
- static gboolean
- call_apply_cb(void *value, void *data _U_)
- {
- module_t *module = (module_t *)value;
- if (module->obsolete)
- return FALSE;
- if (module->prefs_changed) {
- if (module->apply_cb != NULL)
- (*module->apply_cb)();
- module->prefs_changed = FALSE;
- }
- return FALSE;
- }
- /*
- * Call the "apply" callback function for each module if any of its
- * preferences have changed, and then clear the flag saying its
- * preferences have changed, as the module has been notified of that
- * fact.
- */
- void
- prefs_apply_all(void)
- {
- wmem_tree_foreach(prefs_modules, call_apply_cb, NULL);
- }
- /*
- * Call the "apply" callback function for a specific module if any of
- * its preferences have changed, and then clear the flag saying its
- * preferences have changed, as the module has been notified of that
- * fact.
- */
- void
- prefs_apply(module_t *module)
- {
- if (module && module->prefs_changed)
- call_apply_cb(module, NULL);
- }
- /*
- * Register a preference in a module's list of preferences.
- * If it has a title, give it an ordinal number; otherwise, it's a
- * preference that won't show up in the UI, so it shouldn't get an
- * ordinal number (the ordinal should be the ordinal in the set of
- * *visible* preferences).
- */
- static pref_t *
- register_preference(module_t *module, const char *name, const char *title,
- const char *description, pref_type_t type)
- {
- pref_t *preference;
- const gchar *p;
- preference = g_new(pref_t,1);
- preference->name = name;
- preference->title = title;
- preference->description = description;
- preference->type = type;
- if (title != NULL)
- preference->ordinal = module->numprefs;
- else
- preference->ordinal = -1; /* no ordinal for you */
- /*
- * Make sure that only lower-case ASCII letters, numbers,
- * underscores, and dots appear in the preference name.
- *
- * Crash if there is, as that's an error in the code;
- * you can make the title and description nice strings
- * with capitalization, white space, punctuation, etc.,
- * but the name can be used on the command line,
- * and shouldn't require quoting, shifting, etc.
- */
- for (p = name; *p != '\0'; p++)
- if (!(isascii((guchar)*p) &&
- (islower((guchar)*p) || isdigit((guchar)*p) || *p == '_' || *p == '.')))
- g_error("Preference %s.%s contains invalid characters", module->name, name);
- /*
- * Make sure there's not already a preference with that
- * name. Crash if there is, as that's an error in the
- * code, and the code has to be fixed not to register
- * more than one preference with the same name.
- */
- if (prefs_find_preference(module, name) != NULL)
- g_error("Preference %s has already been registered", name);
- if ((type != PREF_OBSOLETE) &&
- /* Don't compare if it's a subtree */
- (module->name != NULL)) {
- /*
- * Make sure the preference name doesn't begin with the
- * module name, as that's redundant and Just Silly.
- */
- if (!((strncmp(name, module->name, strlen(module->name)) != 0) ||
- (((name[strlen(module->name)]) != '.') && ((name[strlen(module->name)]) != '_'))))
- g_error("Preference %s begins with the module name", name);
- }
- /*
- * There isn't already one with that name, so add the
- * preference.
- */
- module->prefs = g_list_append(module->prefs, preference);
- if (title != NULL)
- module->numprefs++;
- return preference;
- }
- /*
- * Find a preference in a module's list of preferences, given the module
- * and the preference's name.
- */
- typedef struct {
- GList *list_entry;
- const char *name;
- } find_pref_arg_t;
- static gint
- preference_match(gconstpointer a, gconstpointer b)
- {
- const pref_t *pref = (const pref_t *)a;
- const char *name = (const char *)b;
- return strcmp(name, pref->name);
- }
- static gboolean module_find_pref_cb(void *value, void *data)
- {
- find_pref_arg_t* arg = (find_pref_arg_t*)data;
- GList *list_entry;
- module_t *module = (module_t *)value;
- if (module == NULL)
- return FALSE;
- list_entry = g_list_find_custom(module->prefs, arg->name,
- preference_match);
- if (list_entry == NULL)
- return FALSE;
- arg->list_entry = list_entry;
- return TRUE;
- }
- struct preference *
- prefs_find_preference(module_t *module, const char *name)
- {
- find_pref_arg_t arg;
- GList *list_entry;
- if (module == NULL)
- return NULL; /* invalid parameters */
- list_entry = g_list_find_custom(module->prefs, name,
- preference_match);
- if (list_entry == NULL)
- {
- arg.list_entry = NULL;
- if (module->submodules != NULL)
- {
- arg.name = name;
- wmem_tree_foreach(module->submodules, module_find_pref_cb, &arg);
- }
- list_entry = arg.list_entry;
- }
- if (list_entry == NULL)
- return NULL; /* no such preference */
- return (struct preference *) list_entry->data;
- }
- /*
- * Returns TRUE if the given protocol has registered preferences
- */
- gboolean
- prefs_is_registered_protocol(const char *name)
- {
- module_t *m = prefs_find_module(name);
- return (m != NULL && !m->obsolete);
- }
- /*
- * Returns the module title of a registered protocol
- */
- const char *
- prefs_get_title_by_name(const char *name)
- {
- module_t *m = prefs_find_module(name);
- return (m != NULL && !m->obsolete) ? m->title : NULL;
- }
- /*
- * Register a preference with an unsigned integral value.
- */
- void
- prefs_register_uint_preference(module_t *module, const char *name,
- const char *title, const char *description,
- guint base, guint *var)
- {
- pref_t *preference;
- preference = register_preference(module, name, title, description,
- PREF_UINT);
- preference->varp.uint = var;
- preference->default_val.uint = *var;
- g_assert(base > 0 && base != 1 && base < 37);
- preference->info.base = base;
- }
- /*
- * XXX Add a prefs_register_{uint16|port}_preference which sets max_value?
- */
- /*
- * Register a "custom" preference with a unsigned integral value.
- * XXX - This should be temporary until we can find a better way
- * to do "custom" preferences
- */
- static void
- prefs_register_uint_custom_preference(module_t *module, const char *name,
- const char *title, const char *description,
- struct pref_custom_cbs* custom_cbs, guint *var)
- {
- pref_t *preference;
- preference = register_preference(module, name, title, description,
- PREF_CUSTOM);
- preference->custom_cbs = *custom_cbs;
- preference->varp.uint = var;
- preference->default_val.uint = *var;
- }
- /*
- * Register a preference with an Boolean value.
- */
- void
- prefs_register_bool_preference(module_t *module, const char *name,
- const char *title, const char *description,
- gboolean *var)
- {
- pref_t *preference;
- preference = register_preference(module, name, title, description,
- PREF_BOOL);
- preference->varp.boolp = var;
- preference->default_val.boolval = *var;
- }
- /*
- * Register a preference with an enumerated value.
- */
- void
- prefs_register_enum_preference(module_t *module, const char *name,
- const char *title, const char *description,
- gint *var, const enum_val_t *enumvals,
- gboolean radio_buttons)
- {
- pref_t *preference;
- preference = register_preference(module, name, title, description,
- PREF_ENUM);
- preference->varp.enump = var;
- preference->default_val.enumval = *var;
- preference->info.enum_info.enumvals = enumvals;
- preference->info.enum_info.radio_buttons = radio_buttons;
- }
- static pref_t*
- register_string_like_preference(module_t *module, const char *name,
- const char *title, const char *description,
- const char **var, pref_type_t type)
- {
- pref_t *preference;
- char *varcopy;
- preference = register_preference(module, name, title, description,
- type);
- /*
- * String preference values should be non-null (as you can't
- * keep them null after using the preferences GUI, you can at best
- * have them be null strings) and freeable (as we free them
- * if we change them).
- *
- * If the value is a null pointer, make it a copy of a null
- * string, otherwise make it a copy of the value.
- */
- if (*var == NULL) {
- *var = g_strdup("");
- varcopy = g_strdup("");
- } else {
- *var = g_strdup(*var);
- varcopy = g_strdup(*var);
- }
- preference->varp.string = var;
- preference->default_val.string = varcopy;
- preference->stashed_val.string = NULL;
- return preference;
- }
- /*
- * Register a preference with a character-string value.
- */
- void
- prefs_register_string_preference(module_t *module, const char *name,
- const char *title, const char *description,
- const char **var)
- {
- register_string_like_preference(module, name, title, description, var,
- PREF_STRING);
- }
- /*
- * Register a "custom" preference with a character-string value.
- * XXX - This should be temporary until we can find a better way
- * to do "custom" preferences
- */
- static
- void prefs_register_string_custom_preference(module_t *module, const char *name,
- const char *title, const char *description,
- struct pref_custom_cbs* custom_cbs, const char **var)
- {
- pref_t *preference;
- preference = register_string_like_preference(module, name, title, description, var,
- PREF_CUSTOM);
- preference->custom_cbs = *custom_cbs;
- }
- /*
- * Register a preference with a file name (string) value.
- */
- void
- prefs_register_filename_preference(module_t *module, const char *name,
- const char *title, const char *description,
- const char **var)
- {
- register_string_like_preference(module, name, title, description, var,
- PREF_FILENAME);
- }
- /*
- * Register a preference with a directory name (string) value.
- */
- void
- prefs_register_directory_preference(module_t *module, const char *name,
- const char *title, const char *description,
- const char **var)
- {
- register_string_like_preference(module, name, title, description, var,
- PREF_DIRNAME);
- }
- /*
- * Register a preference with a ranged value.
- */
- void
- prefs_register_range_preference(module_t *module, const char *name,
- const char *title, const char *description,
- range_t **var, guint32 max_value)
- {
- pref_t *preference;
- preference = register_preference(module, name, title, description,
- PREF_RANGE);
- preference->info.max_value = max_value;
- /*
- * Range preference values should be non-null (as you can't
- * keep them null after using the preferences GUI, you can at best
- * have them be empty ranges) and freeable (as we free them
- * if we change them).
- *
- * If the value is a null pointer, make it an empty range.
- */
- if (*var == NULL)
- *var = range_empty();
- preference->varp.range = var;
- preference->default_val.range = range_copy(*var);
- preference->stashed_val.range = NULL;
- }
- /*
- * Register a static text 'preference'. It can be used to add explanatory
- * text inline with other preferences in the GUI.
- * Note: Static preferences are not saved to the preferences file.
- */
- void
- prefs_register_static_text_preference(module_t *module, const char *name,
- const char *title,
- const char *description)
- {
- register_preference(module, name, title, description, PREF_STATIC_TEXT);
- }
- /*
- * Register a uat 'preference'. It adds a button that opens the uat's window in the
- * preferences tab of the module.
- */
- extern void
- prefs_register_uat_preference(module_t *module, const char *name,
- const char *title, const char *description,
- uat_t* uat)
- {
- pref_t* preference = register_preference(module, name, title, description, PREF_UAT);
- preference->varp.uat = uat;
- }
- /*
- * Register a color preference.
- */
- void prefs_register_color_preference(module_t *module, const char *name,
- const char *title, const char *description, color_t *color)
- {
- pref_t* preference = register_preference(module, name, title, description, PREF_COLOR);
- preference->varp.colorp = color;
- preference->default_val.color = *color;
- }
- /*
- * Register a "custom" preference with a list.
- * XXX - This should be temporary until we can find a better way
- * to do "custom" preferences
- */
- typedef void (*pref_custom_list_init_cb) (pref_t* pref, GList** value);
- static
- void prefs_register_list_custom_preference(module_t *module, const char *name,
- const char *title, const char *description, struct pref_custom_cbs* custom_cbs,
- pref_custom_list_init_cb init_cb, GList** list)
- {
- pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM);
- preference->custom_cbs = *custom_cbs;
- init_cb(preference, list);
- }
- /*
- * Register a custom preference.
- */
- void prefs_register_custom_preference(module_t *module, const char *name,
- const char *title, const char *description, struct pref_custom_cbs* custom_cbs,
- void** custom_data _U_)
- {
- pref_t* preference = register_preference(module, name, title, description, PREF_CUSTOM);
- preference->custom_cbs = *custom_cbs;
- /* XXX - wait until we can handle void** pointers
- preference->custom_cbs.init_cb(preference, custom_data);
- */
- }
- /*
- * Register a preference that used to be supported but no longer is.
- */
- void
- prefs_register_obsolete_preference(module_t *module, const char *name)
- {
- register_preference(module, name, NULL, NULL, PREF_OBSOLETE);
- }
- /*
- * Check to see if a preference is obsolete.
- */
- extern gboolean
- prefs_get_preference_obsolete(pref_t *pref)
- {
- if (pref)
- return pref->type == PREF_OBSOLETE ? TRUE : FALSE;
- return TRUE;
- }
- /*
- * Make a preference obsolete.
- */
- extern prefs_set_pref_e
- prefs_set_preference_obsolete(pref_t *pref)
- {
- if (pref) {
- pref->type = PREF_OBSOLETE;
- return PREFS_SET_OK;
- }
- return PREFS_SET_NO_SUCH_PREF;
- }
- /* Return the value assigned to the given uint preference. */
- guint prefs_get_uint_preference(pref_t *pref)
- {
- if (pref && pref->type == PREF_UINT)
- return *pref->varp.uint;
- return 0;
- }
- /*
- * Call a callback function, with a specified argument, for each preference
- * in a given module.
- *
- * If any of the callbacks return a non-zero value, stop and return that
- * value, otherwise return 0.
- */
- guint
- prefs_pref_foreach(module_t *module, pref_cb callback, gpointer user_data)
- {
- GList *elem;
- pref_t *pref;
- guint ret;
- for (elem = g_list_first(module->prefs); elem != NULL; elem = g_list_next(elem)) {
- pref = (pref_t *)elem->data;
- if (pref->type == PREF_OBSOLETE) {
- /*
- * This preference is no longer supported; it's
- * not a real preference, so we don't call the
- * callback for it (i.e., we treat it as if it
- * weren't found in the list of preferences,
- * and we weren't called in the first place).
- */
- continue;
- }
- ret = (*callback)(pref, user_data);
- if (ret != 0)
- return ret;
- }
- return 0;
- }
- static const enum_val_t print_format_vals[] = {
- { "text", "Plain Text", PR_FMT_TEXT },
- { "postscript", "Postscript", PR_FMT_PS },
- { NULL, NULL, 0 }
- };
- static const enum_val_t print_dest_vals[] = {
- #ifdef _WIN32
- /* "PR_DEST_CMD" means "to printer" on Windows */
- { "command", "Printer", PR_DEST_CMD },
- #else
- { "command", "Command", PR_DEST_CMD },
- #endif
- { "file", "File", PR_DEST_FILE },
- { NULL, NULL, 0 }
- };
- static void stats_callback(void)
- {
- /* Test for a sane tap update interval */
- if (prefs.tap_update_interval < 100 || prefs.tap_update_interval > 10000)
- prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL;
- #ifdef HAVE_LIBPORTAUDIO
- /* Test for a sane max channels entry */
- if (prefs.rtp_player_max_visible < 1 || prefs.rtp_player_max_visible > 10)
- prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE;
- #endif
- }
- static void gui_callback(void)
- {
- /* Ensure there is at least one file count */
- if (prefs.gui_recent_files_count_max == 0)
- prefs.gui_recent_files_count_max = 10;
- /* Ensure there is at least one display filter entry */
- if (prefs.gui_recent_df_entries_max == 0)
- prefs.gui_recent_df_entries_max = 10;
- }
- static void gui_layout_callback(void)
- {
- if (prefs.gui_layout_type == layout_unused ||
- prefs.gui_layout_type >= layout_type_max) {
- /* XXX - report an error? It's not a syntax error - we'd need to
- add a way of reporting a *semantic* error. */
- prefs.gui_layout_type = layout_type_5;
- }
- }
- /******************************************************
- * All custom preference function callbacks
- ******************************************************/
- static void custom_pref_no_cb(pref_t* pref _U_) {}
- /*
- * Console log level custom preference functions
- */
- static void console_log_level_reset_cb(pref_t* pref)
- {
- *pref->varp.uint = pref->default_val.uint;
- }
- static prefs_set_pref_e console_log_level_set_cb(pref_t* pref, const gchar* value, gboolean* changed)
- {
- guint uval;
- uval = (guint)strtoul(value, NULL, 10);
- if (*pref->varp.uint != uval) {
- *changed = TRUE;
- *pref->varp.uint = uval;
- }
- if (*pref->varp.uint & (G_LOG_LEVEL_INFO|G_LOG_LEVEL_DEBUG)) {
- /*
- * GLib >= 2.32 drops INFO and DEBUG messages by default. Tell
- * it not to do that.
- */
- g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
- }
- return PREFS_SET_OK;
- }
- static const char * console_log_level_type_name_cb(void) {
- return "Log level";
- }
- static char * console_log_level_type_description_cb(void) {
- return g_strdup_printf(
- "Console log level (for debugging)\n"
- "A bitmask of log levels:\n"
- "ERROR = 4\n"
- "CRITICAL = 8\n"
- "WARNING = 16\n"
- "MESSAGE = 32\n"
- "INFO = 64\n"
- "DEBUG = 128");
- }
- static gboolean console_log_level_is_default_cb(pref_t* pref) {
- return *pref->varp.uint == pref->default_val.uint;
- }
- static char * console_log_level_to_str_cb(pref_t* pref, gboolean default_val) {
- return g_strdup_printf("%u", default_val ? pref->default_val.uint : *pref->varp.uint);
- }
- /*
- * Column preference functions
- */
- #define PRS_COL_HIDDEN "column.hidden"
- #define PRS_COL_FMT "column.format"
- #define PRS_COL_NUM "column.number"
- static module_t *gui_column_module = NULL;
- static void column_hidden_free_cb(pref_t* pref)
- {
- g_free((char *)*pref->varp.string);
- *pref->varp.string = NULL;
- g_free(pref->default_val.string);
- pref->default_val.string = NULL;
- }
- static void column_hidden_reset_cb(pref_t* pref)
- {
- g_free((void *)*pref->varp.string);
- *pref->varp.string = g_strdup(pref->default_val.string);
- }
- static prefs_set_pref_e column_hidden_set_cb(pref_t* pref, const gchar* value, gboolean* changed)
- {
- GList *clp;
- fmt_data *cfmt;
- pref_t *format_pref;
- if (*pref->varp.string) {
- if (strcmp(*pref->varp.string, value) != 0) {
- *changed = TRUE;
- g_free((void *)*pref->varp.string);
- *pref->varp.string = g_strdup(value);
- }
- } else if (value) {
- *pref->varp.string = g_strdup(value);
- }
- /*
- * Set the "visible" flag for the existing columns; we need to
- * do this if we set PRS_COL_HIDDEN but don't set PRS_COL_FMT
- * after setting it (which might be the case if, for example, we
- * set PRS_COL_HIDDEN on the command line).
- */
- format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT);
- for (clp = *format_pref->varp.list; clp != NULL; clp = clp->next) {
- cfmt = (fmt_data *)clp->data;
- cfmt->visible = prefs_is_column_visible(*pref->varp.string, cfmt);
- }
- return PREFS_SET_OK;
- }
- static const char * column_hidden_type_name_cb(void) {
- return "Packet list hidden columns";
- }
- static char * column_hidden_type_description_cb(void) {
- return g_strdup("List all columns to hide in the packet list.");
- }
- static char * column_hidden_to_str_cb(pref_t* pref, gboolean default_val) {
- GString *cols_hidden = g_string_new ("");
- GList *clp;
- fmt_data *cfmt;
- pref_t *format_pref;
- if (default_val)
- return g_strdup(pref->default_val.string);
- format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT);
- clp = (format_pref) ? *format_pref->varp.list : NULL;
- while (clp) {
- gchar *prefs_fmt;
- cfmt = (fmt_data *) clp->data;
- if ((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_field)) {
- prefs_fmt = g_strdup_printf("%s:%s:%d:%c",
- col_format_to_string(cfmt->fmt),
- cfmt->custom_field,
- cfmt->custom_occurrence,
- cfmt->resolved ? 'R' : 'U');
- } else {
- prefs_fmt = g_strdup(col_format_to_string(cfmt->fmt));
- }
- if (!cfmt->visible) {
- if (cols_hidden->len)
- g_string_append (cols_hidden, ",");
- g_string_append (cols_hidden, prefs_fmt);
- }
- clp = clp->next;
- }
- return g_string_free (cols_hidden, FALSE);
- }
- static gboolean column_hidden_is_default_cb(pref_t* pref) {
- char *cur_hidden_str = column_hidden_to_str_cb(pref, FALSE);
- gboolean is_default = g_strcmp0(cur_hidden_str, pref->default_val.string) == 0;
- g_free(cur_hidden_str);
- return is_default;
- }
- /* Number of columns "preference". This is only used internally and is not written to the
- * preference file
- */
- static void column_num_reset_cb(pref_t* pref)
- {
- *pref->varp.uint = pref->default_val.uint;
- }
- static prefs_set_pref_e column_num_set_cb(pref_t* pref _U_, const gchar* value _U_, gboolean* changed _U_)
- {
- /* Don't write this to the preferences file */
- return PREFS_SET_OK;
- }
- static const char * column_num_type_name_cb(void) {
- return NULL;
- }
- static char * column_num_type_description_cb(void) {
- return g_strdup("");
- }
- static gboolean column_num_is_default_cb(pref_t* pref _U_) {
- return TRUE;
- }
- static char * column_num_to_str_cb(pref_t* pref _U_, gboolean default_val _U_) {
- return g_strdup("");
- }
- /*
- * Column format custom preference functions
- */
- static void column_format_init_cb(pref_t* pref, GList** value)
- {
- fmt_data *src_cfmt, *dest_cfmt;
- GList *entry;
- pref->varp.list = value;
- pref->default_val.list = NULL;
- for (entry = *pref->varp.list; entry != NULL; entry = g_list_next(entry)) {
- src_cfmt = (fmt_data *)entry->data;
- dest_cfmt = g_new(fmt_data,1);
- dest_cfmt->title = g_strdup(src_cfmt->title);
- dest_cfmt->fmt = src_cfmt->fmt;
- if (src_cfmt->custom_field) {
- dest_cfmt->custom_field = g_strdup(src_cfmt->custom_field);
- dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
- } else {
- dest_cfmt->custom_field = NULL;
- dest_cfmt->custom_occurrence = 0;
- }
- dest_cfmt->visible = src_cfmt->visible;
- dest_cfmt->resolved = src_cfmt->resolved;
- pref->default_val.list = g_list_append(pref->default_val.list, dest_cfmt);
- }
- }
- static void column_format_free_cb(pref_t* pref)
- {
- free_col_info(*pref->varp.list);
- free_col_info(pref->default_val.list);
- }
- static void column_format_reset_cb(pref_t* pref)
- {
- fmt_data *src_cfmt, *dest_cfmt;
- GList *entry;
- pref_t *col_num_pref;
- free_col_info(*pref->varp.list);
- *pref->varp.list = NULL;
- for (entry = pref->default_val.list; entry != NULL; entry = g_list_next(entry)) {
- src_cfmt = (fmt_data *)entry->data;
- dest_cfmt = g_new(fmt_data,1);
- dest_cfmt->title = g_strdup(src_cfmt->title);
- dest_cfmt->fmt = src_cfmt->fmt;
- if (src_cfmt->custom_field) {
- dest_cfmt->custom_field = g_strdup(src_cfmt->custom_field);
- dest_cfmt->custom_occurrence = src_cfmt->custom_occurrence;
- } else {
- dest_cfmt->custom_field = NULL;
- dest_cfmt->custom_occurrence = 0;
- }
- dest_cfmt->visible = src_cfmt->visible;
- dest_cfmt->resolved = src_cfmt->resolved;
- *pref->varp.list = g_list_append(*pref->varp.list, dest_cfmt);
- }
- col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
- column_num_reset_cb(col_num_pref);
- }
- static prefs_set_pref_e column_format_set_cb(pref_t* pref, const gchar* value, gboolean* changed _U_)
- {
- GList *col_l, *col_l_elt;
- fmt_data *cfmt;
- gint llen;
- pref_t *hidden_pref, *col_num_pref;
- col_l = prefs_get_string_list(value);
- if (col_l == NULL)
- return PREFS_SET_SYNTAX_ERR;
- if ((g_list_length(col_l) % 2) != 0) {
- /* A title didn't have a matching format. */
- prefs_clear_string_list(col_l);
- return PREFS_SET_SYNTAX_ERR;
- }
- /* Check to make sure all column formats are valid. */
- col_l_elt = g_list_first(col_l);
- while (col_l_elt) {
- fmt_data cfmt_check;
- /* Go past the title. */
- col_l_elt = col_l_elt->next;
- /* Parse the format to see if it's valid. */
- if (!parse_column_format(&cfmt_check, (char *)col_l_elt->data)) {
- /* It's not a valid column format. */
- prefs_clear_string_list(col_l);
- return PREFS_SET_SYNTAX_ERR;
- }
- if (cfmt_check.fmt != COL_CUSTOM) {
- /* Some predefined columns have been migrated to use custom columns.
- * We'll convert these silently here */
- try_convert_to_custom_column(&col_l_elt->data);
- } else {
- /* We don't need the custom column field on this pass. */
- g_free(cfmt_check.custom_field);
- }
- /* Go past the format. */
- col_l_elt = col_l_elt->next;
- }
- /* They're all valid; process them. */
- free_col_info(*pref->varp.list);
- *pref->varp.list = NULL;
- hidden_pref = prefs_find_preference(gui_column_module, PRS_COL_HIDDEN);
- col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
- llen = g_list_length(col_l);
- *col_num_pref->varp.uint = llen / 2;
- col_l_elt = g_list_first(col_l);
- while (col_l_elt) {
- cfmt = g_new(fmt_data,1);
- cfmt->title = g_strdup((gchar *)col_l_elt->data);
- col_l_elt = col_l_elt->next;
- parse_column_format(cfmt, (char *)col_l_elt->data);
- cfmt->visible = prefs_is_column_visible((gchar*)(*hidden_pref->varp.string), cfmt);
- col_l_elt = col_l_elt->next;
- *pref->varp.list = g_list_append(*pref->varp.list, cfmt);
- }
- prefs_clear_string_list(col_l);
- column_hidden_free_cb(hidden_pref);
- return PREFS_SET_OK;
- }
- static const char * column_format_type_name_cb(void) {
- return "Packet list column format";
- }
- static char * column_format_type_description_cb(void) {
- return g_strdup("Each pair of strings consists of a column title and its format");
- }
- static gboolean column_format_is_default_cb(pref_t* pref) {
- GList *clp = *pref->varp.list,
- *pref_col = g_list_first(clp),
- *def_col = g_list_first(pref->default_val.list);
- fmt_data *cfmt, *def_cfmt;
- gboolean is_default = TRUE;
- pref_t *col_num_pref;
- /* See if the column data has changed from the default */
- col_num_pref = prefs_find_preference(gui_column_module, PRS_COL_NUM);
- if (col_num_pref && *col_num_pref->varp.uint != col_num_pref->default_val.uint) {
- is_default = FALSE;
- } else {
- while (pref_col && def_col) {
- cfmt = (fmt_data *) pref_col->data;
- def_cfmt = (fmt_data *) def_col->data;
- if ((g_strcmp0(cfmt->title, def_cfmt->title) != 0) ||
- (cfmt->fmt != def_cfmt->fmt) ||
- (((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_field)) &&
- ((g_strcmp0(cfmt->custom_field, def_cfmt->custom_field) != 0) ||
- (cfmt->resolved != def_cfmt->resolved)))) {
- is_default = FALSE;
- break;
- }
- pref_col = pref_col->next;
- def_col = def_col->next;
- }
- }
- return is_default;
- }
- static char * column_format_to_str_cb(pref_t* pref, gboolean default_val) {
- GList *pref_l = default_val ? pref->default_val.list : *pref->varp.list;
- GList *clp = g_list_first(pref_l);
- GList *col_l;
- fmt_data *cfmt;
- gchar *prefs_fmt;
- char *column_format_str;
- col_l = NULL;
- while (clp) {
- cfmt = (fmt_data *) clp->data;
- …
Large files files are truncated, but you can click here to view the full file