X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=epan%2Fprefs.c;h=f339a2b4469404169b78e027b087cced6582ff45;hb=9db969ded196dcdc942f961cbdf400dc281e973e;hp=4235c03abd8ce5e3980911e387746e2c59fcc280;hpb=23d4eba3b106d7cc8ba77773376ae1bc05d3ff03;p=metze%2Fwireshark%2Fwip.git diff --git a/epan/prefs.c b/epan/prefs.c index 4235c03abd..f339a2b446 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -19,7 +19,7 @@ * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H @@ -37,13 +37,18 @@ #include +#include #include #include #include +#include +#ifdef HAVE_GEOIP +#include +#endif #include #include #include -#include "cfile.h" +#include #include #include "print.h" #include @@ -51,20 +56,29 @@ #include #include +#include "epan/filter_expressions.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)); -static prefs_set_pref_e set_pref(gchar*, gchar*, void *); -static gchar *put_string_list(GList *); -static void free_col_info(e_prefs *); + void (*apply_cb)(void), gboolean use_gui); +static prefs_set_pref_e set_pref(gchar*, gchar*, void *, gboolean); +static gchar *put_string_list(GList *, gboolean is_default); +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 @@ -77,28 +91,65 @@ static int mgcp_udp_port_count; e_prefs prefs; -static const gchar *gui_ptree_line_style_text[] = - { "NONE", "SOLID", "DOTTED", "TABBED", NULL }; - -static const gchar *gui_ptree_expander_style_text[] = - { "NONE", "SQUARE", "TRIANGLE", "CIRCULAR", NULL }; - -static const gchar *gui_hex_dump_highlight_style_text[] = - { "BOLD", "INVERSE", NULL }; - -static const gchar *gui_console_open_text[] = - { "NEVER", "AUTOMATIC", "ALWAYS", NULL }; - -static const gchar *gui_fileopen_style_text[] = - { "LAST_OPENED", "SPECIFIED", NULL }; +static enum_val_t gui_ptree_line_style[] = { + {"NONE", "NONE", 0}, + {"SOLID", "SOLID", 1}, + {"DOTTED", "DOTTED", 2}, + {"TABBED", "TABBED", 3}, + {NULL, NULL, -1} + }; + +static enum_val_t gui_ptree_expander_style[] = { + {"NONE", "NONE", 0}, + {"SQUARE", "SQUARE", 1}, + {"TRIANGLE", "TRIANGLE", 2}, + {"CIRCULAR", "CIRCULAR", 3}, + {NULL, NULL, -1} + }; + +static enum_val_t gui_hex_dump_highlight_style[] = { + {"BOLD", "BOLD", 0}, + {"INVERSE", "INVERSE", 1}, + {NULL, NULL, -1} + }; + +static 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 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 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 gchar *gui_toolbar_style_text[] = - { "ICONS", "TEXT", "BOTH", NULL }; - -static const gchar *gui_layout_content_text[] = - { "NONE", "PLIST", "PDETAILS", "PBYTES", NULL }; +static enum_val_t gui_toolbar_style[] = { + {"ICONS", "ICONS", 0}, + {"TEXT", "TEXT", 1}, + {"BOTH", "BOTH", 2}, + {NULL, NULL, -1} + }; + +static enum_val_t gui_layout_content[] = { + {"NONE", "NONE", 0}, + {"PLIST", "PLIST", 1}, + {"PDETAILS", "PDETAILS", 2}, + {"PBYTES", "PBYTES", 3}, + {NULL, NULL, -1} + }; /* * List of all modules with preference settings. @@ -112,15 +163,68 @@ static emem_tree_t *prefs_modules = NULL; static emem_tree_t *prefs_top_level_modules = NULL; /** Sets up memory used by proto routines. Called at program startup */ -void prefs_init(void) +void +prefs_init(void) +{ + prefs_modules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_modules"); + prefs_top_level_modules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_top_level_modules"); +} + +static void +free_pref(gpointer data, gpointer user_data _U_) +{ + pref_t *pref = 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: + g_free((char *)*pref->varp.string); + *pref->varp.string = NULL; + g_free(pref->default_val.string); + break; + case PREF_RANGE: + g_free(*pref->varp.range); + *pref->varp.range = NULL; + g_free(pref->default_val.range); + break; + case PREF_CUSTOM: + pref->custom_cbs.free_cb(pref); + break; + } + + g_free(pref); +} + +static guint +free_module_prefs(module_t *module, gpointer data _U_) { - prefs_modules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_modules"); - prefs_top_level_modules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_top_level_modules"); + g_list_foreach(module->prefs, free_pref, NULL); + g_list_free(module->prefs); + module->prefs = NULL; + module->numprefs = 0; + /* We don't free the actual module: its submodules pointer points to + a pe_tree and the module itself is stored in a pe_tree + */ + + return 0; } /** Frees memory used by proto routines. Called at program shutdown */ -void prefs_cleanup(void) +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); } /* @@ -132,10 +236,11 @@ void prefs_cleanup(void) */ module_t * prefs_register_module(module_t *parent, const char *name, const char *title, - const char *description, void (*apply_cb)(void)) + const char *description, void (*apply_cb)(void), + const gboolean use_gui) { - return prefs_register_module_or_subtree(parent, name, title, description, - FALSE, apply_cb); + return prefs_register_module_or_subtree(parent, name, title, description, + FALSE, apply_cb, use_gui); } /* @@ -145,186 +250,200 @@ prefs_register_module(module_t *parent, const char *name, const char *title, * dialog box. */ module_t * -prefs_register_subtree(module_t *parent, const char *title, const char *description) +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, - NULL); + 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)) -{ - 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) { - pe_tree_insert_string(prefs_modules, name, module, EMEM_TREE_STRING_NOCASE); - } - - return module; - } - - module = g_malloc(sizeof (module_t)); - module->name = name; - module->title = title; - module->description = description; - module->apply_cb = apply_cb; - module->prefs = NULL; /* no preferences, to start */ - module->submodules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_submodules"); - module->numprefs = 0; - module->prefs_changed = FALSE; - module->obsolete = FALSE; - - /* - * 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. - */ - pe_tree_insert_string(prefs_modules, name, module, EMEM_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. - */ - pe_tree_insert_string(prefs_top_level_modules, title, module, EMEM_TREE_STRING_NOCASE); - } else { - /* - * It goes into the list for this module. - */ - pe_tree_insert_string(parent->submodules, title, module, EMEM_TREE_STRING_NOCASE); - } - - return module; + 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) { + pe_tree_insert_string(prefs_modules, name, module, + EMEM_TREE_STRING_NOCASE); + } + + return module; + } + + module = g_malloc(sizeof (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. + */ + pe_tree_insert_string(prefs_modules, name, module, EMEM_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. + */ + pe_tree_insert_string(prefs_top_level_modules, title, module, EMEM_TREE_STRING_NOCASE); + } else { + /* + * It goes into the list for this module. + */ + + if (parent->submodules == NULL) + parent->submodules = pe_tree_create(EMEM_TREE_TYPE_RED_BLACK, "prefs_submodules"); + + pe_tree_insert_string(parent->submodules, title, module, EMEM_TREE_STRING_NOCASE); + } + + return module; } /* * Register that a protocol has preferences. */ -module_t *protocols_module; +module_t *protocols_module = NULL; module_t * prefs_register_protocol(int id, void (*apply_cb)(void)) { - protocol_t *protocol; + protocol_t *protocol; - /* - * Have we yet created the "Protocols" subtree? - */ - if (protocols_module == NULL) { - /* - * No. Do so. - */ - protocols_module = prefs_register_subtree(NULL, "Protocols", NULL); - } - 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); + /* + * 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; - char *csubtree = NULL; - - /* - * Have we yet created the "Protocols" subtree? - */ - if (protocols_module == NULL) { - /* - * No. Do so. - */ - protocols_module = prefs_register_subtree(NULL, "Protocols", NULL); - } - - subtree_module = protocols_module; + protocol_t *protocol; + module_t *subtree_module; + module_t *new_module; + char *sep = NULL, *ptr = NULL; - if(subtree) { - /* take a copy of the buffer */ - ptr = csubtree = g_strdup(subtree); + /* + * 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(); + } - while(ptr && *ptr) { + subtree_module = protocols_module; - if((sep = strchr(ptr, '/'))) - *sep++ = '\0'; + if(subtree) { + /* take a copy of the buffer */ + ptr = g_strdup(subtree); - if(!(new_module = find_subtree(subtree_module, ptr))) { - /* create it */ - new_module = prefs_register_subtree(subtree_module, ptr, NULL); - } + while(ptr && *ptr) { - subtree_module = new_module; - ptr = sep; + 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). + */ + new_module = prefs_register_subtree(subtree_module, ptr, ptr, NULL); + } - /* g_free(csubtree); */ + subtree_module = new_module; + ptr = sep; - } + } + } - 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); + 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); } @@ -335,37 +454,69 @@ prefs_register_protocol_subtree(const char *subtree, int id, void (*apply_cb)(vo 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. Do so. - */ - protocols_module = prefs_register_subtree(NULL, "Protocols", NULL); - } - 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); - module->obsolete = TRUE; - return module; + 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 pe_tree_lookup_string(prefs_modules, name, EMEM_TREE_STRING_NOCASE); + return pe_tree_lookup_string(prefs_modules, name, EMEM_TREE_STRING_NOCASE); } static module_t * find_subtree(module_t *parent, const char *name) { - return pe_tree_lookup_string(parent ? parent->submodules : prefs_top_level_modules, name, EMEM_TREE_STRING_NOCASE); + return pe_tree_lookup_string(parent ? parent->submodules : prefs_top_level_modules, name, EMEM_TREE_STRING_NOCASE); } /* @@ -382,53 +533,54 @@ find_subtree(module_t *parent, const char *name) */ typedef struct { - module_cb callback; - gpointer user_data; - guint ret; + 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; + 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); + 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(emem_tree_t *module_list, module_cb callback, - gpointer user_data) + gpointer user_data) { - call_foreach_t call_data; + call_foreach_t call_data; - if (module_list == NULL) - module_list = prefs_top_level_modules; + if (module_list == NULL) + module_list = prefs_top_level_modules; - call_data.callback = callback; - call_data.user_data = user_data; - call_data.ret = 0; - pe_tree_foreach(module_list, call_foreach_cb, &call_data); - return call_data.ret; + call_data.callback = callback; + call_data.user_data = user_data; + call_data.ret = 0; + pe_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) +gboolean +prefs_module_has_submodules(module_t *module) { - if (module->submodules == NULL) { - return FALSE; - } + if (module->submodules == NULL) { + return FALSE; + } - if (module->submodules->tree == NULL) { - return FALSE; - } + if (module->submodules->tree == NULL) { + return FALSE; + } - return TRUE; + return TRUE; } /* @@ -442,7 +594,7 @@ gboolean prefs_module_has_submodules(module_t *module) guint prefs_modules_foreach(module_cb callback, gpointer user_data) { - return prefs_module_list_foreach(prefs_modules, callback, user_data); + return prefs_module_list_foreach(prefs_modules, callback, user_data); } /* @@ -456,24 +608,25 @@ prefs_modules_foreach(module_cb callback, gpointer user_data) * 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) +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); + 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 = value; - - if (module->obsolete) - return FALSE; - if (module->prefs_changed) { - if (module->apply_cb != NULL) - (*module->apply_cb)(); - module->prefs_changed = FALSE; - } - return FALSE; + module_t *module = value; + + if (module->obsolete) + return FALSE; + if (module->prefs_changed) { + if (module->apply_cb != NULL) + (*module->apply_cb)(); + module->prefs_changed = FALSE; + } + return FALSE; } /* @@ -485,7 +638,7 @@ call_apply_cb(void *value, void *data _U_) void prefs_apply_all(void) { - pe_tree_foreach(prefs_modules, call_apply_cb, NULL); + pe_tree_foreach(prefs_modules, call_apply_cb, NULL); } /* @@ -497,8 +650,8 @@ prefs_apply_all(void) void prefs_apply(module_t *module) { - if (module && module->prefs_changed) - call_apply_cb(module, NULL); + if (module && module->prefs_changed) + call_apply_cb(module, NULL); } /* @@ -510,87 +663,135 @@ prefs_apply(module_t *module) */ 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_malloc(sizeof (pref_t)); - 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++) - g_assert(isascii((guchar)*p) && - (islower((guchar)*p) || isdigit((guchar)*p) || *p == '_' || *p == '.')); - - /* - * 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. - */ - g_assert(prefs_find_preference(module, name) == NULL); - - if (type != PREF_OBSOLETE) { - /* - * Make sure the preference name doesn't begin with the - * module name, as that's redundant and Just Silly. - */ - g_assert((strncmp(name, module->name, strlen(module->name)) != 0) || - (((name[strlen(module->name)]) != '.') && ((name[strlen(module->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; + const char *description, pref_type_t type) +{ + pref_t *preference; + const gchar *p; + + preference = g_malloc(sizeof (pref_t)); + 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 its 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 = a; - const char *name = b; + const pref_t *pref = a; + const char *name = 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 = value; + + if (module == NULL) + return FALSE; - return strcmp(name, pref->name); + 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) { - GList *list_entry; + 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); - 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; + pe_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; + if (list_entry == NULL) + { + return NULL; /* no such preference */ + } + + return (struct preference *) list_entry->data; } /* @@ -599,9 +800,9 @@ prefs_find_preference(module_t *module, const char *name) gboolean prefs_is_registered_protocol(const char *name) { - module_t *m = prefs_find_module(name); + module_t *m = prefs_find_module(name); - return (m != NULL && !m->obsolete); + return (m != NULL && !m->obsolete); } /* @@ -610,9 +811,9 @@ prefs_is_registered_protocol(const char *name) const char * prefs_get_title_by_name(const char *name) { - module_t *m = prefs_find_module(name); + module_t *m = prefs_find_module(name); - return (m != NULL && !m->obsolete) ? m->title : NULL; + return (m != NULL && !m->obsolete) ? m->title : NULL; } /* @@ -620,15 +821,37 @@ prefs_get_title_by_name(const char *name) */ void prefs_register_uint_preference(module_t *module, const char *name, - const char *title, const char *description, guint base, guint *var) + 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; +} + +/* + * 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; + pref_t *preference; - preference = register_preference(module, name, title, description, - PREF_UINT); - preference->varp.uint = var; - g_assert(base > 0 && base != 1 && base < 37); - preference->info.base = base; + preference = register_preference(module, name, title, description, + PREF_CUSTOM); + + preference->custom_cbs = *custom_cbs; + preference->varp.uint = var; + preference->default_val.uint = *var; } /* @@ -636,13 +859,15 @@ prefs_register_uint_preference(module_t *module, const char *name, */ void prefs_register_bool_preference(module_t *module, const char *name, - const char *title, const char *description, gboolean *var) + const char *title, const char *description, + gboolean *var) { - pref_t *preference; + pref_t *preference; - preference = register_preference(module, name, title, description, - PREF_BOOL); - preference->varp.boolp = var; + preference = register_preference(module, name, title, description, + PREF_BOOL); + preference->varp.boolp = var; + preference->default_val.boolval = *var; } /* @@ -650,16 +875,52 @@ prefs_register_bool_preference(module_t *module, const char *name, */ 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) + 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; + pref_t *preference; + char *varcopy; - preference = register_preference(module, name, title, description, - PREF_ENUM); - preference->varp.enump = var; - preference->info.enum_info.enumvals = enumvals; - preference->info.enum_info.radio_buttons = radio_buttons; + 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->saved_val.string = NULL; + + return preference; } /* @@ -667,28 +928,42 @@ prefs_register_enum_preference(module_t *module, const char *name, */ void prefs_register_string_preference(module_t *module, const char *name, - const char *title, const char *description, const char **var) -{ - pref_t *preference; - - preference = register_preference(module, name, title, description, - PREF_STRING); - - /* - * 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(""); - else - *var = g_strdup(*var); - preference->varp.string = var; - preference->saved_val.string = NULL; + 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); } /* @@ -696,109 +971,1182 @@ prefs_register_string_preference(module_t *module, const char *name, */ void prefs_register_range_preference(module_t *module, const char *name, - const char *title, const char *description, range_t **var, - guint32 max_value) + 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->saved_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, + void* 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.color = 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; + 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 = 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, gchar* value, gboolean* changed) +{ + guint uval; + + uval = 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 void console_log_level_write_cb(pref_t* pref, write_pref_arg_t* arg) +{ + const char *prefix = (arg->module->name != NULL) ? arg->module->name : arg->module->parent->name; + + fprintf(arg->pf, "# (debugging only, not in the Preferences dialog)\n"); + fprintf(arg->pf, "# A bitmask of glib log levels:\n" + "# G_LOG_LEVEL_ERROR = 4\n" + "# G_LOG_LEVEL_CRITICAL = 8\n" + "# G_LOG_LEVEL_WARNING = 16\n" + "# G_LOG_LEVEL_MESSAGE = 32\n" + "# G_LOG_LEVEL_INFO = 64\n" + "# G_LOG_LEVEL_DEBUG = 128\n"); + + if (*pref->varp.uint == pref->default_val.uint) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %u\n", prefix, + pref->name, *pref->varp.uint); +} + +/* + * Column hidden custom 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); +} + +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, gchar* value, gboolean* changed) +{ + GList *clp; + fmt_data *cfmt; + pref_t *format_pref; + + if (strcmp(*pref->varp.string, value) != 0) { + *changed = TRUE; + g_free((void *)*pref->varp.string); + *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 void column_hidden_write_cb(pref_t* pref, write_pref_arg_t* arg) +{ + GString *cols_hidden = g_string_new (""); + GList *clp, *col_l; + fmt_data *cfmt; + const char *prefix = (arg->module->name != NULL) ? arg->module->name : arg->module->parent->name; + pref_t *format_pref; + + format_pref = prefs_find_preference(gui_column_module, PRS_COL_FMT); + clp = *format_pref->varp.list; + col_l = NULL; + while (clp) { + gchar *prefs_fmt; + cfmt = (fmt_data *) clp->data; + col_l = g_list_append(col_l, g_strdup(cfmt->title)); + 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)); + } + col_l = g_list_append(col_l, prefs_fmt); + if (!cfmt->visible) { + if (cols_hidden->len) { + g_string_append (cols_hidden, ","); + } + g_string_append (cols_hidden, prefs_fmt); + } + clp = clp->next; + } + fprintf (arg->pf, "\n# Packet list hidden columns.\n"); + fprintf (arg->pf, "# List all columns to hide in the packet list.\n"); + if (strcmp(cols_hidden->str, pref->default_val.string) == 0) + fprintf(arg->pf, "#"); + fprintf (arg->pf, "%s.%s: %s\n", prefix, pref->name, cols_hidden->str); + /* This frees the list of strings, but not the strings to which it + refers; they are free'ed in put_string_list(). */ + g_string_free (cols_hidden, TRUE); + g_list_free(col_l); +} + +/* 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_, gchar* value _U_, gboolean* changed _U_) +{ + /* Don't write this to the preferences file */ + return PREFS_SET_OK; +} + +static void column_num_write_cb(pref_t* pref _U_, write_pref_arg_t* arg _U_) {} + +/* + * 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 = entry->data; + dest_cfmt = (fmt_data *) g_malloc(sizeof(fmt_data)); + 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 = entry->data; + dest_cfmt = (fmt_data *) g_malloc(sizeof(fmt_data)); + 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, 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, 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 colums. + * 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 = (fmt_data *) g_malloc(sizeof(fmt_data)); + cfmt->title = g_strdup(col_l_elt->data); + col_l_elt = col_l_elt->next; + parse_column_format(cfmt, 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 void column_format_write_cb(pref_t* pref, write_pref_arg_t* arg) +{ + GList *clp = *pref->varp.list, *col_l, + *pref_col = g_list_first(clp), + *def_col = g_list_first(pref->default_val.list); + fmt_data *cfmt, *def_cfmt; + gchar *prefs_fmt; + gboolean is_default = TRUE; + pref_t *col_num_pref; + const char *prefix = (arg->module->name != NULL) ? arg->module->name : arg->module->parent->name; + + /* 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->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 ((strcmp(cfmt->title, def_cfmt->title) != 0) || + (cfmt->fmt != def_cfmt->fmt) || + (((cfmt->fmt == COL_CUSTOM) && (cfmt->custom_field)) && + ((strcmp(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; + } + } + + /* Now write the current columns */ + col_l = NULL; + while (clp) { + cfmt = (fmt_data *) clp->data; + col_l = g_list_append(col_l, g_strdup(cfmt->title)); + 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)); + } + col_l = g_list_append(col_l, prefs_fmt); + clp = clp->next; + } + + fprintf (arg->pf, "\n# Packet list column format.\n"); + fprintf (arg->pf, "# Each pair of strings consists of a column title and its format.\n"); + if (is_default) + fprintf(arg->pf, "#"); + fprintf (arg->pf, "%s.%s: %s\n", prefix, pref->name, put_string_list(col_l, is_default)); + /* This frees the list of strings, but not the strings to which it + refers; they are free'ed in put_string_list(). */ + g_list_free(col_l); +} + +/* + * Capture column custom preference functions + */ +static void capture_column_init_cb(pref_t* pref, GList** value) +{ + GList *list = *value, + *list_copy = NULL; + gchar *col; + + pref->varp.list = value; + /* Copy the current list */ + while (list) { + col = (gchar *)list->data; + list_copy = g_list_append(list_copy, g_strdup(col)); + list = list->next; + } + + pref->default_val.list = list_copy; +} + +static void capture_column_free_cb(pref_t* pref) +{ + GList *list = *pref->varp.list; + gchar *col_name; + + while (list != NULL) { + col_name = list->data; + + g_free(col_name); + list = g_list_remove_link(list, list); + } + g_list_free(list); + + list = pref->default_val.list; + while (list != NULL) { + col_name = list->data; + + g_free(col_name); + list = g_list_remove_link(list, list); + } + g_list_free(list); +} + +static void capture_column_reset_cb(pref_t* pref) +{ + GList *list_copy = *pref->varp.list, + *list = pref->default_val.list; + gchar *col_name; + + /* Clear the list before it's copied */ + while (list_copy != NULL) { + col_name = list_copy->data; + + g_free(col_name); + list_copy = g_list_remove_link(list_copy, list_copy); + } + + while (list) { + col_name = (gchar *)list->data; + list_copy = g_list_append(list_copy, g_strdup(col_name)); + list = list->next; + } +} + +static prefs_set_pref_e capture_column_set_cb(pref_t* pref, gchar* value, gboolean* changed _U_) +{ + GList *col_l, *col_l_elt; + gchar *col_name; + + col_l = prefs_get_string_list(value); + if (col_l == NULL) + return PREFS_SET_SYNTAX_ERR; + + g_list_free(*pref->varp.list); + *pref->varp.list = NULL; + + col_l_elt = g_list_first(col_l); + while(col_l_elt) { + col_name = (gchar *)col_l_elt->data; + *pref->varp.list = g_list_append(*pref->varp.list, col_name); + col_l_elt = col_l_elt->next; + } + + return PREFS_SET_OK; +} + +static void capture_column_write_cb(pref_t* pref, write_pref_arg_t* arg) +{ + GList *clp = *pref->varp.list, + *col_l = NULL, + *pref_col = g_list_first(clp), + *def_col = g_list_first(pref->default_val.list); + gchar *col, *def_col_str; + gboolean is_default = TRUE; + const char *prefix = (arg->module->name != NULL) ? arg->module->name : arg->module->parent->name; + + /* See if the column data has changed from the default */ + while (pref_col && def_col) { + col = (gchar *)pref_col->data; + def_col_str = (gchar *) def_col->data; + if (strcmp(col, def_col_str) != 0) { + is_default = FALSE; + break; + } + + pref_col = pref_col->next; + def_col = def_col->next; + } + + /* Ensure the same column count */ + if (((pref_col == NULL) && (def_col != NULL)) || + ((pref_col != NULL) && (def_col == NULL))) + is_default = FALSE; + + while (clp) { + col = (gchar *) clp->data; + col_l = g_list_append(col_l, g_strdup(col)); + clp = clp->next; + } + + fprintf(arg->pf, "\n# Capture options dialog column list.\n"); + fprintf(arg->pf, "# List of columns to be displayed.\n"); + fprintf(arg->pf, "# Possible values: INTERFACE,LINK,PMODE,SNAPLEN,MONITOR,BUFFER,FILTER\n"); + if (is_default) + fprintf(arg->pf, "#"); + fprintf (arg->pf, "%s.%s: %s\n", prefix, pref->name, put_string_list(col_l, is_default)); + /* This frees the list of strings, but not the strings to which it + refers; they are free'ed in put_string_list(). */ + g_list_free(col_l); + +} + + +static void colorized_frame_free_cb(pref_t* pref) +{ + g_free((char *)*pref->varp.string); + *pref->varp.string = NULL; + g_free(pref->default_val.string); +} + +static void colorized_frame_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 colorized_frame_set_cb(pref_t* pref, gchar* value, gboolean* changed) +{ + if (strcmp(*pref->varp.string, value) != 0) { + *changed = TRUE; + g_free((void *)*pref->varp.string); + *pref->varp.string = g_strdup(value); + } + + return PREFS_SET_OK; +} + +static void colorized_frame_write_cb(pref_t* pref _U_, write_pref_arg_t* arg _U_) +{ + /* Don't write the colors of the 10 easy-access-colorfilters to the preferences + * file until the colors can be changed in the GUI. Currently this is not really + * possible since the STOCK-icons for these colors are hardcoded. + * + * XXX Find a way to change the colors of the STOCK-icons on the fly and then + * add these 10 colors to the list of colors that can be changed through + * the preferences. + * + */ +} + +/* + * Register all non-dissector modules' preferences. + */ +static module_t *gui_module = NULL; +static module_t *gui_color_module = NULL; +static module_t *nameres_module = NULL; + +void +prefs_register_modules(void) +{ + module_t *printing, *capture_module, *console_module, + *gui_layout_module, *gui_font_module; + struct pref_custom_cbs custom_cbs; + + if (protocols_module != NULL) { + /* Already setup preferences */ + return; + } + + /* Ensure the "global" preferences have been initialized so the + * preference API has the proper default values to work from + */ + pre_init_prefs(); + + /* GUI + * These are "simple" GUI preferences that can be read/written using the + * preference module API. These preferences still use their own + * configuration screens for access, but this cuts down on the + * preference "string compare list" in set_pref() + */ + gui_module = prefs_register_module(NULL, "gui", "User Interface", + "User Interface", &gui_callback, FALSE); + + prefs_register_bool_preference(gui_module, "scrollbar_on_right", + "Vertical scrollbars on right side", + "Vertical scrollbars should be on right side?", + &prefs.gui_scrollbar_on_right); + + prefs_register_bool_preference(gui_module, "packet_list_sel_browse", + "Packet-list selection bar browse", + "Packet-list selection bar can be used to browse w/o selecting?", + &prefs.gui_plist_sel_browse); + + prefs_register_bool_preference(gui_module, "protocol_tree_sel_browse", + "Protocol-tree selection bar browse", + "Protocol-tree selection bar can be used to browse w/o selecting?", + &prefs.gui_ptree_sel_browse); + + prefs_register_bool_preference(gui_module, "tree_view_altern_colors", + "Alternating colors in TreeViews", + "Alternating colors in TreeViews?", + &prefs.gui_altern_colors); + + prefs_register_bool_preference(gui_module, "expert_composite_eyecandy", + "Display LEDs on Expert Composite Dialog Tabs", + "Display LEDs on Expert Composite Dialog Tabs?", + &prefs.gui_expert_composite_eyecandy); + + prefs_register_bool_preference(gui_module, "filter_toolbar_show_in_statusbar", + "Place filter toolbar inside the statusbar", + "Place filter toolbar inside the statusbar?", + &prefs.filter_toolbar_show_in_statusbar); + + prefs_register_enum_preference(gui_module, "protocol_tree_line_style", + "Protocol-tree line style", + "Protocol-tree line style", + &prefs.gui_ptree_line_style, gui_ptree_line_style, FALSE); + + prefs_register_enum_preference(gui_module, "protocol_tree_expander_style", + "Protocol-tree expander style", + "Protocol-tree expander style", + &prefs.gui_ptree_expander_style, gui_ptree_expander_style, FALSE); + + prefs_register_enum_preference(gui_module, "hex_dump_highlight_style", + "Hex dump highlight style", + "Hex dump highlight style", + &prefs.gui_hex_dump_highlight_style, gui_hex_dump_highlight_style, FALSE); + + gui_column_module = prefs_register_subtree(gui_module, "Columns", "Columns", NULL); + + custom_cbs.free_cb = column_hidden_free_cb; + custom_cbs.reset_cb = column_hidden_reset_cb; + custom_cbs.set_cb = column_hidden_set_cb; + custom_cbs.write_cb = column_hidden_write_cb; + prefs_register_string_custom_preference(gui_column_module, PRS_COL_HIDDEN, "Packet list hidden columns", + "List all columns to hide in the packet list", &custom_cbs, (const char **)&cols_hidden_list); + + custom_cbs.free_cb = column_format_free_cb; + custom_cbs.reset_cb = column_format_reset_cb; + custom_cbs.set_cb = column_format_set_cb; + custom_cbs.write_cb = column_format_write_cb; + + prefs_register_list_custom_preference(gui_column_module, PRS_COL_FMT, "Packet list column format", + "Each pair of strings consists of a column title and its format", &custom_cbs, + column_format_init_cb, &prefs.col_list); + + /* Number of columns. This is only used internally and is not written to the + * preference file + */ + custom_cbs.free_cb = custom_pref_no_cb; + custom_cbs.reset_cb = column_num_reset_cb; + custom_cbs.set_cb = column_num_set_cb; + custom_cbs.write_cb = column_num_write_cb; + prefs_register_uint_custom_preference(gui_column_module, PRS_COL_NUM, "Number of columns", + "Number of columns in col_list", &custom_cbs, &prefs.num_cols); + + /* User Interface : Font */ + gui_font_module = prefs_register_subtree(gui_module, "Font", "Font", NULL); + + prefs_register_obsolete_preference(gui_font_module, "font_name"); + + prefs_register_string_preference(gui_font_module, "gtk2.font_name", "Font name", + "Font name for packet list, protocol tree, and hex dump panes.", (const char**)(&prefs.gui_font_name)); + + /* User Interface : Colors */ + gui_color_module = prefs_register_subtree(gui_module, "Colors", "Colors", NULL); + + prefs_register_color_preference(gui_color_module, "marked_frame.fg", "Color preferences for a marked frame", + "Color preferences for a marked frame", &prefs.gui_marked_fg); + + prefs_register_color_preference(gui_color_module, "marked_frame.bg", "Color preferences for a marked frame", + "Color preferences for a marked frame", &prefs.gui_marked_bg); + + prefs_register_color_preference(gui_color_module, "ignored_frame.fg", "Color preferences for a ignored frame", + "Color preferences for a ignored frame", &prefs.gui_ignored_fg); + + prefs_register_color_preference(gui_color_module, "ignored_frame.bg", "Color preferences for a ignored frame", + "Color preferences for a ignored frame", &prefs.gui_ignored_bg); + + prefs_register_color_preference(gui_color_module, "stream.client.fg", "TCP stream window color preference", + "TCP stream window color preference", &prefs.st_client_fg); + + prefs_register_color_preference(gui_color_module, "stream.client.bg", "TCP stream window color preference", + "TCP stream window color preference", &prefs.st_client_bg); + + prefs_register_color_preference(gui_color_module, "stream.server.fg", "TCP stream window color preference", + "TCP stream window color preference", &prefs.st_server_fg); + + prefs_register_color_preference(gui_color_module, "stream.server.bg", "TCP stream window color preference", + "TCP stream window color preference", &prefs.st_server_bg); + + custom_cbs.free_cb = colorized_frame_free_cb; + custom_cbs.reset_cb = colorized_frame_reset_cb; + custom_cbs.set_cb = colorized_frame_set_cb; + custom_cbs.write_cb = colorized_frame_write_cb; + prefs_register_string_custom_preference(gui_column_module, "colorized_frame.fg", "Colorized Foreground", + "Filter Colorized Foreground", &custom_cbs, (const char **)&prefs.gui_colorized_fg); + + custom_cbs.free_cb = colorized_frame_free_cb; + custom_cbs.reset_cb = colorized_frame_reset_cb; + custom_cbs.set_cb = colorized_frame_set_cb; + custom_cbs.write_cb = colorized_frame_write_cb; + prefs_register_string_custom_preference(gui_column_module, "colorized_frame.bg", "Colorized Background", + "Filter Colorized Background", &custom_cbs, (const char **)&prefs.gui_colorized_bg); + + prefs_register_enum_preference(gui_module, "console_open", + "Open a console window", + "Open a console window (WIN32 only)", + (gint*)(void*)(&prefs.gui_console_open), gui_console_open_type, FALSE); + + prefs_register_enum_preference(gui_module, "fileopen.style", + "Where to start the File Open dialog box", + "Where to start the File Open dialog box", + &prefs.gui_fileopen_style, gui_fileopen_style, FALSE); + + prefs_register_uint_preference(gui_module, "recent_files_count.max", + "The max. number of items in the open recent files list", + "The max. number of items in the open recent files list", + 10, + &prefs.gui_recent_files_count_max); + + prefs_register_uint_preference(gui_module, "recent_display_filter_entries.max", + "The max. number of entries in the display filter list", + "The max. number of entries in the display filter list", + 10, + &prefs.gui_recent_df_entries_max); + + prefs_register_string_preference(gui_module, "fileopen.dir", "Start Directory", + "Directory to start in when opening File Open dialog.", (const char**)(&prefs.gui_fileopen_dir)); + + prefs_register_obsolete_preference(gui_module, "fileopen.remembered_dir"); + + prefs_register_uint_preference(gui_module, "fileopen.preview", + "The preview timeout in the File Open dialog", + "The preview timeout in the File Open dialog", + 10, + &prefs.gui_fileopen_preview); + + prefs_register_bool_preference(gui_module, "ask_unsaved", + "Ask to save unsaved capture files", + "Ask to save unsaved capture files?", + &prefs.gui_ask_unsaved); + + prefs_register_bool_preference(gui_module, "find_wrap", + "Wrap to beginning/end of file during search", + "Wrap to beginning/end of file during search?", + &prefs.gui_find_wrap); + + prefs_register_bool_preference(gui_module, "use_pref_save", + "Settings dialogs use a save button", + "Settings dialogs use a save button?", + &prefs.gui_use_pref_save); + + prefs_register_bool_preference(gui_module, "geometry.save.position", + "Save window position at exit", + "Save window position at exit?", + &prefs.gui_geometry_save_position); + + prefs_register_bool_preference(gui_module, "geometry.save.size", + "Save window size at exit", + "Save window size at exit?", + &prefs.gui_geometry_save_size); + + prefs_register_bool_preference(gui_module, "geometry.save.maximized", + "Save window maximized state at exit", + "Save window maximized state at exit?", + &prefs.gui_geometry_save_maximized); + + prefs_register_bool_preference(gui_module, "macosx_style", + "Use Mac OS X style", + "Use Mac OS X style (Mac OS X with native GTK only)?", + &prefs.gui_macosx_style); + + prefs_register_obsolete_preference(gui_module, "geometry.main.x"); + prefs_register_obsolete_preference(gui_module, "geometry.main.y"); + prefs_register_obsolete_preference(gui_module, "geometry.main.width"); + prefs_register_obsolete_preference(gui_module, "geometry.main.height"); + prefs_register_obsolete_preference(gui_module, "toolbar_main_show"); + + prefs_register_enum_preference(gui_module, "toolbar_main_style", + "Main Toolbar style", + "Main Toolbar style", + &prefs.gui_toolbar_main_style, gui_toolbar_style, FALSE); + + prefs_register_enum_preference(gui_module, "toolbar_filter_style", + "Filter Toolbar style", + "Filter Toolbar style", + &prefs.gui_toolbar_filter_style, gui_toolbar_style, FALSE); + + prefs_register_string_preference(gui_module, "webbrowser", "The path to the webbrowser", + "The path to the webbrowser (Ex: mozilla)", (const char**)(&prefs.gui_webbrowser)); + + prefs_register_string_preference(gui_module, "window_title", "Custom window title", + "Custom window title. (Appended to existing titles.)", (const char**)(&prefs.gui_window_title)); + + prefs_register_string_preference(gui_module, "start_title", "Custom start page title", + "Custom start page title", (const char**)(&prefs.gui_start_title)); + + prefs_register_enum_preference(gui_module, "version_placement", + "Show version in the start page and/or main screen's title bar", + "Show version in the start page and/or main screen's title bar", + (gint*)(void*)(&prefs.gui_version_placement), gui_version_placement_type, FALSE); + + prefs_register_bool_preference(gui_module, "auto_scroll_on_expand", + "Automatically scroll the recently expanded item", + "Automatically scroll the recently expanded item", + &prefs.gui_auto_scroll_on_expand); + + prefs_register_uint_preference(gui_module, "auto_scroll_percentage", + "The percentage down the view the recently expanded item should be scrolled", + "The percentage down the view the recently expanded item should be scrolled", + 10, + &prefs.gui_auto_scroll_percentage); + + /* User Interface : Layout */ + gui_layout_module = prefs_register_subtree(gui_module, "Layout", "Layout", gui_layout_callback); + + prefs_register_uint_preference(gui_layout_module, "layout_type", + "Layout type", + "Layout type (1-6)", + 10, + (guint*)(void*)(&prefs.gui_layout_type)); + + prefs_register_enum_preference(gui_layout_module, "layout_content_1", + "Layout content of the pane 1", + "Layout content of the pane 1", + (gint*)(void*)(&prefs.gui_layout_content_1), gui_layout_content, FALSE); + + prefs_register_enum_preference(gui_layout_module, "layout_content_2", + "Layout content of the pane 2", + "Layout content of the pane 2", + (gint*)(void*)(&prefs.gui_layout_content_2), gui_layout_content, FALSE); + + prefs_register_enum_preference(gui_layout_module, "layout_content_3", + "Layout content of the pane 3", + "Layout content of the pane 3", + (gint*)(void*)(&prefs.gui_layout_content_3), gui_layout_content, FALSE); + + /* Console + * These are preferences that can be read/written using the + * preference module API. These preferences still use their own + * configuration screens for access, but this cuts down on the + * preference "string compare list" in set_pref() + */ + console_module = prefs_register_module(NULL, "console", "Console", + "CONSOLE", NULL, FALSE); + + custom_cbs.free_cb = custom_pref_no_cb; + custom_cbs.reset_cb = console_log_level_reset_cb; + custom_cbs.set_cb = console_log_level_set_cb; + custom_cbs.write_cb = console_log_level_write_cb; + prefs_register_uint_custom_preference(console_module, "log.level", "logging level", + "A bitmask of glib log levels", &custom_cbs, &prefs.console_log_level); + + /* Capture + * These are preferences that can be read/written using the + * preference module API. These preferences still use their own + * configuration screens for access, but this cuts down on the + * preference "string compare list" in set_pref() + */ + capture_module = prefs_register_module(NULL, "capture", "Capture", + "CAPTURE", NULL, FALSE); + + prefs_register_string_preference(capture_module, "device", "Default capture device", + "Default capture device", (const char**)(&prefs.capture_device)); + + prefs_register_string_preference(capture_module, "devices_linktypes", "Interface link-layer header type", + "Interface link-layer header types (Ex: en0(1),en1(143),...)", + (const char**)(&prefs.capture_devices_linktypes)); + + prefs_register_string_preference(capture_module, "devices_descr", "Interface descriptions", + "Interface descriptions (Ex: eth0(eth0 descr),eth1(eth1 descr),...)", + (const char**)(&prefs.capture_devices_descr)); + + prefs_register_string_preference(capture_module, "devices_hide", "Hide interface", + "Hide interface? (Ex: eth0,eth3,...)", (const char**)(&prefs.capture_devices_hide)); + + prefs_register_string_preference(capture_module, "devices_monitor_mode", "Capture in monitor mode", + "By default, capture in monitor mode on interface? (Ex: eth0,eth3,...)", + (const char**)(&prefs.capture_devices_monitor_mode)); + + prefs_register_bool_preference(capture_module, "prom_mode", "Capture in promiscuous mode", + "Capture in promiscuous mode?", &prefs.capture_prom_mode); + + prefs_register_bool_preference(capture_module, "pcap_ng", "Capture in Pcap-NG format", + "Capture in Pcap-NG format?", &prefs.capture_pcap_ng); + + prefs_register_bool_preference(capture_module, "real_time_update", "Update packet list in real time during capture", + "Update packet list in real time during capture?", &prefs.capture_real_time); + + prefs_register_bool_preference(capture_module, "auto_scroll", "Scroll packet list during capture", + "Scroll packet list during capture?", &prefs.capture_auto_scroll); + + prefs_register_bool_preference(capture_module, "show_info", "Show capture info dialog while capturing", + "Show capture info dialog while capturing?", &prefs.capture_show_info); + + prefs_register_obsolete_preference(capture_module, "syntax_check_filter"); + + custom_cbs.free_cb = capture_column_free_cb; + custom_cbs.reset_cb = capture_column_reset_cb; + custom_cbs.set_cb = capture_column_set_cb; + custom_cbs.write_cb = capture_column_write_cb; + prefs_register_list_custom_preference(capture_module, "columns", "Capture options dialog column list", + "List of columns to be displayed", &custom_cbs, capture_column_init_cb, &prefs.capture_columns); - preference = register_preference(module, name, title, description, - PREF_RANGE); - preference->info.max_value = max_value; + /* Name Resolution */ + nameres_module = prefs_register_module(NULL, "nameres", "Name Resolution", + "Name Resolution", NULL, TRUE); + addr_resolve_pref_init(nameres_module); + oid_pref_init(nameres_module); +#ifdef HAVE_GEOIP + geoip_db_pref_init(nameres_module); +#endif + /* Printing */ + printing = prefs_register_module(NULL, "print", "Printing", + "Printing", NULL, TRUE); - /* - * 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->saved_val.range = NULL; -} + prefs_register_enum_preference(printing, "format", + "Format", "Can be one of \"text\" or \"postscript\"", + &prefs.pr_format, print_format_vals, TRUE); -/* - * 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); -} + prefs_register_enum_preference(printing, "destination", + "Print to", "Can be one of \"command\" or \"file\"", + &prefs.pr_dest, print_dest_vals, TRUE); -/* - * 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, - void* uat) { +#ifndef _WIN32 + prefs_register_string_preference(printing, "command", "Command", + "Output gets piped to this command when the destination is set to \"command\"", (const char**)(&prefs.pr_cmd)); +#endif - pref_t* preference = register_preference(module, name, title, description, PREF_UAT); + prefs_register_filename_preference(printing, "file", "File", + "This is the file that gets written to when the destination is set to \"file\"", (const char**)(&prefs.pr_file)); - preference->varp.uat = uat; -} + /* Statistics */ + stats_module = prefs_register_module(NULL, "statistics", "Statistics", + "Statistics", &stats_callback, TRUE); + prefs_register_uint_preference(stats_module, "update_interval", + "Tap update interval in ms", + "Determines time between tap updates", + 10, + &prefs.tap_update_interval); +#ifdef HAVE_LIBPORTAUDIO + prefs_register_uint_preference(stats_module, "rtp_player_max_visible", + "Max visible channels in RTP Player", + "Determines maximum height of RTP Player window", + 10, + &prefs.rtp_player_max_visible); +#endif -/* - * 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); -} -/* - * 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 = 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; -} + /* Protocols */ + protocols_module = prefs_register_module(NULL, "protocols", "Protocols", + "Protocols", NULL, TRUE); + + prefs_register_bool_preference(protocols_module, "display_hidden_proto_items", + "Display hidden protocol items", + "Display all hidden protocol items in the packet list.", + &prefs.display_hidden_proto_items); + + /* Obsolete preferences + * These "modules" were reorganized/renamed to correspond to their GUI + * configuration screen within the preferences dialog + */ + + /* taps is now part of the stats module */ + prefs_register_module(NULL, "taps", "TAPS", "TAPS", NULL, FALSE); + /* packet_list is now part of the protocol (parent) module */ + prefs_register_module(NULL, "packet_list", "PACKET_LIST", "PACKET_LIST", NULL, FALSE); + /* stream is now part of the gui module */ + prefs_register_module(NULL, "stream", "STREAM", "STREAM", NULL, FALSE); -/* - * Register all non-dissector modules' preferences. - */ -void -prefs_register_modules(void) -{ } /* Parse through a list of comma-separated, possibly quoted strings. @@ -896,18 +2244,20 @@ prefs_get_string_list(gchar *str) #define MAX_FMT_PREF_LEN 1024 #define MAX_FMT_PREF_LINE_LEN 60 static gchar * -put_string_list(GList *sl) +put_string_list(GList *sl, gboolean is_default) { static gchar pref_str[MAX_FMT_PREF_LEN] = ""; GList *clp = g_list_first(sl); gchar *str; - size_t cur_pos = 0, cur_len = 0; + size_t cur_len = 0; gchar *quoted_str; size_t str_len; gchar *strp, *quoted_strp, c; size_t fmt_len; + guint item_count = 0; while (clp) { + item_count++; str = clp->data; /* Allocate a buffer big enough to hold the entire string, with each @@ -929,18 +2279,20 @@ put_string_list(GList *sl) fmt_len = strlen(quoted_str) + 4; if ((fmt_len + cur_len) < (MAX_FMT_PREF_LEN - 1)) { - if ((fmt_len + cur_pos) > MAX_FMT_PREF_LINE_LEN) { + if (item_count % 2) { /* Wrap the line. */ - cur_len--; - cur_pos = 0; + if (cur_len > 0) cur_len--; pref_str[cur_len] = '\n'; cur_len++; + if (is_default) { + pref_str[cur_len] = '#'; cur_len++; + } pref_str[cur_len] = '\t'; cur_len++; } g_snprintf(&pref_str[cur_len], MAX_FMT_PREF_LEN - (gulong) cur_len, "\"%s\", ", quoted_str); - cur_pos += fmt_len; cur_len += fmt_len; } g_free(quoted_str); + g_free(str); clp = clp->next; } @@ -982,42 +2334,23 @@ prefs_clear_string_list(GList *sl) * Otherwise, the default value that was passed as the third argument is * returned. */ -gint +static gint find_val_for_string(const char *needle, const enum_val_t *haystack, - gint default_value) -{ - int i; - - for (i = 0; haystack[i].name != NULL; i++) { - if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) { - return haystack[i].value; - } - } - for (i = 0; haystack[i].name != NULL; i++) { - if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) { - return haystack[i].value; - } - } - return default_value; -} - -/* Takes an string and a pointer to an array of strings, and a default int value. - * The array must be terminated by a NULL string. If the string is found in the array - * of strings, the index of that string in the array is returned. Otherwise, the - * default value that was passed as the third argument is returned. - */ -static int -find_index_from_string_array(char *needle, const char **haystack, int default_value) + gint default_value) { - int i = 0; + int i; - while (haystack[i] != NULL) { - if (strcmp(needle, haystack[i]) == 0) { - return i; - } - i++; - } - return default_value; + for (i = 0; haystack[i].name != NULL; i++) { + if (g_ascii_strcasecmp(needle, haystack[i].name) == 0) { + return haystack[i].value; + } + } + for (i = 0; haystack[i].name != NULL; i++) { + if (g_ascii_strcasecmp(needle, haystack[i].description) == 0) { + return haystack[i].value; + } + } + return default_value; } /* Preferences file format: @@ -1031,67 +2364,152 @@ find_index_from_string_array(char *needle, const char **haystack, int default_va # This is a comment line print.command: lpr print.file: /a/very/long/path/ - to/wireshark-out.ps + to/wireshark-out.ps * */ -#define DEF_NUM_COLS 6 +#define DEF_NUM_COLS 7 + +/* + * Parse a column format, filling in the relevant fields of a fmt_data. + */ +static gboolean +parse_column_format(fmt_data *cfmt, const char *fmt) +{ + const gchar *cust_format = col_format_to_string(COL_CUSTOM); + size_t cust_format_len = strlen(cust_format); + gchar **cust_format_info; + char *p; + int col_fmt; + gchar *col_custom_field; + long col_custom_occurrence; + gboolean col_resolved; + + /* + * Is this a custom column? + */ + if ((strlen(fmt) > cust_format_len) && (fmt[cust_format_len] == ':') && + strncmp(fmt, cust_format, cust_format_len) == 0) { + /* Yes. */ + col_fmt = COL_CUSTOM; + cust_format_info = g_strsplit(&fmt[cust_format_len+1],":",3); /* add 1 for ':' */ + col_custom_field = g_strdup(cust_format_info[0]); + if (col_custom_field && cust_format_info[1]) { + col_custom_occurrence = strtol(cust_format_info[1], &p, 10); + if (p == cust_format_info[1] || *p != '\0') { + /* Not a valid number. */ + g_free(col_custom_field); + g_strfreev(cust_format_info); + return FALSE; + } + } else { + col_custom_occurrence = 0; + } + if (col_custom_field && cust_format_info[1] && cust_format_info[2]) { + col_resolved = (cust_format_info[2][0] == 'U') ? FALSE : TRUE; + } else { + col_resolved = TRUE; + } + g_strfreev(cust_format_info); + } else { + col_fmt = get_column_format_from_str(fmt); + if (col_fmt == -1) + return FALSE; + col_custom_field = NULL; + col_custom_occurrence = 0; + col_resolved = TRUE; + } + + cfmt->fmt = col_fmt; + cfmt->custom_field = col_custom_field; + cfmt->custom_occurrence = (int)col_custom_occurrence; + cfmt->resolved = col_resolved; + return TRUE; +} -/* Initialize preferences to wired-in default values. +/* Initialize non-dissector preferences to wired-in default values. + * (The dissector preferences are assumed to be set to those values + * by the dissectors.) * They may be overridden by the global preferences file or the * user's preferences file. */ static void -init_prefs(void) { - int i; - fmt_data *cfmt; - const gchar *col_fmt[] = {"No.", "%m", "Time", "%t", - "Source", "%s", "Destination", "%d", - "Protocol", "%p", "Info", "%i"}; - +init_prefs(void) +{ if (prefs_initialized) return; uat_load_all(); + pre_init_prefs(); + + filter_expression_init(TRUE); + + prefs_initialized = TRUE; +} + +/* Initialize non-dissector preferences used by the "register preference" API + * to default values so the default values can be used when registered + */ +static void +pre_init_prefs(void) +{ + int i; + gchar *col_name; + fmt_data *cfmt; + static const gchar *col_fmt[DEF_NUM_COLS*2] = { + "No.", "%m", "Time", "%t", + "Source", "%s", "Destination", "%d", + "Protocol", "%p", "Length", "%L", + "Info", "%i"}; +#if defined(HAVE_PCAP_CREATE) + static gint num_capture_cols = 7; + static const gchar *capture_cols[7] = { + "INTERFACE", + "LINK", + "PMODE", + "SNAPLEN", + "MONITOR", + "BUFFER", + "FILTER"}; +#elif defined(_WIN32) && !defined (HAVE_PCAP_CREATE) + static gint num_capture_cols = 6; + static const gchar *capture_cols[6] = { + "INTERFACE", + "LINK", + "PMODE", + "SNAPLEN", + "BUFFER", + "FILTER"}; +#else + static gint num_capture_cols = 5; + static const gchar *capture_cols[5] = { + "INTERFACE", + "LINK", + "PMODE", + "SNAPLEN", + "FILTER"}; +#endif + + if (prefs_pre_initialized) + return; + prefs.pr_format = PR_FMT_TEXT; prefs.pr_dest = PR_DEST_CMD; prefs.pr_file = g_strdup("wireshark.out"); prefs.pr_cmd = g_strdup("lpr"); - prefs.col_list = NULL; - for (i = 0; i < DEF_NUM_COLS; i++) { - cfmt = (fmt_data *) g_malloc(sizeof(fmt_data)); - cfmt->title = g_strdup(col_fmt[i * 2]); - cfmt->fmt = g_strdup(col_fmt[(i * 2) + 1]); - cfmt->custom_field = NULL; - prefs.col_list = g_list_append(prefs.col_list, cfmt); - } - prefs.num_cols = DEF_NUM_COLS; - prefs.st_client_fg.pixel = 0; - prefs.st_client_fg.red = 32767; - prefs.st_client_fg.green = 0; - prefs.st_client_fg.blue = 0; - prefs.st_client_bg.pixel = 0; - prefs.st_client_bg.red = 64507; - prefs.st_client_bg.green = 60909; - prefs.st_client_bg.blue = 60909; - prefs.st_server_fg.pixel = 0; - prefs.st_server_fg.red = 0; - prefs.st_server_fg.green = 0; - prefs.st_server_fg.blue = 32767; - prefs.st_server_bg.pixel = 0; - prefs.st_server_bg.red = 60909; - prefs.st_server_bg.green = 60909; - prefs.st_server_bg.blue = 64507; + prefs.gui_scrollbar_on_right = TRUE; prefs.gui_plist_sel_browse = FALSE; prefs.gui_ptree_sel_browse = FALSE; prefs.gui_altern_colors = FALSE; + prefs.gui_expert_composite_eyecandy = FALSE; prefs.gui_ptree_line_style = 0; prefs.gui_ptree_expander_style = 1; prefs.gui_hex_dump_highlight_style = 1; prefs.filter_toolbar_show_in_statusbar = FALSE; prefs.gui_toolbar_main_style = TB_STYLE_ICONS; + prefs.gui_toolbar_filter_style = TB_STYLE_TEXT; #ifdef _WIN32 prefs.gui_font_name = g_strdup("Lucida Console 10"); #else @@ -1152,11 +2570,35 @@ init_prefs(void) { prefs.gui_marked_bg.red = 0; prefs.gui_marked_bg.green = 0; prefs.gui_marked_bg.blue = 0; + prefs.gui_ignored_fg.pixel = 32767; + prefs.gui_ignored_fg.red = 32767; + prefs.gui_ignored_fg.green = 32767; + prefs.gui_ignored_fg.blue = 32767; + prefs.gui_ignored_bg.pixel = 65535; + prefs.gui_ignored_bg.red = 65535; + prefs.gui_ignored_bg.green = 65535; + prefs.gui_ignored_bg.blue = 65535; prefs.gui_colorized_fg = g_strdup("000000,000000,000000,000000,000000,000000,000000,000000,000000,000000"); prefs.gui_colorized_bg = g_strdup("ffc0c0,ffc0ff,e0c0e0,c0c0ff,c0e0e0,c0ffff,c0ffc0,ffffc0,e0e0c0,e0e0e0"); - prefs.gui_geometry_save_position = FALSE; - prefs.gui_geometry_save_size = TRUE; - prefs.gui_geometry_save_maximized= TRUE; + prefs.st_client_fg.pixel = 0; + prefs.st_client_fg.red = 32767; + prefs.st_client_fg.green = 0; + prefs.st_client_fg.blue = 0; + prefs.st_client_bg.pixel = 0; + prefs.st_client_bg.red = 64507; + prefs.st_client_bg.green = 60909; + prefs.st_client_bg.blue = 60909; + prefs.st_server_fg.pixel = 0; + prefs.st_server_fg.red = 0; + prefs.st_server_fg.green = 0; + prefs.st_server_fg.blue = 32767; + prefs.st_server_bg.pixel = 0; + prefs.st_server_bg.red = 60909; + prefs.st_server_bg.green = 60909; + prefs.st_server_bg.blue = 64507; + prefs.gui_geometry_save_position = FALSE; + prefs.gui_geometry_save_size = TRUE; + prefs.gui_geometry_save_maximized= TRUE; prefs.gui_macosx_style = TRUE; prefs.gui_console_open = console_open_never; prefs.gui_fileopen_style = FO_STYLE_LAST_OPENED; @@ -1170,36 +2612,135 @@ init_prefs(void) { prefs.gui_webbrowser = g_strdup(HTML_VIEWER " %s"); prefs.gui_window_title = g_strdup(""); prefs.gui_start_title = g_strdup("The World's Most Popular Network Protocol Analyzer"); - prefs.gui_version_in_start_page = FALSE; + prefs.gui_version_placement = version_both; + prefs.gui_auto_scroll_on_expand = FALSE; + prefs.gui_auto_scroll_percentage = 0; prefs.gui_layout_type = layout_type_5; prefs.gui_layout_content_1 = layout_pane_content_plist; prefs.gui_layout_content_2 = layout_pane_content_pdetails; prefs.gui_layout_content_3 = layout_pane_content_pbytes; - prefs.console_log_level = - G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR; + + prefs.col_list = NULL; + for (i = 0; i < DEF_NUM_COLS; i++) { + cfmt = (fmt_data *) g_malloc(sizeof(fmt_data)); + cfmt->title = g_strdup(col_fmt[i * 2]); + parse_column_format(cfmt, col_fmt[(i * 2) + 1]); + cfmt->visible = TRUE; + cfmt->resolved = TRUE; + cfmt->custom_field = NULL; + cfmt->custom_occurrence = 0; + prefs.col_list = g_list_append(prefs.col_list, cfmt); + } + prefs.num_cols = DEF_NUM_COLS; /* set the default values for the capture dialog box */ - prefs.capture_device = NULL; - prefs.capture_devices_linktypes= NULL; - prefs.capture_devices_descr = NULL; - prefs.capture_devices_hide = NULL; - prefs.capture_prom_mode = TRUE; - prefs.capture_pcap_ng = FALSE; - prefs.capture_real_time = TRUE; - prefs.capture_auto_scroll = TRUE; - prefs.capture_show_info = FALSE; - -/* set the default values for the name resolution dialog box */ - prefs.name_resolve = RESOLV_ALL ^ RESOLV_NETWORK; - prefs.name_resolve_concurrency = 500; + prefs.capture_prom_mode = TRUE; +#ifdef PCAP_NG_DEFAULT + prefs.capture_pcap_ng = TRUE; +#else + prefs.capture_pcap_ng = FALSE; +#endif + prefs.capture_real_time = TRUE; + prefs.capture_auto_scroll = TRUE; + prefs.capture_show_info = FALSE; + + prefs.capture_columns = NULL; + for (i = 0; i < num_capture_cols; i++) { + col_name = g_strdup(capture_cols[i]); + prefs.capture_columns = g_list_append(prefs.capture_columns, col_name); + } + + prefs.console_log_level = + G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR; /* set the default values for the tap/statistics dialog box */ - prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL; + prefs.tap_update_interval = TAP_UPDATE_DEFAULT_INTERVAL; prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE; prefs.display_hidden_proto_items = FALSE; - prefs_initialized = TRUE; + prefs_pre_initialized = TRUE; +} + +/* + * Reset a single dissector preference. + */ +static void +reset_pref(gpointer data, gpointer user_data _U_) +{ + pref_t *pref = data; + + switch (pref->type) { + + case PREF_UINT: + *pref->varp.uint = pref->default_val.uint; + break; + + case PREF_BOOL: + *pref->varp.boolp = pref->default_val.boolval; + break; + + case PREF_ENUM: + /* + * For now, we save the "description" value, so that if we + * save the preferences older versions of Wireshark can at + * least read preferences that they supported; we support + * either the short name or the description when reading + * the preferences file or a "-o" option. + */ + *pref->varp.enump = pref->default_val.enumval; + break; + + case PREF_STRING: + case PREF_FILENAME: + g_free((void *)*pref->varp.string); + *pref->varp.string = g_strdup(pref->default_val.string); + break; + + case PREF_RANGE: + g_free(*pref->varp.range); + *pref->varp.range = range_copy(pref->default_val.range); + break; + + case PREF_STATIC_TEXT: + case PREF_UAT: + /* Nothing to do */ + break; + + case PREF_COLOR: + *pref->varp.color = pref->default_val.color; + break; + + case PREF_CUSTOM: + pref->custom_cbs.reset_cb(pref); + break; + + case PREF_OBSOLETE: + /* + * This preference is no longer supported; it's not a + * real preference, so we don't reset 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). + */ + break; + } +} + +typedef struct { + module_t *module; +} reset_pref_arg_t; + +/* + * Reset all preferences for a module. + */ +static gboolean +reset_module_prefs(void *value, void *data _U_) +{ + reset_pref_arg_t arg; + + arg.module = value; + g_list_foreach(arg.module->prefs, reset_pref, &arg); + return FALSE; } /* Reset preferences */ @@ -1208,23 +2749,25 @@ prefs_reset(void) { prefs_initialized = FALSE; - g_free(prefs.pr_file); - g_free(prefs.pr_cmd); - free_col_info(&prefs); - g_free(prefs.gui_font_name); - g_free(prefs.gui_colorized_fg); - g_free(prefs.gui_colorized_bg); - g_free(prefs.gui_fileopen_dir); - g_free(prefs.gui_webbrowser); - g_free(prefs.gui_window_title); - g_free(prefs.gui_start_title); - g_free(prefs.capture_device); - g_free(prefs.capture_devices_linktypes); - g_free(prefs.capture_devices_descr); - g_free(prefs.capture_devices_hide); - + /* + * Unload all UAT preferences. + */ uat_unload_all(); + + /* + * Unload any loaded MIBs. + */ + oids_cleanup(); + + /* + * Reset the non-dissector preferences. + */ init_prefs(); + + /* + * Reset the non-UAT dissector preferences. + */ + pe_tree_foreach(prefs_modules, reset_module_prefs, NULL); } /* Read the preferences file, fill in "prefs", and return a pointer to it. @@ -1240,13 +2783,16 @@ prefs_reset(void) return NULL. */ e_prefs * read_prefs(int *gpf_errno_return, int *gpf_read_errno_return, - char **gpf_path_return, int *pf_errno_return, - int *pf_read_errno_return, char **pf_path_return) + char **gpf_path_return, int *pf_errno_return, + int *pf_read_errno_return, char **pf_path_return) { int err; char *pf_path; FILE *pf; + /* clean up libsmi structures before reading prefs */ + oids_cleanup(); + init_prefs(); /* @@ -1345,13 +2891,17 @@ read_prefs(int *gpf_errno_return, int *gpf_read_errno_return, g_free(pf_path); } + /* load SMI modules if needed */ + oids_init(); + return &prefs; } /* read the preferences file (or similiar) and call the callback * function to set each key/value pair found */ int -read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fct, void *private_data) +read_prefs_file(const char *pf_path, FILE *pf, + pref_set_pair_cb pref_set_pair_fct, void *private_data) { enum { START, IN_VAR, PRE_VAL, IN_VAL, IN_SKIP }; int got_c, state = START; @@ -1376,13 +2926,17 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc if (isalnum(got_c)) { if (cur_var->len > 0) { if (got_val) { - switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data)) { + /* Convert the string to a range. Since we're reading the + * preferences file, silently lower values in excess of the + * range's maximum. + */ + switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, FALSE)) { case PREFS_SET_OK: break; case PREFS_SET_SYNTAX_ERR: - g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint); + g_warning ("%s line %d: Syntax error in preference %s %s", pf_path, pline, cur_var->str, hint); break; case PREFS_SET_NO_SUCH_PREF: @@ -1430,19 +2984,23 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc } break; case IN_VAL: - g_string_append_c(cur_val, (gchar) got_c); + g_string_append_c(cur_val, (gchar) got_c); break; } } if (cur_var->len > 0) { if (got_val) { - switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data)) { + /* Convert the string to a range. Since we're reading the + * preferences file, silently lower values in excess of the + * range's maximum. + */ + switch (pref_set_pair_fct(cur_var->str, cur_val->str, private_data, FALSE)) { case PREFS_SET_OK: break; case PREFS_SET_SYNTAX_ERR: - g_warning ("%s line %d: Syntax error %s", pf_path, pline, hint); + g_warning ("%s line %d: Syntax error in preference %s %s", pf_path, pline, cur_var->str, hint); break; case PREFS_SET_NO_SUCH_PREF: @@ -1476,44 +3034,44 @@ read_prefs_file(const char *pf_path, FILE *pf, pref_set_pair_cb pref_set_pair_fc */ static gboolean prefs_set_uat_pref(char *uat_entry) { - gchar *p, *colonp; - uat_t *uat; - gchar *err; - - colonp = strchr(uat_entry, ':'); - if (colonp == NULL) - return FALSE; - - p = colonp; - *p++ = '\0'; - - /* - * Skip over any white space (there probably won't be any, but - * as we allow it in the preferences file, we might as well - * allow it here). - */ - while (isspace((guchar)*p)) - p++; - if (*p == '\0') { - /* - * Put the colon back, so if our caller uses, in an - * error message, the string they passed us, the message - * looks correct. - */ - *colonp = ':'; - return FALSE; - } - - uat = uat_find(uat_entry); - *colonp = ':'; - if (uat == NULL) { - return FALSE; - } - - if (uat_load_str(uat, p, &err)) { - return TRUE; - } - return FALSE; + gchar *p, *colonp; + uat_t *uat; + gchar *err; + + colonp = strchr(uat_entry, ':'); + if (colonp == NULL) + return FALSE; + + p = colonp; + *p++ = '\0'; + + /* + * Skip over any white space (there probably won't be any, but + * as we allow it in the preferences file, we might as well + * allow it here). + */ + while (isspace((guchar)*p)) + p++; + if (*p == '\0') { + /* + * Put the colon back, so if our caller uses, in an + * error message, the string they passed us, the message + * looks correct. + */ + *colonp = ':'; + return FALSE; + } + + uat = uat_find(uat_entry); + *colonp = ':'; + if (uat == NULL) { + return FALSE; + } + + if (uat_load_str(uat, p, &err)) { + return TRUE; + } + return FALSE; } /* @@ -1525,49 +3083,49 @@ prefs_set_uat_pref(char *uat_entry) { prefs_set_pref_e prefs_set_pref(char *prefarg) { - gchar *p, *colonp; - prefs_set_pref_e ret; - - /* - * Set the counters of "mgcp.{tcp,udp}.port" entries we've - * seen to values that keep us from trying to interpret tham - * as "mgcp.{tcp,udp}.gateway_port" or "mgcp.{tcp,udp}.callagent_port", - * as, from the command line, we have no way of guessing which - * the user had in mind. - */ - mgcp_tcp_port_count = -1; - mgcp_udp_port_count = -1; - - colonp = strchr(prefarg, ':'); - if (colonp == NULL) - return PREFS_SET_SYNTAX_ERR; - - p = colonp; - *p++ = '\0'; - - /* - * Skip over any white space (there probably won't be any, but - * as we allow it in the preferences file, we might as well - * allow it here). - */ - while (isspace((guchar)*p)) - p++; - if (*p == '\0') { - /* - * Put the colon back, so if our caller uses, in an - * error message, the string they passed us, the message - * looks correct. - */ - *colonp = ':'; - return PREFS_SET_SYNTAX_ERR; - } - if (strcmp(prefarg, "uat")) { - ret = set_pref(prefarg, p, NULL); - } else { - ret = prefs_set_uat_pref(p) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR; - } - *colonp = ':'; /* put the colon back */ - return ret; + gchar *p, *colonp; + prefs_set_pref_e ret; + + /* + * Set the counters of "mgcp.{tcp,udp}.port" entries we've + * seen to values that keep us from trying to interpret tham + * as "mgcp.{tcp,udp}.gateway_port" or "mgcp.{tcp,udp}.callagent_port", + * as, from the command line, we have no way of guessing which + * the user had in mind. + */ + mgcp_tcp_port_count = -1; + mgcp_udp_port_count = -1; + + colonp = strchr(prefarg, ':'); + if (colonp == NULL) + return PREFS_SET_SYNTAX_ERR; + + p = colonp; + *p++ = '\0'; + + /* + * Skip over any white space (there probably won't be any, but + * as we allow it in the preferences file, we might as well + * allow it here). + */ + while (isspace((guchar)*p)) + p++; + if (*p == '\0') { + /* + * Put the colon back, so if our caller uses, in an + * error message, the string they passed us, the message + * looks correct. + */ + *colonp = ':'; + return PREFS_SET_SYNTAX_ERR; + } + if (strcmp(prefarg, "uat")) { + ret = set_pref(prefarg, p, NULL, TRUE); + } else { + ret = prefs_set_uat_pref(p) ? PREFS_SET_OK : PREFS_SET_SYNTAX_ERR; + } + *colonp = ':'; /* put the colon back */ + return ret; } /* @@ -1576,173 +3134,183 @@ prefs_set_pref(char *prefarg) gboolean prefs_is_capture_device_hidden(const char *name) { - gchar *tok, *devices; - size_t len; - - if (prefs.capture_devices_hide && name) { - devices = g_strdup (prefs.capture_devices_hide); - len = strlen (name); - for (tok = strtok (devices, ","); tok; tok = strtok(NULL, ",")) { - if (strlen (tok) == len && strcmp (name, tok) == 0) { - g_free (devices); - return TRUE; - } - } - g_free (devices); - } + gchar *tok, *devices; + size_t len; + + if (prefs.capture_devices_hide && name) { + devices = g_strdup (prefs.capture_devices_hide); + len = strlen (name); + for (tok = strtok (devices, ","); tok; tok = strtok(NULL, ",")) { + if (strlen (tok) == len && strcmp (name, tok) == 0) { + g_free (devices); + return TRUE; + } + } + g_free (devices); + } - return FALSE; + return FALSE; } -#define PRS_PRINT_FMT "print.format" -#define PRS_PRINT_DEST "print.destination" -#define PRS_PRINT_FILE "print.file" -#define PRS_PRINT_CMD "print.command" -#define PRS_COL_FMT "column.format" -#define PRS_STREAM_CL_FG "stream.client.fg" -#define PRS_STREAM_CL_BG "stream.client.bg" -#define PRS_STREAM_SR_FG "stream.server.fg" -#define PRS_STREAM_SR_BG "stream.server.bg" -#define PRS_GUI_SCROLLBAR_ON_RIGHT "gui.scrollbar_on_right" -#define PRS_GUI_PLIST_SEL_BROWSE "gui.packet_list_sel_browse" -#define PRS_GUI_PTREE_SEL_BROWSE "gui.protocol_tree_sel_browse" -#define PRS_GUI_ALTERN_COLORS "gui.tree_view_altern_colors" -#define PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR "gui.filter_toolbar_show_in_statusbar" -#define PRS_GUI_PTREE_LINE_STYLE "gui.protocol_tree_line_style" -#define PRS_GUI_PTREE_EXPANDER_STYLE "gui.protocol_tree_expander_style" -#define PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE "gui.hex_dump_highlight_style" -#define PRS_GUI_FONT_NAME_1 "gui.font_name" -#define PRS_GUI_FONT_NAME_2 "gui.gtk2.font_name" -#define PRS_GUI_MARKED_FG "gui.marked_frame.fg" -#define PRS_GUI_MARKED_BG "gui.marked_frame.bg" -#define PRS_GUI_COLORIZED_FG "gui.colorized_frame.fg" -#define PRS_GUI_COLORIZED_BG "gui.colorized_frame.bg" -#define PRS_GUI_CONSOLE_OPEN "gui.console_open" -#define PRS_GUI_FILEOPEN_STYLE "gui.fileopen.style" -#define PRS_GUI_RECENT_COUNT_MAX "gui.recent_files_count.max" -#define PRS_GUI_RECENT_DF_ENTRIES_MAX "gui.recent_display_filter_entries.max" -#define PRS_GUI_FILEOPEN_DIR "gui.fileopen.dir" -#define PRS_GUI_FILEOPEN_REMEMBERED_DIR "gui.fileopen.remembered_dir" -#define PRS_GUI_FILEOPEN_PREVIEW "gui.fileopen.preview" -#define PRS_GUI_ASK_UNSAVED "gui.ask_unsaved" -#define PRS_GUI_FIND_WRAP "gui.find_wrap" -#define PRS_GUI_USE_PREF_SAVE "gui.use_pref_save" -#define PRS_GUI_GEOMETRY_SAVE_POSITION "gui.geometry.save.position" -#define PRS_GUI_GEOMETRY_SAVE_SIZE "gui.geometry.save.size" -#define PRS_GUI_GEOMETRY_SAVE_MAXIMIZED "gui.geometry.save.maximized" -#define PRS_GUI_MACOSX_STYLE "gui.macosx_style" -#define PRS_GUI_GEOMETRY_MAIN_X "gui.geometry.main.x" -#define PRS_GUI_GEOMETRY_MAIN_Y "gui.geometry.main.y" -#define PRS_GUI_GEOMETRY_MAIN_WIDTH "gui.geometry.main.width" -#define PRS_GUI_GEOMETRY_MAIN_HEIGHT "gui.geometry.main.height" -#define PRS_GUI_TOOLBAR_MAIN_SHOW "gui.toolbar_main_show" -#define PRS_GUI_TOOLBAR_MAIN_STYLE "gui.toolbar_main_style" -#define PRS_GUI_WEBBROWSER "gui.webbrowser" -#define PRS_GUI_WINDOW_TITLE "gui.window_title" -#define PRS_GUI_START_TITLE "gui.start_title" -#define PRS_GUI_VERSION_IN_START_PAGE "gui.version_in_start_page" -#define PRS_GUI_LAYOUT_TYPE "gui.layout_type" -#define PRS_GUI_LAYOUT_CONTENT_1 "gui.layout_content_1" -#define PRS_GUI_LAYOUT_CONTENT_2 "gui.layout_content_2" -#define PRS_GUI_LAYOUT_CONTENT_3 "gui.layout_content_3" -#define PRS_CONSOLE_LOG_LEVEL "console.log.level" - /* - * This applies to more than just captures, so it's not "capture.name_resolve"; - * "capture.name_resolve" is supported on input for backwards compatibility. - * - * It's not a preference for a particular part of Wireshark, it's used all - * over the place, so its name doesn't have two components. + * Returns TRUE if the given column is visible (not hidden) */ -#define PRS_NAME_RESOLVE "name_resolve" -#define PRS_NAME_RESOLVE_CONCURRENCY "name_resolve_concurrency" -#define PRS_CAP_NAME_RESOLVE "capture.name_resolve" - -/* values for the capture dialog box */ -#define PRS_CAP_DEVICE "capture.device" -#define PRS_CAP_DEVICES_LINKTYPES "capture.devices_linktypes" -#define PRS_CAP_DEVICES_DESCR "capture.devices_descr" -#define PRS_CAP_DEVICES_HIDE "capture.devices_hide" -#define PRS_CAP_PROM_MODE "capture.prom_mode" -#define PRS_CAP_PCAP_NG "capture.pcap_ng" -#define PRS_CAP_REAL_TIME "capture.real_time_update" -#define PRS_CAP_AUTO_SCROLL "capture.auto_scroll" -#define PRS_CAP_SHOW_INFO "capture.show_info" +static gboolean +prefs_is_column_visible(const gchar *cols_hidden, fmt_data *cfmt) +{ + gchar *tok, *cols; + fmt_data cfmt_hidden; -#define RED_COMPONENT(x) (guint16) (((((x) >> 16) & 0xff) * 65535 / 255)) -#define GREEN_COMPONENT(x) (guint16) (((((x) >> 8) & 0xff) * 65535 / 255)) -#define BLUE_COMPONENT(x) (guint16) ( (((x) & 0xff) * 65535 / 255)) + /* + * Do we have a list of hidden columns? + */ + if (cols_hidden) { + /* + * Yes - check the column against each of the ones in the + * list. + */ + cols = g_strdup(cols_hidden); + for (tok = strtok(cols, ","); tok; tok = strtok(NULL, ",")) { + tok = g_strstrip(tok); + + /* + * Parse this column format. + */ + if (!parse_column_format(&cfmt_hidden, tok)) { + /* + * It's not valid; ignore it. + */ + continue; + } -/* values for the rtp player preferences dialog box */ -#define PRS_TAP_UPDATE_INTERVAL "taps.update_interval" -#define PRS_RTP_PLAYER_MAX_VISIBLE "taps.rtp_player_max_visible" + /* + * Does it match the column? + */ + if (cfmt->fmt != cfmt_hidden.fmt) { + /* No. */ + g_free(cfmt_hidden.custom_field); + continue; + } + if (cfmt->fmt == COL_CUSTOM) { + /* + * A custom column has to have the + * same custom field and occurrence. + */ + if (strcmp(cfmt->custom_field, + cfmt_hidden.custom_field) != 0) { + /* Different fields. */ + g_free(cfmt_hidden.custom_field); + continue; + } + if (cfmt->custom_occurrence != cfmt_hidden.custom_occurrence) { + /* Different occurrences. */ + g_free(cfmt_hidden.custom_field); + continue; + } + } -#define PRS_DISPLAY_HIDDEN_PROTO_ITEMS "packet_list.display_hidden_proto_items" + /* + * OK, they match, so it's one of the hidden fields, + * hence not visible. + */ + g_free(cfmt_hidden.custom_field); + g_free(cols); + return FALSE; + } + g_free(cols); + } -static const gchar *pr_formats[] = { "text", "postscript" }; -static const gchar *pr_dests[] = { "command", "file" }; + /* + * No - either there are no hidden columns or this isn't one + * of them - so it is visible. + */ + return TRUE; +} -typedef struct { - char letter; - guint32 value; -} name_resolve_opt_t; - -static name_resolve_opt_t name_resolve_opt[] = { - { 'm', RESOLV_MAC }, - { 'n', RESOLV_NETWORK }, - { 't', RESOLV_TRANSPORT }, - { 'C', RESOLV_CONCURRENT }, -}; +/* + * Returns TRUE if the given device should capture in monitor mode by default + */ +gboolean +prefs_capture_device_monitor_mode(const char *name) +{ + gchar *tok, *devices; + size_t len; + + if (prefs.capture_devices_monitor_mode && name) { + devices = g_strdup (prefs.capture_devices_monitor_mode); + len = strlen (name); + for (tok = strtok (devices, ","); tok; tok = strtok(NULL, ",")) { + if (strlen (tok) == len && strcmp (name, tok) == 0) { + g_free (devices); + return TRUE; + } + } + g_free (devices); + } -#define N_NAME_RESOLVE_OPT (sizeof name_resolve_opt / sizeof name_resolve_opt[0]) + return FALSE; +} -static const char * -name_resolve_to_string(guint32 name_resolve) +/* + * Returns TRUE if the user has marked this column as visible + */ +gboolean +prefs_capture_options_dialog_column_is_visible(const gchar *column) { - static char string[N_NAME_RESOLVE_OPT+1]; - char *p; - unsigned int i; - gboolean all_opts_set = TRUE; - - if (name_resolve == RESOLV_NONE) - return "FALSE"; - p = &string[0]; - for (i = 0; i < N_NAME_RESOLVE_OPT; i++) { - if (name_resolve & name_resolve_opt[i].value) - *p++ = name_resolve_opt[i].letter; - else - all_opts_set = FALSE; - } - *p = '\0'; - if (all_opts_set) - return "TRUE"; - return string; + GList *curr; + gchar *col; + + for (curr = g_list_first(prefs.capture_columns); curr; curr = g_list_next(curr)) { + col = (gchar *)curr->data; + if (col && (g_ascii_strcasecmp(col, column) == 0)) { + return TRUE; + } + } + return FALSE; } +#define PRS_GUI_FILTER_LABEL "gui.filter_expressions.label" +#define PRS_GUI_FILTER_EXPR "gui.filter_expressions.expr" +#define PRS_GUI_FILTER_ENABLED "gui.filter_expressions.enabled" + +#define RED_COMPONENT(x) (guint16) (((((x) >> 16) & 0xff) * 65535 / 255)) +#define GREEN_COMPONENT(x) (guint16) (((((x) >> 8) & 0xff) * 65535 / 255)) +#define BLUE_COMPONENT(x) (guint16) ( (((x) & 0xff) * 65535 / 255)) + char -string_to_name_resolve(char *string, guint32 *name_resolve) +string_to_name_resolve(char *string, e_addr_resolve *name_resolve) { char c; - unsigned int i; - *name_resolve = 0; + memset(name_resolve, 0, sizeof(e_addr_resolve)); while ((c = *string++) != '\0') { - for (i = 0; i < N_NAME_RESOLVE_OPT; i++) { - if (c == name_resolve_opt[i].letter) { - *name_resolve |= name_resolve_opt[i].value; - break; + switch (c) { + case 'm': + name_resolve->mac_name = TRUE; + break; + case 'n': + name_resolve->network_name = TRUE; + break; + case 'N': + name_resolve->use_external_net_name_resolver = TRUE; + break; + case 't': + name_resolve->transport_name = TRUE; + break; + case 'C': + name_resolve->concurrent_dns = TRUE; + break; + default: + /* + * Unrecognized letter. + */ + return c; } - } - if (i == N_NAME_RESOLVE_OPT) { - /* - * Unrecognized letter. - */ - return c; - } } return '\0'; } + static void try_convert_to_custom_column(gpointer *el_data) { @@ -1753,12 +3321,17 @@ try_convert_to_custom_column(gpointer *el_data) } migrated_columns[] = { { COL_COS_VALUE, "vlan.priority" }, { COL_CIRCUIT_ID, "iax2.call" }, + { COL_BSSGP_TLLI, "bssgp.tlli" }, { COL_HPUX_SUBSYS, "nettl.subsys" }, { COL_HPUX_DEVID, "nettl.devid" }, - { COL_DSCP_VALUE, "ip.dsfield" }, { COL_FR_DLCI, "fr.dlci" }, { COL_REL_CONV_TIME, "tcp.time_relative" }, - { COL_DELTA_CONV_TIME, "tcp.time_delta" } + { COL_DELTA_CONV_TIME, "tcp.time_delta" }, + { COL_OXID, "fc.ox_id" }, + { COL_RXID, "fc.rx_id" }, + { COL_SRCIDX, "mdshdr.srcidx" }, + { COL_DSTIDX, "mdshdr.dstidx" }, + { COL_DCE_CTX, "dcerpc.cn_ctx_id" } }; guint haystack_idx; @@ -1772,7 +3345,7 @@ try_convert_to_custom_column(gpointer *el_data) haystack_fmt = col_format_to_string(migrated_columns[haystack_idx].el); if (strcmp(haystack_fmt, *fmt) == 0) { - gchar *cust_col = g_strdup_printf("%%Cus:%s", + gchar *cust_col = g_strdup_printf("%%Cus:%s:0", migrated_columns[haystack_idx].col_expr); g_free(*fmt); @@ -1782,375 +3355,83 @@ try_convert_to_custom_column(gpointer *el_data) } static prefs_set_pref_e -set_pref(gchar *pref_name, gchar *value, void *private_data _U_) +set_pref(gchar *pref_name, gchar *value, void *private_data _U_, + gboolean return_range_errors) { - GList *col_l, *col_l_elt; - gint llen; - fmt_data *cfmt; unsigned long int cval; guint uval; gboolean bval; gint enum_val; char *p; gchar *dotp, *last_dotp; + static gchar *filter_label = NULL; + static gboolean filter_enabled = FALSE; + gchar *filter_expr = NULL; module_t *module; pref_t *pref; gboolean had_a_dot; - const gchar *cust_format = col_format_to_string(COL_CUSTOM); - size_t cust_format_len = strlen(cust_format); - - if (strcmp(pref_name, PRS_PRINT_FMT) == 0) { - if (strcmp(value, pr_formats[PR_FMT_TEXT]) == 0) { - prefs.pr_format = PR_FMT_TEXT; - } else if (strcmp(value, pr_formats[PR_FMT_PS]) == 0) { - prefs.pr_format = PR_FMT_PS; - } else { - return PREFS_SET_SYNTAX_ERR; - } - } else if (strcmp(pref_name, PRS_PRINT_DEST) == 0) { - if (strcmp(value, pr_dests[PR_DEST_CMD]) == 0) { - prefs.pr_dest = PR_DEST_CMD; - } else if (strcmp(value, pr_dests[PR_DEST_FILE]) == 0) { - prefs.pr_dest = PR_DEST_FILE; - } else { - return PREFS_SET_SYNTAX_ERR; - } - } else if (strcmp(pref_name, PRS_PRINT_FILE) == 0) { - g_free(prefs.pr_file); - prefs.pr_file = g_strdup(value); - } else if (strcmp(pref_name, PRS_PRINT_CMD) == 0) { - g_free(prefs.pr_cmd); - prefs.pr_cmd = g_strdup(value); - } else if (strcmp(pref_name, PRS_COL_FMT) == 0) { - 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) { - /* Make sure the title isn't empty. */ - if (strcmp(col_l_elt->data, "") == 0) { - /* It is. */ - prefs_clear_string_list(col_l); - return PREFS_SET_SYNTAX_ERR; - } - - /* Go past the title. */ - col_l_elt = col_l_elt->next; - - /* Check the format. */ - if (strncmp(col_l_elt->data, cust_format, cust_format_len) != 0) { - if (get_column_format_from_str(col_l_elt->data) == -1) { - /* It's not a valid column format. */ - prefs_clear_string_list(col_l); - return PREFS_SET_SYNTAX_ERR; - } - - /* Some predefined columns have been migrated to use custom colums. - * We'll convert these silently here */ - try_convert_to_custom_column(&col_l_elt->data); - } - /* Go past the format. */ - col_l_elt = col_l_elt->next; - } - free_col_info(&prefs); - prefs.col_list = NULL; - llen = g_list_length(col_l); - prefs.num_cols = llen / 2; - col_l_elt = g_list_first(col_l); - while(col_l_elt) { - cfmt = (fmt_data *) g_malloc(sizeof(fmt_data)); - cfmt->title = g_strdup(col_l_elt->data); - col_l_elt = col_l_elt->next; - if (strncmp(col_l_elt->data, cust_format, cust_format_len) == 0) { - gchar *fmt = g_strdup(col_l_elt->data); - cfmt->fmt = g_strdup(cust_format); - cfmt->custom_field = g_strdup(&fmt[cust_format_len+1]); /* add 1 for ':' */ - g_free (fmt); - } else { - cfmt->fmt = g_strdup(col_l_elt->data); - cfmt->custom_field = NULL; - } - col_l_elt = col_l_elt->next; - prefs.col_list = g_list_append(prefs.col_list, cfmt); - } - prefs_clear_string_list(col_l); - } else if (strcmp(pref_name, PRS_STREAM_CL_FG) == 0) { - cval = strtoul(value, NULL, 16); - prefs.st_client_fg.pixel = 0; - prefs.st_client_fg.red = RED_COMPONENT(cval); - prefs.st_client_fg.green = GREEN_COMPONENT(cval); - prefs.st_client_fg.blue = BLUE_COMPONENT(cval); - } else if (strcmp(pref_name, PRS_STREAM_CL_BG) == 0) { - cval = strtoul(value, NULL, 16); - prefs.st_client_bg.pixel = 0; - prefs.st_client_bg.red = RED_COMPONENT(cval); - prefs.st_client_bg.green = GREEN_COMPONENT(cval); - prefs.st_client_bg.blue = BLUE_COMPONENT(cval); - } else if (strcmp(pref_name, PRS_STREAM_SR_FG) == 0) { - cval = strtoul(value, NULL, 16); - prefs.st_server_fg.pixel = 0; - prefs.st_server_fg.red = RED_COMPONENT(cval); - prefs.st_server_fg.green = GREEN_COMPONENT(cval); - prefs.st_server_fg.blue = BLUE_COMPONENT(cval); - } else if (strcmp(pref_name, PRS_STREAM_SR_BG) == 0) { - cval = strtoul(value, NULL, 16); - prefs.st_server_bg.pixel = 0; - prefs.st_server_bg.red = RED_COMPONENT(cval); - prefs.st_server_bg.green = GREEN_COMPONENT(cval); - prefs.st_server_bg.blue = BLUE_COMPONENT(cval); - } else if (strcmp(pref_name, PRS_GUI_SCROLLBAR_ON_RIGHT) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_scrollbar_on_right = TRUE; - } - else { - prefs.gui_scrollbar_on_right = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_PLIST_SEL_BROWSE) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_plist_sel_browse = TRUE; - } - else { - prefs.gui_plist_sel_browse = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_PTREE_SEL_BROWSE) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_ptree_sel_browse = TRUE; - } - else { - prefs.gui_ptree_sel_browse = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_ALTERN_COLORS) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_altern_colors = TRUE; - } - else { - prefs.gui_altern_colors = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_PTREE_LINE_STYLE) == 0) { - prefs.gui_ptree_line_style = - find_index_from_string_array(value, gui_ptree_line_style_text, 0); - } else if (strcmp(pref_name, PRS_GUI_PTREE_EXPANDER_STYLE) == 0) { - prefs.gui_ptree_expander_style = - find_index_from_string_array(value, gui_ptree_expander_style_text, 1); - } else if (strcmp(pref_name, PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE) == 0) { - prefs.gui_hex_dump_highlight_style = - find_index_from_string_array(value, gui_hex_dump_highlight_style_text, 1); - } else if (strcmp(pref_name, PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.filter_toolbar_show_in_statusbar = TRUE; - } - else { - prefs.filter_toolbar_show_in_statusbar = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_TOOLBAR_MAIN_SHOW) == 0) { - /* obsoleted by recent setting */ - } else if (strcmp(pref_name, PRS_GUI_TOOLBAR_MAIN_STYLE) == 0) { - /* see toolbar.c for details, "icons only" is default */ - prefs.gui_toolbar_main_style = - find_index_from_string_array(value, gui_toolbar_style_text, - TB_STYLE_ICONS); - } else if (strcmp(pref_name, PRS_GUI_FONT_NAME_1) == 0) { - /* GTK1 font name obsolete */ - } else if (strcmp(pref_name, PRS_GUI_FONT_NAME_2) == 0) { - g_free(prefs.gui_font_name); - prefs.gui_font_name = g_strdup(value); - } else if (strcmp(pref_name, PRS_GUI_MARKED_FG) == 0) { - cval = strtoul(value, NULL, 16); - prefs.gui_marked_fg.pixel = 0; - prefs.gui_marked_fg.red = RED_COMPONENT(cval); - prefs.gui_marked_fg.green = GREEN_COMPONENT(cval); - prefs.gui_marked_fg.blue = BLUE_COMPONENT(cval); - } else if (strcmp(pref_name, PRS_GUI_MARKED_BG) == 0) { - cval = strtoul(value, NULL, 16); - prefs.gui_marked_bg.pixel = 0; - prefs.gui_marked_bg.red = RED_COMPONENT(cval); - prefs.gui_marked_bg.green = GREEN_COMPONENT(cval); - prefs.gui_marked_bg.blue = BLUE_COMPONENT(cval); - } else if (strcmp(pref_name, PRS_GUI_COLORIZED_FG) == 0) { - g_free(prefs.gui_colorized_fg); - prefs.gui_colorized_fg = g_strdup(value); - } else if (strcmp(pref_name, PRS_GUI_COLORIZED_BG) == 0) { - g_free(prefs.gui_colorized_bg); - prefs.gui_colorized_bg = g_strdup(value); - } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_POSITION) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_geometry_save_position = TRUE; - } - else { - prefs.gui_geometry_save_position = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_SIZE) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_geometry_save_size = TRUE; - } - else { - prefs.gui_geometry_save_size = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_SAVE_MAXIMIZED) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_geometry_save_maximized = TRUE; - } - else { - prefs.gui_geometry_save_maximized = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_MACOSX_STYLE) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_macosx_style = TRUE; - } - else { - prefs.gui_macosx_style = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_X) == 0) { /* deprecated */ - } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_Y) == 0) { /* deprecated */ - } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_WIDTH) == 0) { /* deprecated */ - } else if (strcmp(pref_name, PRS_GUI_GEOMETRY_MAIN_HEIGHT) == 0) { /* deprecated */ - } else if (strcmp(pref_name, PRS_GUI_CONSOLE_OPEN) == 0) { - prefs.gui_console_open = - find_index_from_string_array(value, gui_console_open_text, - console_open_never); - } else if (strcmp(pref_name, PRS_GUI_RECENT_COUNT_MAX) == 0) { - prefs.gui_recent_files_count_max = strtoul(value, NULL, 10); - if (prefs.gui_recent_files_count_max == 0) { - /* We really should put up a dialog box here ... */ - prefs.gui_recent_files_count_max = 10; - } - } else if (strcmp(pref_name, PRS_GUI_RECENT_DF_ENTRIES_MAX) == 0) { - prefs.gui_recent_df_entries_max = strtoul(value, NULL, 10); - if (prefs.gui_recent_df_entries_max == 0) { - /* We really should put up a dialog box here ... */ - prefs.gui_recent_df_entries_max = 10; - } - } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_STYLE) == 0) { - prefs.gui_fileopen_style = - find_index_from_string_array(value, gui_fileopen_style_text, - FO_STYLE_LAST_OPENED); - } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_DIR) == 0) { - g_free(prefs.gui_fileopen_dir); - prefs.gui_fileopen_dir = g_strdup(value); - } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_REMEMBERED_DIR) == 0) { /* deprecated */ - } else if (strcmp(pref_name, PRS_GUI_FILEOPEN_PREVIEW) == 0) { - prefs.gui_fileopen_preview = strtoul(value, NULL, 10); - } else if (strcmp(pref_name, PRS_GUI_ASK_UNSAVED) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_ask_unsaved = TRUE; - } - else { - prefs.gui_ask_unsaved = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_FIND_WRAP) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_find_wrap = TRUE; - } - else { - prefs.gui_find_wrap = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_USE_PREF_SAVE) == 0) { + if (strcmp(pref_name, PRS_GUI_FILTER_LABEL) == 0) { + filter_label = g_strdup(value); + } else if (strcmp(pref_name, PRS_GUI_FILTER_ENABLED) == 0) { + filter_enabled = (strcmp(value, "TRUE") == 0) ? TRUE : FALSE; + } else if (strcmp(pref_name, PRS_GUI_FILTER_EXPR) == 0) { + filter_expr = g_strdup(value); + filter_expression_new(filter_label, filter_expr, filter_enabled); + g_free(filter_label); + g_free(filter_expr); + } else if (strcmp(pref_name, "gui.version_in_start_page") == 0) { + /* Convert deprecated value to closest current equivalent */ if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_use_pref_save = TRUE; - } - else { - prefs.gui_use_pref_save = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_WEBBROWSER) == 0) { - g_free(prefs.gui_webbrowser); - prefs.gui_webbrowser = g_strdup(value); - } else if (strcmp(pref_name, PRS_GUI_WINDOW_TITLE) == 0) { - g_free(prefs.gui_window_title); - prefs.gui_window_title = g_strdup(value); - } else if (strcmp(pref_name, PRS_GUI_START_TITLE) == 0) { - g_free(prefs.gui_start_title); - prefs.gui_start_title = g_strdup(value); - } else if (strcmp(pref_name, PRS_GUI_VERSION_IN_START_PAGE) == 0) { - if (g_ascii_strcasecmp(value, "true") == 0) { - prefs.gui_version_in_start_page = TRUE; + prefs.gui_version_placement = version_both; } else { - prefs.gui_version_in_start_page = FALSE; - } - } else if (strcmp(pref_name, PRS_GUI_LAYOUT_TYPE) == 0) { - prefs.gui_layout_type = strtoul(value, NULL, 10); - 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; + prefs.gui_version_placement = version_neither; } - } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_1) == 0) { - prefs.gui_layout_content_1 = - find_index_from_string_array(value, gui_layout_content_text, 0); - } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_2) == 0) { - prefs.gui_layout_content_2 = - find_index_from_string_array(value, gui_layout_content_text, 0); - } else if (strcmp(pref_name, PRS_GUI_LAYOUT_CONTENT_3) == 0) { - prefs.gui_layout_content_3 = - find_index_from_string_array(value, gui_layout_content_text, 0); - } else if (strcmp(pref_name, PRS_CONSOLE_LOG_LEVEL) == 0) { - prefs.console_log_level = strtoul(value, NULL, 10); - -/* handle the capture options */ - } else if (strcmp(pref_name, PRS_CAP_DEVICE) == 0) { - g_free(prefs.capture_device); - prefs.capture_device = g_strdup(value); - } else if (strcmp(pref_name, PRS_CAP_DEVICES_LINKTYPES) == 0) { - g_free(prefs.capture_devices_linktypes); - prefs.capture_devices_linktypes = g_strdup(value); - } else if (strcmp(pref_name, PRS_CAP_DEVICES_DESCR) == 0) { - g_free(prefs.capture_devices_descr); - prefs.capture_devices_descr = g_strdup(value); - } else if (strcmp(pref_name, PRS_CAP_DEVICES_HIDE) == 0) { - g_free(prefs.capture_devices_hide); - prefs.capture_devices_hide = g_strdup(value); - } else if (strcmp(pref_name, PRS_CAP_PROM_MODE) == 0) { - prefs.capture_prom_mode = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE); - } else if (strcmp(pref_name, PRS_CAP_PCAP_NG) == 0) { - prefs.capture_pcap_ng = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE); - } else if (strcmp(pref_name, PRS_CAP_REAL_TIME) == 0) { - prefs.capture_real_time = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE); - } else if (strcmp(pref_name, PRS_CAP_AUTO_SCROLL) == 0) { - prefs.capture_auto_scroll = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE); - } else if (strcmp(pref_name, PRS_CAP_SHOW_INFO) == 0) { - prefs.capture_show_info = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE); - -/* handle the global options */ - } else if (strcmp(pref_name, PRS_NAME_RESOLVE) == 0 || - strcmp(pref_name, PRS_CAP_NAME_RESOLVE) == 0) { +/* handle the deprecated name resolution options */ + } else if (strcmp(pref_name, "name_resolve") == 0 || + strcmp(pref_name, "capture.name_resolve") == 0) { /* * "TRUE" and "FALSE", for backwards compatibility, are synonyms for * RESOLV_ALL and RESOLV_NONE. * * Otherwise, we treat it as a list of name types we want to resolve. */ - if (g_ascii_strcasecmp(value, "true") == 0) - prefs.name_resolve = RESOLV_ALL; - else if (g_ascii_strcasecmp(value, "false") == 0) - prefs.name_resolve = RESOLV_NONE; - else { - prefs.name_resolve = RESOLV_NONE; /* start out with none set */ - if (string_to_name_resolve(value, &prefs.name_resolve) != '\0') - return PREFS_SET_SYNTAX_ERR; - } - } else if (strcmp(pref_name, PRS_NAME_RESOLVE_CONCURRENCY) == 0) { - prefs.name_resolve_concurrency = strtol(value, NULL, 10); - } else if ((strcmp(pref_name, PRS_RTP_PLAYER_MAX_VISIBLE) == 0) || - (strcmp(pref_name, "rtp_player.max_visible") == 0)) { - /* ... also accepting old name for this preference */ - prefs.rtp_player_max_visible = strtol(value, NULL, 10); - } else if (strcmp(pref_name, PRS_TAP_UPDATE_INTERVAL) == 0) { - prefs.tap_update_interval = strtol(value, NULL, 10); - } else if (strcmp(pref_name, PRS_DISPLAY_HIDDEN_PROTO_ITEMS) == 0) { - prefs.display_hidden_proto_items = ((g_ascii_strcasecmp(value, "true") == 0)?TRUE:FALSE); + if (g_ascii_strcasecmp(value, "true") == 0) { + gbl_resolv_flags.mac_name = TRUE; + gbl_resolv_flags.network_name = TRUE; + gbl_resolv_flags.transport_name = TRUE; + gbl_resolv_flags.concurrent_dns = TRUE; + } + else if (g_ascii_strcasecmp(value, "false") == 0) { + gbl_resolv_flags.mac_name = FALSE; + gbl_resolv_flags.network_name = FALSE; + gbl_resolv_flags.transport_name = FALSE; + gbl_resolv_flags.concurrent_dns = FALSE; + } + else { + /* start out with none set */ + gbl_resolv_flags.mac_name = FALSE; + gbl_resolv_flags.network_name = FALSE; + gbl_resolv_flags.transport_name = FALSE; + gbl_resolv_flags.concurrent_dns = FALSE; + if (string_to_name_resolve(value, &gbl_resolv_flags) != '\0') + return PREFS_SET_SYNTAX_ERR; + } } else { - /* To which module does this preference belong? */ - module = NULL; - last_dotp = pref_name; - had_a_dot = FALSE; - while (!module) { + /* Handle deprecated "global" options that don't have a module + * associated with them + */ + if ((strcmp(pref_name, "name_resolve_concurrency") == 0) || + (strcmp(pref_name, "name_resolve_load_smi_modules") == 0) || + (strcmp(pref_name, "name_resolve_suppress_smi_errors") == 0)) { + module = nameres_module; + dotp = pref_name; + } else { + /* To which module does this preference belong? */ + module = NULL; + last_dotp = pref_name; + had_a_dot = FALSE; + while (!module) { dotp = strchr(last_dotp, '.'); if (dotp == NULL) { if (had_a_dot) { @@ -2183,10 +3464,17 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) * However, SMPP now has its own preferences, so we just map * "smpp-gsm-sms" to "gsm-sms-ud", and then handle SMPP below. * - * We also renamed "dcp" to "dccp" and "x.25" to "x25". + * We also renamed "dcp" to "dccp", "x.25" to "x25", "x411" to "p1" + * and "nsip" to "gprs_ns". + * + * The SynOptics Network Management Protocol (SONMP) is now known by + * its modern name, the Nortel Discovery Protocol (NDP). + * */ if (module == NULL) { - if (strcmp(pref_name, "Diameter") == 0) + if (strcmp(pref_name, "column") == 0) + module = gui_column_module; + else if (strcmp(pref_name, "Diameter") == 0) module = prefs_find_module("diameter"); else if (strcmp(pref_name, "bxxp") == 0) module = prefs_find_module("beep"); @@ -2199,16 +3487,34 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) module = prefs_find_module("dccp"); else if (strcmp(pref_name, "x.25") == 0) module = prefs_find_module("x25"); + else if (strcmp(pref_name, "x411") == 0) + module = prefs_find_module("p1"); + else if (strcmp(pref_name, "nsip") == 0) + module = prefs_find_module("gprs-ns"); + else if (strcmp(pref_name, "sonmp") == 0) + module = prefs_find_module("ndp"); + else if (strcmp(pref_name, "etheric") == 0 || + strcmp(pref_name, "isup_thin") == 0) + /* This protocols was removed 7. July 2009 */ + return PREFS_SET_OBSOLETE; } - *dotp = '.'; /* put the preference string back */ - dotp++; /* skip past separator to preference name */ + *dotp = '.'; /* put the preference string back */ + dotp++; /* skip past separator to preference name */ last_dotp = dotp; + } } pref = prefs_find_preference(module, dotp); if (pref == NULL) { - if (strcmp(module->name, "mgcp") == 0) { + /* "gui" prefix was added to column preferences for better organization + * within the preferences file + */ + if ((strcmp(pref_name, PRS_COL_HIDDEN) == 0) || + (strcmp(pref_name, PRS_COL_FMT) == 0)) { + pref = prefs_find_preference(module, pref_name); + } + else if (strcmp(module->name, "mgcp") == 0) { /* * XXX - "mgcp.display raw text toggle" and "mgcp.display dissect tree" * rather than "mgcp.display_raw_text" and "mgcp.display_dissect_tree" @@ -2237,24 +3543,24 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) if (mgcp_tcp_port_count == 1) { /* It's the first one */ pref = prefs_find_preference(module, "tcp.gateway_port"); - } else if (mgcp_tcp_port_count == 2) { + } else if (mgcp_tcp_port_count == 2) { /* It's the second one */ pref = prefs_find_preference(module, "tcp.callagent_port"); - } + } /* Otherwise it's from the command line, and we don't bother mapping it. */ - } else if (strcmp(dotp, "udp.port") == 0) { + } else if (strcmp(dotp, "udp.port") == 0) { mgcp_udp_port_count++; if (mgcp_udp_port_count == 1) { /* It's the first one */ pref = prefs_find_preference(module, "udp.gateway_port"); - } else if (mgcp_udp_port_count == 2) { + } else if (mgcp_udp_port_count == 2) { /* It's the second one */ pref = prefs_find_preference(module, "udp.callagent_port"); - } + } /* Otherwise it's from the command line, and we don't bother mapping it. */ - } + } } else if (strcmp(module->name, "smb") == 0) { /* Handle old names for SMB preferences. */ if (strcmp(dotp, "smb.trans.reassembly") == 0) @@ -2424,17 +3730,47 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) else if (strcmp(value, "raw") == 0 || strcmp(value, "Raw data") == 0) value = "guess"; } + } else if (strcmp(module->name, "eth") == 0) { + /* "eth.qinq_ethertype" has been changed(restored) to "vlan.qinq.ethertype" */ + if (strcmp(dotp, "qinq_ethertype") == 0) { + module_t *new_module = prefs_find_module("vlan"); + if(new_module) { + pref = prefs_find_preference(new_module, "qinq_ethertype"); + module = new_module; + } + } + } else if (strcmp(module->name, "taps") == 0) { + /* taps preferences moved to stats module */ + if (strcmp(dotp, "update_interval") == 0 || strcmp(value, "rtp_player_max_visible") == 0) + pref = prefs_find_preference(stats_module, dotp); + } else if (strcmp(module->name, "packet_list") == 0) { + /* packet_list preferences moved to protocol module */ + if (strcmp(dotp, "display_hidden_proto_items") == 0) + pref = prefs_find_preference(protocols_module, dotp); + } else if (strcmp(module->name, "stream") == 0) { + /* stream preferences moved to gui color module */ + if ((strcmp(dotp, "stream.client.fg") == 0) || (strcmp(value, "stream.client.bg") == 0) || + (strcmp(dotp, "stream.server.fg") == 0) || (strcmp(value, "stream.server.bg") == 0)) + pref = prefs_find_preference(gui_color_module, pref_name); + } else if (strcmp(module->name, "nameres") == 0) { + if (strcmp(pref_name, "name_resolve_concurrency") == 0) { + pref = prefs_find_preference(nameres_module, pref_name); + } else if (strcmp(pref_name, "name_resolve_load_smi_modules") == 0) { + pref = prefs_find_preference(nameres_module, "load_smi_modules"); + } else if (strcmp(pref_name, "name_resolve_suppress_smi_errors") == 0) { + pref = prefs_find_preference(nameres_module, "suppress_smi_errors"); + } } } if (pref == NULL) - return PREFS_SET_NO_SUCH_PREF; /* no such preference */ + return PREFS_SET_NO_SUCH_PREF; /* no such preference */ switch (pref->type) { case PREF_UINT: uval = strtoul(value, &p, pref->info.base); if (p == value || *p != '\0') - return PREFS_SET_SYNTAX_ERR; /* number was bad */ + return PREFS_SET_SYNTAX_ERR; /* number was bad */ if (*pref->varp.uint != uval) { module->prefs_changed = TRUE; *pref->varp.uint = uval; @@ -2448,22 +3784,23 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) else bval = FALSE; if (*pref->varp.boolp != bval) { - module->prefs_changed = TRUE; - *pref->varp.boolp = bval; + module->prefs_changed = TRUE; + *pref->varp.boolp = bval; } break; case PREF_ENUM: /* XXX - give an error if it doesn't match? */ - enum_val = find_val_for_string(value, - pref->info.enum_info.enumvals, 1); + enum_val = find_val_for_string(value, pref->info.enum_info.enumvals, + *pref->varp.enump); if (*pref->varp.enump != enum_val) { - module->prefs_changed = TRUE; - *pref->varp.enump = enum_val; + module->prefs_changed = TRUE; + *pref->varp.enump = enum_val; } break; case PREF_STRING: + case PREF_FILENAME: if (strcmp(*pref->varp.string, value) != 0) { module->prefs_changed = TRUE; g_free((void *)*pref->varp.string); @@ -2475,23 +3812,39 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) { range_t *newrange; - if (range_convert_str(&newrange, value, pref->info.max_value) != - CVT_NO_ERROR) { - /* XXX - distinguish between CVT_SYNTAX_ERROR and - CVT_NUMBER_TOO_BIG */ - return PREFS_SET_SYNTAX_ERR; /* number was bad */ + if (range_convert_str_work(&newrange, value, pref->info.max_value, + return_range_errors) != CVT_NO_ERROR) { + return PREFS_SET_SYNTAX_ERR; /* number was bad */ } if (!ranges_are_equal(*pref->varp.range, newrange)) { - module->prefs_changed = TRUE; - g_free(*pref->varp.range); - *pref->varp.range = newrange; + module->prefs_changed = TRUE; + g_free(*pref->varp.range); + *pref->varp.range = newrange; } else { - g_free (newrange); + g_free (newrange); + } + break; + } + + case PREF_COLOR: + { + cval = strtoul(value, NULL, 16); + pref->varp.color->pixel = 0; + if ((pref->varp.color->red != RED_COMPONENT(cval)) || + (pref->varp.color->green != GREEN_COMPONENT(cval)) || + (pref->varp.color->blue != BLUE_COMPONENT(cval))) { + module->prefs_changed = TRUE; + pref->varp.color->red = RED_COMPONENT(cval); + pref->varp.color->green = GREEN_COMPONENT(cval); + pref->varp.color->blue = BLUE_COMPONENT(cval); } break; } + case PREF_CUSTOM: + return pref->custom_cbs.set_cb(pref, value, &module->prefs_changed); + case PREF_STATIC_TEXT: case PREF_UAT: { @@ -2499,7 +3852,7 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) } case PREF_OBSOLETE: - return PREFS_SET_OBSOLETE; /* no such preference any more */ + return PREFS_SET_OBSOLETE; /* no such preference any more */ } } @@ -2507,144 +3860,214 @@ set_pref(gchar *pref_name, gchar *value, void *private_data _U_) } typedef struct { - module_t *module; - FILE *pf; -} write_pref_arg_t; + FILE *pf; + gboolean is_gui_module; +} write_gui_pref_arg_t; /* - * Write out a single preference. + * Write out a single dissector preference. */ static void write_pref(gpointer data, gpointer user_data) { - pref_t *pref = data; - write_pref_arg_t *arg = user_data; - const enum_val_t *enum_valp; - const char *val_string; - gchar **desc_lines; - int i; - - if (pref->type == PREF_OBSOLETE) { - /* - * This preference is no longer supported; it's not a - * real preference, so we don't write it out (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). - */ - return; - } - - /* - * Make multiple line descriptions appear as - * multiple commented lines in prefs file. - */ - if (g_ascii_strncasecmp(pref->description,"", 2) != 0) { - desc_lines = g_strsplit(pref->description,"\n",0); - for (i = 0; desc_lines[i] != NULL; ++i) { - fprintf(arg->pf, "\n# %s", desc_lines[i]); - } - fprintf(arg->pf, "\n"); - g_strfreev(desc_lines); - } else { - fprintf(arg->pf, "\n# No description\n"); - } - - switch (pref->type) { - - case PREF_UINT: - switch (pref->info.base) { - - case 10: - fprintf(arg->pf, "# A decimal number.\n"); - fprintf(arg->pf, "%s.%s: %u\n", arg->module->name, - pref->name, *pref->varp.uint); - break; - - case 8: - fprintf(arg->pf, "# An octal number.\n"); - fprintf(arg->pf, "%s.%s: %#o\n", arg->module->name, - pref->name, *pref->varp.uint); - break; - - case 16: - fprintf(arg->pf, "# A hexadecimal number.\n"); - fprintf(arg->pf, "%s.%s: %#x\n", arg->module->name, - pref->name, *pref->varp.uint); - break; - } - break; - - case PREF_BOOL: - fprintf(arg->pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name, - *pref->varp.boolp ? "TRUE" : "FALSE"); - break; - - case PREF_ENUM: - /* - * For now, we save the "description" value, so that if we - * save the preferences older versions of Wireshark can at - * least read preferences that they supported; we support - * either the short name or the description when reading - * the preferences file or a "-o" option. - */ - fprintf(arg->pf, "# One of: "); - enum_valp = pref->info.enum_info.enumvals; - val_string = NULL; - while (enum_valp->name != NULL) { - if (enum_valp->value == *pref->varp.enump) - val_string = enum_valp->description; - fprintf(arg->pf, "%s", enum_valp->description); - enum_valp++; - if (enum_valp->name == NULL) - fprintf(arg->pf, "\n"); - else - fprintf(arg->pf, ", "); - } - fprintf(arg->pf, "# (case-insensitive).\n"); - fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, - pref->name, val_string); - break; - - case PREF_STRING: - fprintf(arg->pf, "# A string.\n"); - fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name, - *pref->varp.string); - break; - - case PREF_RANGE: - { - char *range_string; - - range_string = range_convert_range(*pref->varp.range); - fprintf(arg->pf, "# A string denoting an positive integer range (e.g., \"1-20,30-40\").\n"); - fprintf(arg->pf, "%s.%s: %s\n", arg->module->name, pref->name, - range_string); - break; - } - - case PREF_STATIC_TEXT: - case PREF_UAT: - { - /* Nothing to do */ - break; - } - - case PREF_OBSOLETE: - g_assert_not_reached(); - break; - } + pref_t *pref = data; + write_pref_arg_t *arg = user_data; + const enum_val_t *enum_valp; + const char *val_string, *prefix; + gchar **desc_lines; + int i; + + switch (pref->type) { + case PREF_OBSOLETE: + /* + * This preference is no longer supported; it's not a + * real preference, so we don't write it out (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). + */ + return; + + case PREF_STATIC_TEXT: + case PREF_UAT: + /* Nothing to do; don't bother printing the description */ + return; + default: + break; + } + + /* + * The prefix will either be the module name or the parent + * name if its a subtree + */ + prefix = (arg->module->name != NULL) ? arg->module->name : arg->module->parent->name; + + /* + * Make multiple line descriptions appear as + * multiple commented lines in prefs file. + */ + if (pref->type != PREF_CUSTOM) { + if (pref->description && + (g_ascii_strncasecmp(pref->description,"", 2) != 0)) { + desc_lines = g_strsplit(pref->description,"\n",0); + for (i = 0; desc_lines[i] != NULL; ++i) { + fprintf(arg->pf, "\n# %s", desc_lines[i]); + } + fprintf(arg->pf, "\n"); + g_strfreev(desc_lines); + } else { + fprintf(arg->pf, "\n# No description\n"); + } + } + + switch (pref->type) { + + case PREF_UINT: + switch (pref->info.base) { + + case 10: + fprintf(arg->pf, "# A decimal number.\n"); + if (pref->default_val.uint == *pref->varp.uint) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %u\n", prefix, + pref->name, *pref->varp.uint); + break; + + case 8: + fprintf(arg->pf, "# An octal number.\n"); + if (pref->default_val.uint == *pref->varp.uint) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %#o\n", prefix, + pref->name, *pref->varp.uint); + break; + + case 16: + fprintf(arg->pf, "# A hexadecimal number.\n"); + if (pref->default_val.uint == *pref->varp.uint) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %#x\n", prefix, + pref->name, *pref->varp.uint); + break; + } + break; + + case PREF_BOOL: + fprintf(arg->pf, "# TRUE or FALSE (case-insensitive).\n"); + if (pref->default_val.boolval == *pref->varp.boolp) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %s\n", prefix, pref->name, + *pref->varp.boolp ? "TRUE" : "FALSE"); + break; + + case PREF_ENUM: + /* + * For now, we save the "description" value, so that if we + * save the preferences older versions of Wireshark can at + * least read preferences that they supported; we support + * either the short name or the description when reading + * the preferences file or a "-o" option. + */ + fprintf(arg->pf, "# One of: "); + enum_valp = pref->info.enum_info.enumvals; + val_string = NULL; + while (enum_valp->name != NULL) { + if (enum_valp->value == *pref->varp.enump) + val_string = enum_valp->description; + fprintf(arg->pf, "%s", enum_valp->description); + enum_valp++; + if (enum_valp->name == NULL) + fprintf(arg->pf, "\n"); + else + fprintf(arg->pf, ", "); + } + fprintf(arg->pf, "# (case-insensitive).\n"); + if (pref->default_val.enumval == *pref->varp.enump) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %s\n", prefix, + pref->name, val_string); + break; + + case PREF_STRING: + case PREF_FILENAME: + fprintf(arg->pf, "# A string.\n"); + if (!(strcmp(pref->default_val.string, *pref->varp.string))) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %s\n", prefix, pref->name, + *pref->varp.string); + break; + + case PREF_RANGE: + { + char *range_string_p; + + range_string_p = range_convert_range(*pref->varp.range); + fprintf(arg->pf, "# A string denoting an positive integer range (e.g., \"1-20,30-40\").\n"); + if ((ranges_are_equal(pref->default_val.range, *pref->varp.range))) + fprintf(arg->pf, "#"); + fprintf(arg->pf, "%s.%s: %s\n", prefix, pref->name, + range_string_p); + break; + } + + case PREF_COLOR: + { + fprintf (arg->pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n"); + if ((pref->default_val.color.red == pref->varp.color->red) && + (pref->default_val.color.green == pref->varp.color->green) && + (pref->default_val.color.blue == pref->varp.color->blue)) + fprintf(arg->pf, "#"); + fprintf (arg->pf, "%s.%s: %02x%02x%02x\n", prefix, pref->name, + (pref->varp.color->red * 255 / 65535), + (pref->varp.color->green * 255 / 65535), + (pref->varp.color->blue * 255 / 65535)); + break; + } + + case PREF_CUSTOM: + pref->custom_cbs.write_cb(pref, arg); + break; + + case PREF_OBSOLETE: + case PREF_STATIC_TEXT: + case PREF_UAT: + g_assert_not_reached(); + break; + } } -static gboolean -write_module_prefs(void *value, void *data) +/* + * Write out all preferences for a module. + */ +static guint +write_module_prefs(module_t *module, gpointer user_data) { - write_pref_arg_t arg; + write_gui_pref_arg_t *gui_pref_arg = (write_gui_pref_arg_t*)user_data; + write_pref_arg_t arg; + + /* The GUI module needs to be explicitly called out so it + can be written out of order */ + if ((module == gui_module) && (gui_pref_arg->is_gui_module != TRUE)) + return 0; + + /* Write a header for the main modules and GUI sub-modules */ + if (((module->parent == NULL) || (module->parent == gui_module)) && + ((prefs_module_has_submodules(module)) || + (module->numprefs > 0) || + (module->name == NULL))) { + if ((module->name == NULL) && (module->parent != NULL)) { + fprintf(gui_pref_arg->pf, "\n####### %s: %s ########\n", module->parent->title, module->title); + } else { + fprintf(gui_pref_arg->pf, "\n####### %s ########\n", module->title); + } + } + + arg.module = module; + arg.pf = gui_pref_arg->pf; + g_list_foreach(arg.module->prefs, write_pref, &arg); + + if(prefs_module_has_submodules(module)) + return prefs_modules_foreach_submodules(module, write_module_prefs, user_data); - arg.module = value; - arg.pf = data; - g_list_foreach(arg.module->prefs, write_pref, &arg); - return FALSE; + return 0; } /* Write out "prefs" to the user's preferences file, and return 0. @@ -2658,9 +4081,7 @@ write_prefs(char **pf_path_return) { char *pf_path; FILE *pf; - GList *clp, *col_l; - fmt_data *cfmt; - const gchar *cust_format = col_format_to_string(COL_CUSTOM); + write_gui_pref_arg_t write_gui_pref_info; /* Needed for "-G defaultprefs" */ init_prefs(); @@ -2682,338 +4103,42 @@ write_prefs(char **pf_path_return) } fputs("# Configuration file for Wireshark " VERSION ".\n" - "#\n" - "# This file is regenerated each time preferences are saved within\n" - "# Wireshark. Making manual changes should be safe, however.\n", pf); - - fprintf (pf, "\n######## User Interface ########\n"); - - fprintf(pf, "\n# Vertical scrollbars should be on right side?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_SCROLLBAR_ON_RIGHT ": %s\n", - prefs.gui_scrollbar_on_right == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Packet-list selection bar can be used to browse w/o selecting?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_PLIST_SEL_BROWSE ": %s\n", - prefs.gui_plist_sel_browse == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Protocol-tree selection bar can be used to browse w/o selecting?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_PTREE_SEL_BROWSE ": %s\n", - prefs.gui_ptree_sel_browse == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Alternating colors in TreeViews?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_ALTERN_COLORS ": %s\n", - prefs.gui_altern_colors == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Place filter toolbar inside the statusbar?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_FILTER_TOOLBAR_IN_STATUSBAR ": %s\n", - prefs.filter_toolbar_show_in_statusbar == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Protocol-tree line style.\n"); - fprintf(pf, "# One of: NONE, SOLID, DOTTED, TABBED\n"); - fprintf(pf, PRS_GUI_PTREE_LINE_STYLE ": %s\n", - gui_ptree_line_style_text[prefs.gui_ptree_line_style]); - - fprintf(pf, "\n# Protocol-tree expander style.\n"); - fprintf(pf, "# One of: NONE, SQUARE, TRIANGLE, CIRCULAR\n"); - fprintf(pf, PRS_GUI_PTREE_EXPANDER_STYLE ": %s\n", - gui_ptree_expander_style_text[prefs.gui_ptree_expander_style]); - - fprintf(pf, "\n# Hex dump highlight style.\n"); - fprintf(pf, "# One of: BOLD, INVERSE\n"); - fprintf(pf, PRS_GUI_HEX_DUMP_HIGHLIGHT_STYLE ": %s\n", - gui_hex_dump_highlight_style_text[prefs.gui_hex_dump_highlight_style]); - - fprintf(pf, "\n# Main Toolbar style.\n"); - fprintf(pf, "# One of: ICONS, TEXT, BOTH\n"); - fprintf(pf, PRS_GUI_TOOLBAR_MAIN_STYLE ": %s\n", - gui_toolbar_style_text[prefs.gui_toolbar_main_style]); - - fprintf(pf, "\n# Save window position at exit?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_GEOMETRY_SAVE_POSITION ": %s\n", - prefs.gui_geometry_save_position == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Save window size at exit?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_GEOMETRY_SAVE_SIZE ": %s\n", - prefs.gui_geometry_save_size == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Save window maximized state at exit?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_GEOMETRY_SAVE_MAXIMIZED ": %s\n", - prefs.gui_geometry_save_maximized == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Use MacOS X style (Mac OS X with native GTK only)?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_MACOSX_STYLE ": %s\n", - prefs.gui_macosx_style == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Open a console window (WIN32 only)?\n"); - fprintf(pf, "# One of: NEVER, AUTOMATIC, ALWAYS\n"); - fprintf(pf, PRS_GUI_CONSOLE_OPEN ": %s\n", - gui_console_open_text[prefs.gui_console_open]); - - fprintf(pf, "\n# The max. number of entries in the display filter list.\n"); - fprintf(pf, "# A decimal number.\n"); - fprintf(pf, PRS_GUI_RECENT_DF_ENTRIES_MAX ": %d\n", - prefs.gui_recent_df_entries_max); - - fprintf(pf, "\n# The max. number of items in the open recent files list.\n"); - fprintf(pf, "# A decimal number.\n"); - fprintf(pf, PRS_GUI_RECENT_COUNT_MAX ": %d\n", - prefs.gui_recent_files_count_max); - - fprintf(pf, "\n# Where to start the File Open dialog box.\n"); - fprintf(pf, "# One of: LAST_OPENED, SPECIFIED\n"); - fprintf(pf, PRS_GUI_FILEOPEN_STYLE ": %s\n", - gui_fileopen_style_text[prefs.gui_fileopen_style]); - - if (prefs.gui_fileopen_dir != NULL) { - fprintf(pf, "\n# Directory to start in when opening File Open dialog.\n"); - fprintf(pf, PRS_GUI_FILEOPEN_DIR ": %s\n", - prefs.gui_fileopen_dir); - } - - fprintf(pf, "\n# The preview timeout in the File Open dialog.\n"); - fprintf(pf, "# A decimal number (in seconds).\n"); - fprintf(pf, PRS_GUI_FILEOPEN_PREVIEW ": %d\n", - prefs.gui_fileopen_preview); - - fprintf(pf, "\n# Ask to save unsaved capture files?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_ASK_UNSAVED ": %s\n", - prefs.gui_ask_unsaved == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Wrap to beginning/end of file during search?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_FIND_WRAP ": %s\n", - prefs.gui_find_wrap == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Settings dialogs use a save button?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_USE_PREF_SAVE ": %s\n", - prefs.gui_use_pref_save == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# The path to the webbrowser.\n"); - fprintf(pf, "# Ex: mozilla %%s\n"); - fprintf(pf, PRS_GUI_WEBBROWSER ": %s\n", prefs.gui_webbrowser); - - fprintf(pf, "\n# Custom window title. (Prepended to existing titles.)\n"); - fprintf(pf, PRS_GUI_WINDOW_TITLE ": %s\n", - prefs.gui_window_title); - - fprintf(pf, "\n# Custom start page title.\n"); - fprintf(pf, PRS_GUI_START_TITLE ": %s\n", - prefs.gui_start_title); - - fprintf(pf, "\n# Show version in start page, can be useful in custom builds.\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_GUI_VERSION_IN_START_PAGE ": %s\n", - prefs.gui_version_in_start_page == TRUE ? "TRUE" : "FALSE"); - - fprintf (pf, "\n######## User Interface: Layout ########\n"); - - fprintf(pf, "\n# Layout type (1-6).\n"); - fprintf(pf, PRS_GUI_LAYOUT_TYPE ": %d\n", - prefs.gui_layout_type); - - fprintf(pf, "\n# Layout content of the panes (1-3).\n"); - fprintf(pf, "# One of: NONE, PLIST, PDETAILS, PBYTES\n"); - fprintf(pf, PRS_GUI_LAYOUT_CONTENT_1 ": %s\n", - gui_layout_content_text[prefs.gui_layout_content_1]); - fprintf(pf, PRS_GUI_LAYOUT_CONTENT_2 ": %s\n", - gui_layout_content_text[prefs.gui_layout_content_2]); - fprintf(pf, PRS_GUI_LAYOUT_CONTENT_3 ": %s\n", - gui_layout_content_text[prefs.gui_layout_content_3]); - - fprintf (pf, "\n######## User Interface: Columns ########\n"); - - clp = prefs.col_list; - col_l = NULL; - while (clp) { - cfmt = (fmt_data *) clp->data; - col_l = g_list_append(col_l, cfmt->title); - if ((strcmp(cfmt->fmt, cust_format) == 0) && (cfmt->custom_field)) { - gchar *fmt = g_strdup_printf("%s:%s", cfmt->fmt, cfmt->custom_field); - col_l = g_list_append(col_l, fmt); - } else { - col_l = g_list_append(col_l, cfmt->fmt); + "#\n" + "# This file is regenerated each time preferences are saved within\n" + "# Wireshark. Making manual changes should be safe, however.\n" + "# Preferences that have been commented out have not been\n" + "# changed from their default value.\n", pf); + + /* + * For "backwards compatibility" the GUI module is written first as its + * at the top of the file. This is followed by all modules that can't + * fit into the preferences read/write API. Finally the remaining modules + * are written in alphabetical order (including of course the protocol preferences) + */ + write_gui_pref_info.pf = pf; + write_gui_pref_info.is_gui_module = TRUE; + + write_module_prefs(gui_module, &write_gui_pref_info); + + { + struct filter_expression *fe = *(struct filter_expression **)prefs.filter_expressions; + + if (fe != NULL) + fprintf(pf, "\n####### Filter Expressions ########\n"); + + while (fe != NULL) { + if (fe->deleted == FALSE) { + fprintf(pf, "%s: %s\n", PRS_GUI_FILTER_LABEL, fe->label); + fprintf(pf, "%s: %s\n", PRS_GUI_FILTER_ENABLED, + fe->enabled == TRUE ? "TRUE" : "FALSE"); + fprintf(pf, "%s: %s\n", PRS_GUI_FILTER_EXPR, fe->expression); + } + fe = fe->next; } - clp = clp->next; - } - fprintf (pf, "\n# Packet list column format.\n"); - fprintf (pf, "# Each pair of strings consists of a column title and its format.\n"); - fprintf (pf, "%s: %s\n", PRS_COL_FMT, put_string_list(col_l)); - /* This frees the list of strings, but not the strings to which it - refers; that's what we want, as we haven't copied those strings, - we just referred to them. */ - g_list_free(col_l); - - fprintf (pf, "\n######## User Interface: Font ########\n"); - - fprintf(pf, "\n# Font name for packet list, protocol tree, and hex dump panes.\n"); - fprintf(pf, PRS_GUI_FONT_NAME_2 ": %s\n", prefs.gui_font_name); - - fprintf (pf, "\n######## User Interface: Colors ########\n"); - - fprintf (pf, "\n# Color preferences for a marked frame.\n"); - fprintf (pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n"); - fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_MARKED_FG, - (prefs.gui_marked_fg.red * 255 / 65535), - (prefs.gui_marked_fg.green * 255 / 65535), - (prefs.gui_marked_fg.blue * 255 / 65535)); - fprintf (pf, "%s: %02x%02x%02x\n", PRS_GUI_MARKED_BG, - (prefs.gui_marked_bg.red * 255 / 65535), - (prefs.gui_marked_bg.green * 255 / 65535), - (prefs.gui_marked_bg.blue * 255 / 65535)); - - /* Don't write the colors of the 10 easy-access-colorfilters to the preferences - * file until the colors can be changed in the GUI. Currently this is not really - * possible since the STOCK-icons for these colors are hardcoded. - * - * XXX Find a way to change the colors of the STOCK-icons on the fly and then - * add these 10 colors to the list of colors that can be changed through - * the preferences. - * - fprintf (pf, "%s: %s\n", PRS_GUI_COLORIZED_FG, prefs.gui_colorized_fg); - fprintf (pf, "%s: %s\n", PRS_GUI_COLORIZED_BG, prefs.gui_colorized_bg); - */ - - fprintf (pf, "\n# TCP stream window color preferences.\n"); - fprintf (pf, "# Each value is a six digit hexadecimal color value in the form rrggbb.\n"); - fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_CL_FG, - (prefs.st_client_fg.red * 255 / 65535), - (prefs.st_client_fg.green * 255 / 65535), - (prefs.st_client_fg.blue * 255 / 65535)); - fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_CL_BG, - (prefs.st_client_bg.red * 255 / 65535), - (prefs.st_client_bg.green * 255 / 65535), - (prefs.st_client_bg.blue * 255 / 65535)); - fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_SR_FG, - (prefs.st_server_fg.red * 255 / 65535), - (prefs.st_server_fg.green * 255 / 65535), - (prefs.st_server_fg.blue * 255 / 65535)); - fprintf (pf, "%s: %02x%02x%02x\n", PRS_STREAM_SR_BG, - (prefs.st_server_bg.red * 255 / 65535), - (prefs.st_server_bg.green * 255 / 65535), - (prefs.st_server_bg.blue * 255 / 65535)); - - fprintf(pf, "\n######## Console: logging level ########\n"); - fprintf(pf, "# (debugging only, not in the Preferences dialog)\n"); - fprintf(pf, "# A bitmask of glib log levels:\n" - "# G_LOG_LEVEL_ERROR = 4\n" - "# G_LOG_LEVEL_CRITICAL = 8\n" - "# G_LOG_LEVEL_WARNING = 16\n" - "# G_LOG_LEVEL_MESSAGE = 32\n" - "# G_LOG_LEVEL_INFO = 64\n" - "# G_LOG_LEVEL_DEBUG = 128\n"); - - fprintf(pf, PRS_CONSOLE_LOG_LEVEL ": %u\n", - prefs.console_log_level); - - fprintf(pf, "\n####### Capture ########\n"); - - if (prefs.capture_device != NULL) { - fprintf(pf, "\n# Default capture device\n"); - fprintf(pf, PRS_CAP_DEVICE ": %s\n", prefs.capture_device); - } - - if (prefs.capture_devices_linktypes != NULL) { - fprintf(pf, "\n# Interface link-layer header types.\n"); - fprintf(pf, "# A decimal number for the DLT.\n"); - fprintf(pf, "# Ex: en0(1),en1(143),...\n"); - fprintf(pf, PRS_CAP_DEVICES_LINKTYPES ": %s\n", prefs.capture_devices_linktypes); - } - - if (prefs.capture_devices_descr != NULL) { - fprintf(pf, "\n# Interface descriptions.\n"); - fprintf(pf, "# Ex: eth0(eth0 descr),eth1(eth1 descr),...\n"); - fprintf(pf, PRS_CAP_DEVICES_DESCR ": %s\n", prefs.capture_devices_descr); } - if (prefs.capture_devices_hide != NULL) { - fprintf(pf, "\n# Hide interface?\n"); - fprintf(pf, "# Ex: eth0,eth3,...\n"); - fprintf(pf, PRS_CAP_DEVICES_HIDE ": %s\n", prefs.capture_devices_hide); - } - - fprintf(pf, "\n# Capture in promiscuous mode?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_CAP_PROM_MODE ": %s\n", - prefs.capture_prom_mode == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Capture in Pcap-NG format?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_CAP_PCAP_NG ": %s\n", - prefs.capture_pcap_ng == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Update packet list in real time during capture?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_CAP_REAL_TIME ": %s\n", - prefs.capture_real_time == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Scroll packet list during capture?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_CAP_AUTO_SCROLL ": %s\n", - prefs.capture_auto_scroll == TRUE ? "TRUE" : "FALSE"); - - fprintf(pf, "\n# Show capture info dialog while capturing?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_CAP_SHOW_INFO ": %s\n", - prefs.capture_show_info == TRUE ? "TRUE" : "FALSE"); - - fprintf (pf, "\n######## Printing ########\n"); - - fprintf (pf, "\n# Can be one of \"text\" or \"postscript\".\n" - "print.format: %s\n", pr_formats[prefs.pr_format]); - - fprintf (pf, "\n# Can be one of \"command\" or \"file\".\n" - "print.destination: %s\n", pr_dests[prefs.pr_dest]); - - fprintf (pf, "\n# This is the file that gets written to when the " - "destination is set to \"file\"\n" - "%s: %s\n", PRS_PRINT_FILE, prefs.pr_file); - - fprintf (pf, "\n# Output gets piped to this command when the destination " - "is set to \"command\"\n" - "%s: %s\n", PRS_PRINT_CMD, prefs.pr_cmd); - - fprintf(pf, "\n####### Name Resolution ########\n"); - - fprintf(pf, "\n# Resolve addresses to names?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive), or a list of address types to resolve.\n"); - fprintf(pf, PRS_NAME_RESOLVE ": %s\n", - name_resolve_to_string(prefs.name_resolve)); - - fprintf(pf, "\n# Name resolution concurrency.\n"); - fprintf(pf, "# A decimal number.\n"); - fprintf(pf, PRS_NAME_RESOLVE_CONCURRENCY ": %d\n", - prefs.name_resolve_concurrency); - - fprintf(pf, "\n####### Taps/Statistics ########\n"); - - fprintf(pf, "\n# Tap update interval in ms.\n"); - fprintf(pf, "# An integer value greater between 100 and 10000.\n"); - fprintf(pf, PRS_TAP_UPDATE_INTERVAL ": %d\n", - prefs.tap_update_interval); - fprintf(pf, "\n# Maximum visible channels in RTP Player window.\n"); - fprintf(pf, "# An integer value greater than 0.\n"); - fprintf(pf, PRS_RTP_PLAYER_MAX_VISIBLE ": %d\n", - prefs.rtp_player_max_visible); - - fprintf(pf, "\n####### Protocols ########\n"); - - fprintf(pf, "\n# Display hidden items in packet details pane?\n"); - fprintf(pf, "# TRUE or FALSE (case-insensitive).\n"); - fprintf(pf, PRS_DISPLAY_HIDDEN_PROTO_ITEMS ": %s\n", - prefs.display_hidden_proto_items == TRUE ? "TRUE" : "FALSE"); - - pe_tree_foreach(prefs_modules, write_module_prefs, pf); + write_gui_pref_info.is_gui_module = FALSE; + prefs_modules_foreach_submodules(NULL, write_module_prefs, &write_gui_pref_info); fclose(pf); @@ -3024,148 +4149,23 @@ write_prefs(char **pf_path_return) return 0; } -/* Copy a set of preferences. */ -void -copy_prefs(e_prefs *dest, e_prefs *src) -{ - fmt_data *src_cfmt, *dest_cfmt; - GList *entry; - - dest->pr_format = src->pr_format; - dest->pr_dest = src->pr_dest; - dest->pr_file = g_strdup(src->pr_file); - dest->pr_cmd = g_strdup(src->pr_cmd); - dest->col_list = NULL; - for (entry = src->col_list; entry != NULL; entry = g_list_next(entry)) { - src_cfmt = entry->data; - dest_cfmt = (fmt_data *) g_malloc(sizeof(fmt_data)); - dest_cfmt->title = g_strdup(src_cfmt->title); - dest_cfmt->fmt = g_strdup(src_cfmt->fmt); - if (src_cfmt->custom_field) { - dest_cfmt->custom_field = g_strdup(src_cfmt->custom_field); - } else { - dest_cfmt->custom_field = NULL; - } - dest->col_list = g_list_append(dest->col_list, dest_cfmt); - } - dest->num_cols = src->num_cols; - dest->st_client_fg = src->st_client_fg; - dest->st_client_bg = src->st_client_bg; - dest->st_server_fg = src->st_server_fg; - dest->st_server_bg = src->st_server_bg; - dest->gui_scrollbar_on_right = src->gui_scrollbar_on_right; - dest->gui_plist_sel_browse = src->gui_plist_sel_browse; - dest->gui_ptree_sel_browse = src->gui_ptree_sel_browse; - dest->gui_altern_colors = src->gui_altern_colors; - dest->filter_toolbar_show_in_statusbar = src->filter_toolbar_show_in_statusbar; - dest->gui_ptree_line_style = src->gui_ptree_line_style; - dest->gui_ptree_expander_style = src->gui_ptree_expander_style; - dest->gui_hex_dump_highlight_style = src->gui_hex_dump_highlight_style; - dest->gui_toolbar_main_style = src->gui_toolbar_main_style; - dest->gui_fileopen_dir = g_strdup(src->gui_fileopen_dir); - dest->gui_console_open = src->gui_console_open; - dest->gui_fileopen_style = src->gui_fileopen_style; - dest->gui_fileopen_preview = src->gui_fileopen_preview; - dest->gui_ask_unsaved = src->gui_ask_unsaved; - dest->gui_find_wrap = src->gui_find_wrap; - dest->gui_use_pref_save = src->gui_use_pref_save; - dest->gui_layout_type = src->gui_layout_type; - dest->gui_layout_content_1 = src->gui_layout_content_1; - dest->gui_layout_content_2 = src->gui_layout_content_2; - dest->gui_layout_content_3 = src->gui_layout_content_3; - dest->gui_font_name = g_strdup(src->gui_font_name); - dest->gui_marked_fg = src->gui_marked_fg; - dest->gui_marked_bg = src->gui_marked_bg; - dest->gui_geometry_save_position = src->gui_geometry_save_position; - dest->gui_geometry_save_size = src->gui_geometry_save_size; - dest->gui_geometry_save_maximized = src->gui_geometry_save_maximized; - dest->gui_macosx_style = src->gui_macosx_style; - dest->gui_webbrowser = g_strdup(src->gui_webbrowser); - dest->gui_window_title = g_strdup(src->gui_window_title); - dest->gui_start_title = g_strdup(src->gui_start_title); - dest->gui_version_in_start_page = src->gui_version_in_start_page; - dest->console_log_level = src->console_log_level; -/* values for the capture dialog box */ - dest->capture_device = g_strdup(src->capture_device); - dest->capture_devices_linktypes = g_strdup(src->capture_devices_linktypes); - dest->capture_devices_descr = g_strdup(src->capture_devices_descr); - dest->capture_devices_hide = g_strdup(src->capture_devices_hide); - dest->capture_prom_mode = src->capture_prom_mode; - dest->capture_pcap_ng = src->capture_pcap_ng; - dest->capture_real_time = src->capture_real_time; - dest->capture_auto_scroll = src->capture_auto_scroll; - dest->capture_show_info = src->capture_show_info; - dest->name_resolve = src->name_resolve; - dest->name_resolve_concurrency = src->name_resolve_concurrency; - dest->display_hidden_proto_items = src->display_hidden_proto_items; - -} - -/* Free a set of preferences. */ -void -free_prefs(e_prefs *pr) -{ - if (pr->pr_file != NULL) { - g_free(pr->pr_file); - pr->pr_file = NULL; - } - if (pr->pr_cmd != NULL) { - g_free(pr->pr_cmd); - pr->pr_cmd = NULL; - } - free_col_info(pr); - if (pr->gui_font_name != NULL) { - g_free(pr->gui_font_name); - pr->gui_font_name = NULL; - } - if (pr->gui_fileopen_dir != NULL) { - g_free(pr->gui_fileopen_dir); - pr->gui_fileopen_dir = NULL; - } - g_free(pr->gui_webbrowser); - pr->gui_webbrowser = NULL; - if (pr->gui_window_title != NULL) { - g_free(pr->gui_window_title); - pr->gui_window_title = NULL; - } - if (pr->gui_start_title != NULL) { - g_free(pr->gui_start_title); - pr->gui_start_title = NULL; - } - if (pr->capture_device != NULL) { - g_free(pr->capture_device); - pr->capture_device = NULL; - } - if (pr->capture_devices_linktypes != NULL) { - g_free(pr->capture_devices_linktypes); - pr->capture_devices_linktypes = NULL; - } - if (pr->capture_devices_descr != NULL) { - g_free(pr->capture_devices_descr); - pr->capture_devices_descr = NULL; - } - if (pr->capture_devices_hide != NULL) { - g_free(pr->capture_devices_hide); - pr->capture_devices_hide = NULL; - } -} - +/** The col_list is only partly managed by the custom preference API + * because its data is shared between multiple preferences, so + * it's freed here + */ static void -free_col_info(e_prefs *pr) +free_col_info(GList * list) { fmt_data *cfmt; - while (pr->col_list != NULL) { - cfmt = pr->col_list->data; + while (list != NULL) { + cfmt = list->data; g_free(cfmt->title); - g_free(cfmt->fmt); g_free(cfmt->custom_field); g_free(cfmt); - pr->col_list = g_list_remove_link(pr->col_list, pr->col_list); + list = g_list_remove_link(list, list); } - g_list_free(pr->col_list); - pr->col_list = NULL; + g_list_free(list); + list = NULL; } - -