From 23a7006c8982d0a8d5b15389200512b69039eb9c Mon Sep 17 00:00:00 2001 From: gerald Date: Tue, 10 Dec 2013 19:23:26 +0000 Subject: [PATCH] Get the "Decode As" dialog working, albeit with a few warts. It differs from the GTK flavor in two major ways: - The "Decode As" and "User Specified Decodes" dialog have been unified. - You can modify the decode as behavior at any time, not just when you have a packet selected. Revert part of 53498 so that we can move items marked /*** THE FOLLOWING SHOULD NOT BE USED BY ANY DISSECTORS!!! ***/ from epan/decode_as.h to ui/decode_as_utils.h. Move "save" code from decode_as_dlg.c to decode_as_utils.c as well. In packet-dcerpc.c don't register a table named "ethertype". We might want to add checks for duplicate table names. To do: - Add support for ranges? - Either add support for DCERPC or make DCERPC use a regular dissector table. - Fix string selectors (i.e. BER). git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@53910 f5534014-38df-0310-8fa8-9805f1628bb7 --- epan/decode_as.c | 210 +-------------- epan/decode_as.h | 39 +-- epan/dissectors/packet-ber.c | 2 +- epan/dissectors/packet-dcerpc.c | 2 +- epan/packet.c | 35 ++- epan/packet.h | 38 ++- epan/prefs.c | 6 +- ui/CMakeLists.txt | 1 + ui/Makefile.common | 2 + ui/decode_as_utils.c | 294 ++++++++++++++++++++ ui/decode_as_utils.h | 93 +++++++ ui/gtk/decode_as_dlg.c | 40 +-- ui/gtk/main.c | 4 + ui/qt/decode_as_dialog.cpp | 461 ++++++++++++++++++++++++++++---- ui/qt/decode_as_dialog.h | 28 ++ ui/qt/decode_as_dialog.ui | 43 ++- ui/qt/preferences_dialog.ui | 5 +- ui/qt/stats_tree_dialog.cpp | 1 + ui/qt/wireshark_application.cpp | 2 +- 19 files changed, 954 insertions(+), 352 deletions(-) create mode 100644 ui/decode_as_utils.c create mode 100644 ui/decode_as_utils.h diff --git a/epan/decode_as.c b/epan/decode_as.c index 9f8791e765..287ffb229c 100644 --- a/epan/decode_as.c +++ b/epan/decode_as.c @@ -24,28 +24,14 @@ #include "config.h" -#include - #include #include "decode_as.h" #include "packet.h" -#include "prefs.h" -#include "prefs-int.h" - -#include "epan/dissectors/packet-dcerpc.h" - -#include "wsutil/filesystem.h" -#include "wsutil/file_util.h" +/* XXX Should this be in ui/decode_as_util? */ GList *decode_as_list = NULL; -/* - * A list of dissectors that need to be reset. - */ -GSList *dissector_reset_list = NULL; - - void register_decode_as(decode_as_t* reg) { /* Ensure valid functions */ @@ -92,7 +78,6 @@ void decode_as_default_populate_list(const gchar *table_name, decode_as_add_to_l dissector_table_foreach_handle(table_name, decode_proto_add_to_list, &populate); } - gboolean decode_as_default_reset(const char *name, const gpointer pattern) { dissector_reset_uint(name, GPOINTER_TO_UINT(pattern)); @@ -107,199 +92,6 @@ gboolean decode_as_default_change(const char *name, const gpointer pattern, gpoi return TRUE; } -/* UI-related functions */ - -/* - * Data structure used as user data when iterating dissector handles - */ -struct lookup_entry { - gchar* dissector_short_name; - dissector_handle_t handle; -}; - -/* - * Data structure for tracking which dissector need to be reset. This - * structure is necessary as a hash table entry cannot be removed - * while a g_hash_table_foreach walk is in progress. - */ -struct dissector_delete_item { - /* The name of the dissector table */ - const gchar *ddi_table_name; - /* The type of the selector in that dissector table */ - ftenum_t ddi_selector_type; - /* The selector in the dissector table */ - union { - guint sel_uint; - char *sel_string; - } ddi_selector; -}; - -typedef struct lookup_entry lookup_entry_t; - -/* - * A callback function to changed a dissector_handle if matched - * This is used when iterating a dissector table - */ -static void -change_dissector_if_matched(gpointer item, gpointer user_data) -{ - dissector_handle_t handle = (dissector_handle_t)item; - lookup_entry_t * lookup = (lookup_entry_t *)user_data; - if (strcmp(lookup->dissector_short_name, dissector_handle_get_short_name(handle)) == 0) { - lookup->handle = handle; - } -} - -/* - * A callback function to parse each "decode as" entry in the file and apply the change - */ -static prefs_set_pref_e -read_set_decode_as_entries(gchar *key, const gchar *value, - void *user_data _U_, - gboolean return_range_errors _U_) -{ - gchar *values[4] = {NULL, NULL, NULL, NULL}; - gchar delimiter[4] = {',', ',', ',','\0'}; - gchar *pch; - guint i, j; - dissector_table_t sub_dissectors; - prefs_set_pref_e retval = PREFS_SET_OK; - gboolean is_valid = FALSE; - - if (strcmp(key, DECODE_AS_ENTRY) == 0) { - /* Parse csv into table, selector, initial, current */ - for (i = 0; i < 4; i++) { - pch = strchr(value, delimiter[i]); - if (pch == NULL) { - for (j = 0; j < i; j++) { - g_free(values[j]); - } - return PREFS_SET_SYNTAX_ERR; - } - values[i] = g_strndup(value, pch - value); - value = pch + 1; - } - sub_dissectors = find_dissector_table(values[0]); - if (sub_dissectors != NULL) { - lookup_entry_t lookup; - lookup.dissector_short_name = values[3]; - lookup.handle = NULL; - g_slist_foreach(dissector_table_get_dissector_handles(sub_dissectors), - change_dissector_if_matched, &lookup); - if (lookup.handle != NULL || g_ascii_strcasecmp(values[3], DECODE_AS_NONE) == 0) { - is_valid = TRUE; - } - - if (is_valid) { - dissector_change_uint(values[0], atoi(values[1]), lookup.handle); - decode_build_reset_list(g_strdup(values[0]), dissector_table_get_type(sub_dissectors), - g_strdup(values[1]), NULL, NULL); - } - } else { - retval = PREFS_SET_SYNTAX_ERR; - } - - } else { - retval = PREFS_SET_NO_SUCH_PREF; - } - - for (i = 0; i < 4; i++) { - g_free(values[i]); - } - return retval; -} - -void load_decode_as_entries(void) -{ - char *daf_path; - FILE *daf; - - if (dissector_reset_list) { - decode_clear_all(); - } - - daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE); - if ((daf = ws_fopen(daf_path, "r")) != NULL) { - read_prefs_file(daf_path, daf, read_set_decode_as_entries, NULL); - fclose(daf); - } - g_free(daf_path); -} - -/* - * A typedef for the data structure to track the original dissector - * used for any given port on any given protocol. - */ -typedef struct dissector_delete_item dissector_delete_item_t; - -void -decode_build_reset_list (const gchar *table_name, ftenum_t selector_type, - gpointer key, gpointer value _U_, - gpointer user_data _U_) -{ - dissector_delete_item_t *item; - - item = g_new(dissector_delete_item_t,1); - item->ddi_table_name = table_name; - item->ddi_selector_type = selector_type; - switch (selector_type) { - - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - item->ddi_selector.sel_uint = GPOINTER_TO_UINT(key); - break; - - case FT_STRING: - case FT_STRINGZ: - item->ddi_selector.sel_string = (char *)key; - break; - - default: - g_assert_not_reached(); - } - dissector_reset_list = g_slist_prepend(dissector_reset_list, item); -} - -/* clear all settings */ -void -decode_clear_all(void) -{ - dissector_delete_item_t *item; - GSList *tmp; - - dissector_all_tables_foreach_changed(decode_build_reset_list, NULL); - - for (tmp = dissector_reset_list; tmp; tmp = g_slist_next(tmp)) { - item = (dissector_delete_item_t *)tmp->data; - switch (item->ddi_selector_type) { - - case FT_UINT8: - case FT_UINT16: - case FT_UINT24: - case FT_UINT32: - dissector_reset_uint(item->ddi_table_name, - item->ddi_selector.sel_uint); - break; - - case FT_STRING: - case FT_STRINGZ: - dissector_reset_string(item->ddi_table_name, - item->ddi_selector.sel_string); - break; - - default: - g_assert_not_reached(); - } - g_free(item); - } - g_slist_free(dissector_reset_list); - dissector_reset_list = NULL; - - decode_dcerpc_reset_all(); -} - /* * Editor modelines * diff --git a/epan/decode_as.h b/epan/decode_as.h index c28d7d60fd..248cdf23bf 100644 --- a/epan/decode_as.h +++ b/epan/decode_as.h @@ -94,43 +94,10 @@ WS_DLL_PUBLIC gboolean decode_as_default_reset(const char *name, const gpointer /* Add a FT_UINT32 value to dissector table list */ WS_DLL_PUBLIC gboolean decode_as_default_change(const char *name, const gpointer pattern, gpointer handle, gchar* list_name); -/*** THE FOLLOWING SHOULD NOT BE USED BY ANY DISSECTORS!!! ***/ - -WS_DLL_PUBLIC GList *decode_as_list; - -/** Reset the "decode as" entries and reload ones of the current profile. - */ -WS_DLL_PUBLIC void load_decode_as_entries(void); - -/* - * This routine creates one entry in the list of protocol dissector - * that need to be reset. It is called by the g_hash_table_foreach - * routine once for each changed entry in a dissector table. - * Unfortunately it cannot delete the entry immediately as this screws - * up the foreach function, so it builds a list of dissectors to be - * reset once the foreach routine finishes. - * - * @param table_name The table name in which this dissector is found. - * - * @param key A pointer to the key for this entry in the dissector - * hash table. This is generally the numeric selector of the - * protocol, i.e. the ethernet type code, IP port number, TCP port - * number, etc. - * - * @param value A pointer to the value for this entry in the dissector - * hash table. This is an opaque pointer that can only be handed back - * to routine in the file packet.c - but it's unused. - * - * @param user_data Unused. +/** List of registered decode_as_t structs. + * For UI code only. Should not be directly accessed by dissectors. */ -WS_DLL_PUBLIC void decode_build_reset_list (const gchar *table_name, ftenum_t selector_type, - gpointer key, gpointer value _U_, - gpointer user_data _U_); - -/** Clear all "decode as" settings - */ -WS_DLL_PUBLIC void decode_clear_all(void); - +WS_DLL_PUBLIC GList *decode_as_list; #ifdef __cplusplus } diff --git a/epan/dissectors/packet-ber.c b/epan/dissectors/packet-ber.c index ffdc7aad39..f8dad61126 100644 --- a/epan/dissectors/packet-ber.c +++ b/epan/dissectors/packet-ber.c @@ -5463,7 +5463,7 @@ proto_register_ber(void) users_uat); ber_oid_dissector_table = register_dissector_table("ber.oid", "BER OID Dissectors", FT_STRING, BASE_NONE); - ber_syntax_dissector_table = register_dissector_table("ber.syntax", "BER Syntax Dissectors", FT_STRING, BASE_NONE); + ber_syntax_dissector_table = register_dissector_table("ber.syntax", "BER syntax", FT_STRING, BASE_NONE); syntax_table = g_hash_table_new(g_str_hash, g_str_equal); /* oid to syntax */ register_ber_syntax_dissector("ASN.1", proto_ber, dissect_ber_syntax); diff --git a/epan/dissectors/packet-dcerpc.c b/epan/dissectors/packet-dcerpc.c index 86e9b9748a..6fd3bcdaaa 100644 --- a/epan/dissectors/packet-dcerpc.c +++ b/epan/dissectors/packet-dcerpc.c @@ -6322,7 +6322,7 @@ proto_register_dcerpc(void) static decode_as_t dcerpc_da = {"dcerpc", "DCE-RPC", /* XXX - DCE/RPC doesn't have a true (sub)dissector table, so provide a "fake" one to fit the Decode As algorithm */ - "ethertype", + "dcerpc.fake", 1, 0, &dcerpc_da_values, NULL, NULL, dcerpc_populate_list, decode_dcerpc_binding_reset, dcerpc_decode_as_change, dcerpc_decode_as_free}; diff --git a/epan/packet.c b/epan/packet.c index 9befce39d1..2a1da2a74a 100644 --- a/epan/packet.c +++ b/epan/packet.c @@ -1070,6 +1070,19 @@ dissector_get_uint_handle(dissector_table_t const sub_dissectors, const guint32 return NULL; } +dissector_handle_t +dissector_get_default_uint_handle(const char *name, const guint32 uint_val) +{ + dissector_table_t sub_dissectors = find_dissector_table(name); + + if (sub_dissectors != NULL) { + dtbl_entry_t *dtbl_entry = find_uint_dtbl_entry(sub_dissectors, uint_val); + if (dtbl_entry != NULL) + return dtbl_entry->initial; + } + return NULL; +} + /* Find an entry in a string dissector table. */ static dtbl_entry_t * find_string_dtbl_entry(dissector_table_t const sub_dissectors, const gchar *pattern) @@ -1322,6 +1335,19 @@ dissector_get_string_handle(dissector_table_t sub_dissectors, return NULL; } +dissector_handle_t +dissector_get_default_string_handle(const char *name, const gchar *string) +{ + dissector_table_t sub_dissectors = find_dissector_table(name); + + if (sub_dissectors != NULL) { + dtbl_entry_t *dtbl_entry = find_string_dtbl_entry(sub_dissectors, string); + if (dtbl_entry != NULL) + return dtbl_entry->initial; + } + return NULL; +} + dissector_handle_t dtbl_entry_get_handle (dtbl_entry_t *dtbl_entry) { @@ -1691,7 +1717,8 @@ register_dissector_table(const char *name, const char *ui_name, const ftenum_t t const char * get_dissector_table_ui_name(const char *name) { - dissector_table_t sub_dissectors = find_dissector_table( name); + dissector_table_t sub_dissectors = find_dissector_table(name); + if (!sub_dissectors) return NULL; return sub_dissectors->ui_name; } @@ -1699,7 +1726,8 @@ get_dissector_table_ui_name(const char *name) ftenum_t get_dissector_table_selector_type(const char *name) { - dissector_table_t sub_dissectors = find_dissector_table( name); + dissector_table_t sub_dissectors = find_dissector_table(name); + if (!sub_dissectors) return FT_NONE; return sub_dissectors->type; } @@ -1707,7 +1735,8 @@ get_dissector_table_selector_type(const char *name) int get_dissector_table_base(const char *name) { - dissector_table_t sub_dissectors = find_dissector_table( name); + dissector_table_t sub_dissectors = find_dissector_table(name); + if (!sub_dissectors) return 0; return sub_dissectors->base; } diff --git a/epan/packet.h b/epan/packet.h index 205df7ff3b..2b850c3782 100644 --- a/epan/packet.h +++ b/epan/packet.h @@ -256,11 +256,26 @@ WS_DLL_PUBLIC gboolean dissector_try_uint(dissector_table_t sub_dissectors, WS_DLL_PUBLIC gboolean dissector_try_uint_new(dissector_table_t sub_dissectors, const guint32 uint_val, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, const gboolean add_proto_name, void *data); -/* Look for a given value in a given uint dissector table and, if found, - return the dissector handle for that value. */ +/** Look for a given value in a given uint dissector table and, if found, + * return the current dissector handle for that value. + * + * @param[in] sub_dissectors Dissector table to search. + * @param[in] uint_val Value to match, e.g. the port number for the TCP dissector. + * @return The matching dissector handle on success, NULL if no match is found. + */ WS_DLL_PUBLIC dissector_handle_t dissector_get_uint_handle( dissector_table_t const sub_dissectors, const guint32 uint_val); +/** Look for a given value in a given uint dissector table and, if found, + * return the default dissector handle for that value. + * + * @param[in] name Dissector table name. + * @param[in] uint_val Value to match, e.g. the port number for the TCP dissector. + * @return The matching dissector handle on success, NULL if no match is found. + */ +WS_DLL_PUBLIC dissector_handle_t dissector_get_default_uint_handle( + const char *name, const guint32 uint_val); + /* Add an entry to a string dissector table. */ WS_DLL_PUBLIC void dissector_add_string(const char *name, const gchar *pattern, dissector_handle_t handle); @@ -284,11 +299,26 @@ WS_DLL_PUBLIC void dissector_reset_string(const char *name, const gchar *pattern WS_DLL_PUBLIC gboolean dissector_try_string(dissector_table_t sub_dissectors, const gchar *string, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data); -/* Look for a given value in a given string dissector table and, if found, - return the dissector handle for that value. */ +/** Look for a given value in a given string dissector table and, if found, + * return the current dissector handle for that value. + * + * @param[in] sub_dissectors Dissector table to search. + * @param[in] string Value to match, e.g. the OID for the BER dissector. + * @return The matching dissector handle on success, NULL if no match is found. + */ WS_DLL_PUBLIC dissector_handle_t dissector_get_string_handle( dissector_table_t sub_dissectors, const gchar *string); +/** Look for a given value in a given string dissector table and, if found, + * return the default dissector handle for that value. + * + * @param[in] name Dissector table name. + * @param[in] string Value to match, e.g. the OID for the BER dissector. + * @return The matching dissector handle on success, NULL if no match is found. + */ +WS_DLL_PUBLIC dissector_handle_t dissector_get_default_string_handle( + const char *name, const gchar *string); + /* Add a handle to the list of handles that *could* be used with this table. That list is used by code in the UI. */ WS_DLL_PUBLIC void dissector_add_handle(const char *name, dissector_handle_t handle); diff --git a/epan/prefs.c b/epan/prefs.c index b3e210df43..cb4daa3bdc 100644 --- a/epan/prefs.c +++ b/epan/prefs.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #ifdef HAVE_GEOIP #include @@ -3270,9 +3269,6 @@ read_prefs(int *gpf_errno_return, int *gpf_read_errno_return, /* load SMI modules if needed */ oids_init(); - /* load the decode as entries of this profile */ - load_decode_as_entries(); - return &prefs; } @@ -4795,7 +4791,7 @@ 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" + "# 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); diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index 7ddd0e50a2..b7b768d922 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -24,6 +24,7 @@ set(COMMON_UI_SRC alert_box.c + decode_as_utils.c export_object.c export_object_dicom.c export_object_http.c diff --git a/ui/Makefile.common b/ui/Makefile.common index 6845b5519f..7cb273164b 100644 --- a/ui/Makefile.common +++ b/ui/Makefile.common @@ -45,6 +45,7 @@ GENERATOR_FILES = \ WIRESHARK_UI_SRC = \ alert_box.c \ + decode_as_utils.c \ export_object.c \ export_object_dicom.c \ export_object_http.c \ @@ -71,6 +72,7 @@ WIRESHARK_UI_SRC = \ noinst_HEADERS = \ alert_box.h \ capture_globals.h \ + decode_as_utils.h \ export_object.h \ last_open_dir.h \ file_dialog.h \ diff --git a/ui/decode_as_utils.c b/ui/decode_as_utils.c new file mode 100644 index 0000000000..d78c5d8dde --- /dev/null +++ b/ui/decode_as_utils.c @@ -0,0 +1,294 @@ +/* decode_as_utils.c + * + * $Id$ + * + * Routines to modify dissector tables on the fly. + * + * By David Hampton + * Copyright 2001 David Hampton + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "config.h" + +#include + +#include +#include + +#include "epan/decode_as.h" +#include "epan/packet.h" +#include "epan/prefs.h" +#include "epan/prefs-int.h" + +#include "epan/dissectors/packet-dcerpc.h" + +#include "ui/decode_as_utils.h" +#include "ui/simple_dialog.h" + +#include "wsutil/file_util.h" +#include "wsutil/filesystem.h" + +#include "version_info.h" + +/* + * A list of dissectors that need to be reset. + */ +static GSList *dissector_reset_list = NULL; + +/* + * Data structure used as user data when iterating dissector handles + */ +typedef struct lookup_entry { + gchar* dissector_short_name; + dissector_handle_t handle; +} lookup_entry_t; + +/* + * Data structure for tracking which dissector need to be reset. This + * structure is necessary as a hash table entry cannot be removed + * while a g_hash_table_foreach walk is in progress. + */ +typedef struct dissector_delete_item { + /* The name of the dissector table */ + const gchar *ddi_table_name; + /* The type of the selector in that dissector table */ + ftenum_t ddi_selector_type; + /* The selector in the dissector table */ + union { + guint sel_uint; + char *sel_string; + } ddi_selector; +} dissector_delete_item_t; + +/* + * A callback function to changed a dissector_handle if matched + * This is used when iterating a dissector table + */ +static void +change_dissector_if_matched(gpointer item, gpointer user_data) +{ + dissector_handle_t handle = (dissector_handle_t)item; + lookup_entry_t * lookup = (lookup_entry_t *)user_data; + if (strcmp(lookup->dissector_short_name, dissector_handle_get_short_name(handle)) == 0) { + lookup->handle = handle; + } +} + +/* + * A callback function to parse each "decode as" entry in the file and apply the change + */ +static prefs_set_pref_e +read_set_decode_as_entries(gchar *key, const gchar *value, + void *user_data _U_, + gboolean return_range_errors _U_) +{ + gchar *values[4] = {NULL, NULL, NULL, NULL}; + gchar delimiter[4] = {',', ',', ',','\0'}; + gchar *pch; + guint i, j; + dissector_table_t sub_dissectors; + prefs_set_pref_e retval = PREFS_SET_OK; + gboolean is_valid = FALSE; + + if (strcmp(key, DECODE_AS_ENTRY) == 0) { + /* Parse csv into table, selector, initial, current */ + for (i = 0; i < 4; i++) { + pch = strchr(value, delimiter[i]); + if (pch == NULL) { + for (j = 0; j < i; j++) { + g_free(values[j]); + } + return PREFS_SET_SYNTAX_ERR; + } + values[i] = g_strndup(value, pch - value); + value = pch + 1; + } + sub_dissectors = find_dissector_table(values[0]); + if (sub_dissectors != NULL) { + lookup_entry_t lookup; + lookup.dissector_short_name = values[3]; + lookup.handle = NULL; + ftenum_t selector_type = dissector_table_get_type(sub_dissectors); + g_slist_foreach(dissector_table_get_dissector_handles(sub_dissectors), + change_dissector_if_matched, &lookup); + if (lookup.handle != NULL || g_ascii_strcasecmp(values[3], DECODE_AS_NONE) == 0) { + is_valid = TRUE; + } + + if (is_valid) { + if (selector_type == FT_STRING || selector_type == FT_STRINGZ) { + dissector_change_string(values[0], values[1], lookup.handle); + } else { + dissector_change_uint(values[0], atoi(values[1]), lookup.handle); + } + decode_build_reset_list(g_strdup(values[0]), selector_type, + g_strdup(values[1]), NULL, NULL); + } + } else { + retval = PREFS_SET_SYNTAX_ERR; + } + + } else { + retval = PREFS_SET_NO_SUCH_PREF; + } + + for (i = 0; i < 4; i++) { + g_free(values[i]); + } + return retval; +} + +void +load_decode_as_entries(void) +{ + char *daf_path; + FILE *daf; + + if (dissector_reset_list) { + decode_clear_all(); + } + + daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE); + if ((daf = ws_fopen(daf_path, "r")) != NULL) { + read_prefs_file(daf_path, daf, read_set_decode_as_entries, NULL); + fclose(daf); + } + g_free(daf_path); +} + +void +decode_build_reset_list (const gchar *table_name, ftenum_t selector_type, + gpointer key, gpointer value _U_, + gpointer user_data _U_) +{ + dissector_delete_item_t *item; + + item = g_new(dissector_delete_item_t,1); + item->ddi_table_name = table_name; + item->ddi_selector_type = selector_type; + switch (selector_type) { + + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + item->ddi_selector.sel_uint = GPOINTER_TO_UINT(key); + break; + + case FT_STRING: + case FT_STRINGZ: + item->ddi_selector.sel_string = (char *)key; + break; + + default: + g_assert_not_reached(); + } + dissector_reset_list = g_slist_prepend(dissector_reset_list, item); +} + +/* clear all settings */ +void +decode_clear_all(void) +{ + dissector_delete_item_t *item; + GSList *tmp; + + dissector_all_tables_foreach_changed(decode_build_reset_list, NULL); + + for (tmp = dissector_reset_list; tmp; tmp = g_slist_next(tmp)) { + item = (dissector_delete_item_t *)tmp->data; + switch (item->ddi_selector_type) { + + case FT_UINT8: + case FT_UINT16: + case FT_UINT24: + case FT_UINT32: + dissector_reset_uint(item->ddi_table_name, + item->ddi_selector.sel_uint); + break; + + case FT_STRING: + case FT_STRINGZ: + dissector_reset_string(item->ddi_table_name, + item->ddi_selector.sel_string); + break; + + default: + g_assert_not_reached(); + } + g_free(item); + } + g_slist_free(dissector_reset_list); + dissector_reset_list = NULL; + + decode_dcerpc_reset_all(); +} + +/* XXX - We might want to switch this to a UAT */ +FILE * +decode_as_open() { + char *pf_dir_path; + char *daf_path; + FILE *da_file; + + if (create_persconffile_dir(&pf_dir_path) == -1) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path, + g_strerror(errno)); + g_free(pf_dir_path); + return NULL; + } + + daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE); + if ((da_file = ws_fopen(daf_path, "w")) == NULL) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "Can't open decode_as_entries file\n\"%s\": %s.", daf_path, + g_strerror(errno)); + g_free(daf_path); + return NULL; + } + + fputs("# \"Decode As\" entries file for Wireshark " VERSION ".\n" + "#\n" + "# This file is regenerated each time \"Decode As\" preferences\n" + "# are saved within Wireshark. Making manual changes should be safe," + "# however.\n", da_file); + + return da_file; +} + +/* XXX We might want to have separate int and string routines. */ +void +decode_as_write_entry(FILE *da_file, const char *table_name, const char *selector, const char *default_proto, const char *current_proto) { + fprintf (da_file, + DECODE_AS_ENTRY ": %s,%s,%s,%s\n", + table_name, selector, default_proto, current_proto); +} + + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ + diff --git a/ui/decode_as_utils.h b/ui/decode_as_utils.h new file mode 100644 index 0000000000..de050c731f --- /dev/null +++ b/ui/decode_as_utils.h @@ -0,0 +1,93 @@ +/* decode_as_utils.h + * + * $Id$ + * + * "Decode As" UI utility routines. + * + * By David Hampton + * Copyright 2001 David Hampton + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef __DECODE_AS_UTILS_H__ +#define __DECODE_AS_UTILS_H__ + +/** @file + * "Decode As" / "User Specified Decodes" dialog box. + * @ingroup main_ui_group + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** Reset the "decode as" entries and reload ones of the current profile. + */ +WS_DLL_PUBLIC void load_decode_as_entries(void); + +/** This routine creates one entry in the list of protocol dissector + * that need to be reset. It is called by the g_hash_table_foreach + * routine once for each changed entry in a dissector table. + * Unfortunately it cannot delete the entry immediately as this screws + * up the foreach function, so it builds a list of dissectors to be + * reset once the foreach routine finishes. + * + * @param table_name The table name in which this dissector is found. + * + * @param key A pointer to the key for this entry in the dissector + * hash table. This is generally the numeric selector of the + * protocol, i.e. the ethernet type code, IP port number, TCP port + * number, etc. + * + * @param value A pointer to the value for this entry in the dissector + * hash table. This is an opaque pointer that can only be handed back + * to routine in the file packet.c - but it's unused. + * + * @param user_data Unused. + */ +WS_DLL_PUBLIC void decode_build_reset_list (const gchar *table_name, ftenum_t selector_type, + gpointer key, gpointer value _U_, + gpointer user_data _U_); + +/** Clear all "decode as" settings. + */ +WS_DLL_PUBLIC void decode_clear_all(void); + +/** Open the "decode_as_entries" configuration file and write its header. + * + * Entries should be written with decode_as_write_entry(). The file should + * be closed with fclose(). + * + * @return A valid FILE pointer on success, NULL on failure. + */ +FILE *decode_as_open(); + +/** Write an entry to the "decode_as_entries" file. + * + * @param[in] da_file FILE pointer returned by decode_as_open(). + * @param[in] table_name A short decode_as table name. + * @param[in] selector Integer or string selector, e.g. 80 for TCP port 80. + * @param[in] default_proto The default protocol for the selector, or "(none)". + * @param[in] current_proto The desired protocol for the selector, or "(none)" to disable. + */ +void decode_as_write_entry(FILE *da_file, const char *table_name, const char *selector, const char *default_proto, const char *current_proto); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __DECODE_AS_UTILS_H__ */ diff --git a/ui/gtk/decode_as_dlg.c b/ui/gtk/decode_as_dlg.c index bb676f209d..9b4ae16c21 100644 --- a/ui/gtk/decode_as_dlg.c +++ b/ui/gtk/decode_as_dlg.c @@ -22,7 +22,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "config.h" -#include #include #include @@ -32,11 +31,10 @@ #include #include -#include #include #include -#include +#include "ui/decode_as_utils.h" #include "ui/simple_dialog.h" #include "ui/utf8_entities.h" @@ -162,7 +160,10 @@ write_da_entry(gpointer item, gpointer user_data) { da_entry_t *entry = (da_entry_t *)item; FILE *daf = (FILE *)user_data; - fprintf (daf, DECODE_AS_ENTRY ": %s,%d,%s,%s\n", entry->table, entry->selector, entry->initial, entry->current); + gchar *selector_str = g_strdup_printf("%d", entry->selector); + + decode_as_write_entry(daf, entry->table, selector_str, entry->initial, entry->current); + g_free(selector_str); } /* @@ -452,35 +453,10 @@ decode_show_destroy_cb (GtkWidget *win _U_, gpointer user_data _U_) static void decode_show_save_cb (GtkWidget *win _U_, gpointer user_data _U_) { - char *pf_dir_path; - char *daf_path; - FILE *daf; - - if (create_persconffile_dir(&pf_dir_path) == -1) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Can't create directory\n\"%s\"\nfor recent file: %s.", pf_dir_path, - g_strerror(errno)); - g_free(pf_dir_path); - return; - } - - daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE); - if ((daf = ws_fopen(daf_path, "w")) == NULL) { - simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, - "Can't open decode_as_entries file\n\"%s\": %s.", daf_path, - g_strerror(errno)); - g_free(daf_path); - return; - } - - fputs("# \"Decode As\" entries file for Wireshark " VERSION ".\n" - "#\n" - "# This file is regenerated when saving the \"Decode As...\" list.\n" - "# So be careful, if you want to make manual changes here.\n" - "\n" - "######## Decode As table entries, can be altered through command line ########\n" - "\n", daf); + FILE *daf = decode_as_open(); + if (!daf) return; + g_slist_foreach(da_entries, write_da_entry, daf); fclose(daf); diff --git a/ui/gtk/main.c b/ui/gtk/main.c index ba605c8e06..774d321dd5 100644 --- a/ui/gtk/main.c +++ b/ui/gtk/main.c @@ -112,6 +112,7 @@ #include "gtk_iface_monitor.h" #include "ui/alert_box.h" +#include "ui/decode_as_utils.h" #include "ui/main_statusbar.h" #include "ui/persfilepath_opt.h" #include "ui/preference_utils.h" @@ -1973,6 +1974,9 @@ read_configuration_files(char **gdp_path, char **dp_path) int pf_open_errno, pf_read_errno; e_prefs *prefs_p; + /* load the decode as entries of this profile */ + load_decode_as_entries(); + /* Read the preference files. */ prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path, &pf_open_errno, &pf_read_errno, &pf_path); diff --git a/ui/qt/decode_as_dialog.cpp b/ui/qt/decode_as_dialog.cpp index 284d070ec0..8d36d13ded 100644 --- a/ui/qt/decode_as_dialog.cpp +++ b/ui/qt/decode_as_dialog.cpp @@ -26,24 +26,52 @@ #include "epan/decode_as.h" #include "epan/dissectors/packet-dcerpc.h" +#include "epan/epan_dissect.h" + +#include "ui/decode_as_utils.h" +#include "ui/utf8_entities.h" #include "wireshark_application.h" -#include +#include +#include +#include + +// To do: +// - Ranges +// - Add DCERPC support (or make DCERPC use a regular dissector table?) +// - Fix string (BER) selectors -#include +const int table_col_ = 0; +const int selector_col_ = 1; +const int type_col_ = 2; +const int default_col_ = 3; // aka "initial" +const int proto_col_ = 4; // aka "current" -const int field_col_ = 0; -const int value_col_ = 1; -const int default_col_ = 2; -const int current_col_ = 3; +const char *default_table_ = "TCP port"; +const char *default_proto_ = "HTTP"; +const char *default_int_selector_ = "0"; // Arbitrary +const char *default_str_selector_ = "foo"; // Arbitrary +const int max_name_em_width_ = 10; // Some table names are a tad long. DecodeAsDialog::DecodeAsDialog(QWidget *parent, capture_file *cf) : QDialog(parent), ui(new Ui::DecodeAsDialog), - cap_file_(cf) + cap_file_(cf), + table_names_combo_box_(NULL), + selector_combo_box_(NULL) { ui->setupUi(this); + ui->deleteToolButton->setEnabled(false); + + GList *cur; + for (cur = decode_as_list; cur; cur = cur->next) { + decode_as_t *entry = (decode_as_t *) cur->data; + QString table_ui_name = get_dissector_table_ui_name(entry->table_name); + if (!table_ui_name.isEmpty()) { + ui_name_to_name_[table_ui_name] = entry->table_name; + } + } connect(wsApp, SIGNAL(preferencesChanged()), this, SLOT(fillTable())); fillTable(); @@ -60,31 +88,10 @@ void DecodeAsDialog::setCaptureFile(capture_file *cf) fillTable(); } -void DecodeAsDialog::fillTable() +QString DecodeAsDialog::entryString(const gchar *table_name, gpointer value) { - ui->decodeAsTreeWidget->clear(); - dissector_all_tables_foreach_changed(buildChangedList, this); - decode_dcerpc_add_show_list(buildDceRpcChangedList, this); -} - -void DecodeAsDialog::buildChangedList(const gchar *table_name, ftenum_t selector_type, gpointer key, gpointer value, gpointer user_data) -{ - DecodeAsDialog *da_dlg = (DecodeAsDialog *)user_data; - if (!da_dlg) return; - - dissector_handle_t default_dh, current_dh; - QString value_str; - QString default_proto_name = "(none)", current_proto_name = "(none)"; - QTreeWidgetItem *ti = new QTreeWidgetItem(); - - current_dh = dtbl_entry_get_handle((dtbl_entry_t *)value); - if (current_dh) { - current_proto_name = dissector_handle_get_short_name(current_dh); - } - default_dh = dtbl_entry_get_initial_handle((dtbl_entry_t *)value); - if (default_dh) { - default_proto_name = dissector_handle_get_short_name(default_dh); - } + QString entry_str; + ftenum_t selector_type = get_dissector_table_selector_type(table_name); switch (selector_type) { @@ -92,66 +99,420 @@ void DecodeAsDialog::buildChangedList(const gchar *table_name, ftenum_t selector case FT_UINT16: case FT_UINT24: case FT_UINT32: + { + uint num_val = GPOINTER_TO_UINT(value); switch (get_dissector_table_base(table_name)) { case BASE_DEC: - value_str = QString::number(GPOINTER_TO_UINT(key)); + entry_str = QString::number(num_val); break; case BASE_HEX: - switch (get_dissector_table_selector_type(table_name)) { - + int width; + switch (selector_type) { case FT_UINT8: - value_str = QString("%1").arg(GPOINTER_TO_UINT(key), 2, 16, QChar('0')); + width = 2; break; - case FT_UINT16: - value_str = QString("%1").arg(GPOINTER_TO_UINT(key), 4, 16, QChar('0')); + width = 4; break; - case FT_UINT24: - value_str = QString("%1").arg(GPOINTER_TO_UINT(key), 6, 16, QChar('0')); + width = 6; break; - case FT_UINT32: - value_str = QString("%1").arg(GPOINTER_TO_UINT(key), 8, 16, QChar('0')); + width = 8; break; default: g_assert_not_reached(); break; } + entry_str = QString("0x%1").arg(num_val, width, 16, QChar('0')); break; case BASE_OCT: - value_str = QString::number(GPOINTER_TO_UINT(key), 8); + entry_str = "0" + QString::number(num_val, 8); break; } break; + } case FT_STRING: case FT_STRINGZ: - value_str = (char *)key; + entry_str = (char *)value; break; default: g_assert_not_reached(); break; } + return entry_str; +} - ti->setText(field_col_, get_dissector_table_ui_name(table_name)); - ti->setText(value_col_, value_str); - ti->setText(default_col_, default_proto_name); - ti->setText(current_col_, current_proto_name); +void DecodeAsDialog::fillTable() +{ + ui->decodeAsTreeWidget->clear(); + dissector_all_tables_foreach_changed(buildChangedList, this); + decode_dcerpc_add_show_list(buildDceRpcChangedList, this); - da_dlg->ui->decodeAsTreeWidget->addTopLevelItem(ti); + ui->decodeAsTreeWidget->resizeColumnToContents(table_col_); + ui->decodeAsTreeWidget->resizeColumnToContents(selector_col_); + ui->decodeAsTreeWidget->resizeColumnToContents(type_col_); + ui->decodeAsTreeWidget->resizeColumnToContents(default_col_); + ui->decodeAsTreeWidget->resizeColumnToContents(proto_col_); +} + +void DecodeAsDialog::activateLastItem() +{ + int last_idx = ui->decodeAsTreeWidget->topLevelItemCount() - 1; + if (last_idx < 0) return; + + QTreeWidgetItem *last_item = ui->decodeAsTreeWidget->invisibleRootItem()->child(last_idx); + if (!last_item) return; + + ui->decodeAsTreeWidget->setCurrentItem(last_item); + on_decodeAsTreeWidget_itemActivated(last_item); +} + +void DecodeAsDialog::on_decodeAsTreeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) +{ + if (current == previous) return; + + for (int col = 0; col < ui->decodeAsTreeWidget->columnCount(); col++) { + if (previous && ui->decodeAsTreeWidget->itemWidget(previous, col)) { + ui->decodeAsTreeWidget->removeItemWidget(previous, col); + } + } +} + +void DecodeAsDialog::on_decodeAsTreeWidget_itemActivated(QTreeWidgetItem *item, int column) +{ + Q_UNUSED(column); + GList *cur; + + table_names_combo_box_ = new QComboBox(); + QString current_text = item->text(table_col_); + QSet da_set; + + // If a packet is selected group its tables at the top in order + // from last-dissected to first. + + for (cur = decode_as_list; cur; cur = cur->next) { + decode_as_t *entry = (decode_as_t *) cur->data; + const char *table_name = get_dissector_table_ui_name(entry->table_name); + if (table_name) { + da_set.insert(get_dissector_table_ui_name(entry->table_name)); + } + } + + if (cap_file_ && cap_file_->edt) { + bool copying = !current_text.isEmpty(); + wmem_list_frame_t * protos = wmem_list_head(cap_file_->edt->pi.layers); + while (protos != NULL) { + int proto_id = GPOINTER_TO_INT(wmem_list_frame_data(protos)); + const gchar * proto_name = proto_get_protocol_filter_name(proto_id); + for (cur = decode_as_list; cur; cur = cur->next) { + decode_as_t *entry = (decode_as_t *) cur->data; + if (g_strcmp0(proto_name, entry->name) == 0) { + QString table_ui_name = get_dissector_table_ui_name(entry->table_name); + table_names_combo_box_->insertItem(0, table_ui_name, entry->table_name); + da_set.remove(table_ui_name); + if (!copying) { + current_text = table_ui_name; + } + } + } + protos = wmem_list_frame_next(protos); + } + } + + if (table_names_combo_box_->count() > 0) { + table_names_combo_box_->insertSeparator(table_names_combo_box_->count()); + } + + QList da_list = da_set.toList(); + qSort(da_list.begin(), da_list.end()); + + foreach (QString table_ui_name, da_list) { + table_names_combo_box_->addItem(table_ui_name, ui_name_to_name_[table_ui_name]); + } + + if (current_text.isEmpty()) current_text = default_table_; + ui->decodeAsTreeWidget->setItemWidget(item, table_col_, table_names_combo_box_); + + selector_combo_box_ = new QComboBox(); + selector_combo_box_->setEditable(true); + selector_combo_box_->setCurrentText(item->text(selector_col_)); + + connect(selector_combo_box_, SIGNAL(destroyed()), this, SLOT(selectorDestroyed())); + connect(selector_combo_box_, SIGNAL(editTextChanged(QString)), this, SLOT(selectorEditTextChanged(QString))); + + ui->decodeAsTreeWidget->setItemWidget(item, selector_col_, selector_combo_box_); + + cur_proto_combo_box_ = new QComboBox(); + + ui->decodeAsTreeWidget->setItemWidget(item, proto_col_, cur_proto_combo_box_); + connect(cur_proto_combo_box_, SIGNAL(currentIndexChanged(const QString &)), + this, SLOT(curProtoCurrentIndexChanged(const QString &))); + connect(cur_proto_combo_box_, SIGNAL(destroyed()), this, SLOT(curProtoDestroyed())); + + table_names_combo_box_->setCurrentText(current_text); + tableNamesCurrentIndexChanged(current_text); + + connect(table_names_combo_box_, SIGNAL(currentIndexChanged(const QString &)), + this, SLOT(tableNamesCurrentIndexChanged(const QString &))); + connect(table_names_combo_box_, SIGNAL(destroyed()), this, SLOT(tableNamesDestroyed())); + table_names_combo_box_->setFocus(); + + QFontMetrics fm(font()); + ui->decodeAsTreeWidget->setColumnWidth(table_col_, fm.height() * max_name_em_width_); + ui->decodeAsTreeWidget->setColumnWidth(selector_col_, fm.height() * max_name_em_width_); +} + +void DecodeAsDialog::on_decodeAsTreeWidget_itemSelectionChanged() +{ + if (ui->decodeAsTreeWidget->selectedItems().length() > 0) { + ui->deleteToolButton->setEnabled(true); + ui->copyToolButton->setEnabled(true); + } else { + ui->deleteToolButton->setEnabled(false); + ui->copyToolButton->setEnabled(false); + } +} + +void DecodeAsDialog::buildChangedList(const gchar *table_name, ftenum_t selector_type, gpointer key, gpointer value, gpointer user_data) +{ + Q_UNUSED(selector_type); + + DecodeAsDialog *da_dlg = (DecodeAsDialog *)user_data; + if (!da_dlg) return; + + dissector_handle_t default_dh, current_dh; + QString default_proto_name = DECODE_AS_NONE, current_proto_name = DECODE_AS_NONE; + QTreeWidgetItem *item = new QTreeWidgetItem(); + + item->setText(table_col_, get_dissector_table_ui_name(table_name)); + item->setText(selector_col_, da_dlg->entryString(table_name, key)); + da_dlg->fillTypeColumn(item); + + default_dh = dtbl_entry_get_initial_handle((dtbl_entry_t *)value); + if (default_dh) { + default_proto_name = dissector_handle_get_short_name(default_dh); + } + item->setText(default_col_, default_proto_name); + + current_dh = dtbl_entry_get_handle((dtbl_entry_t *)value); + if (current_dh) { + current_proto_name = dissector_handle_get_short_name(current_dh); + } + item->setText(proto_col_, current_proto_name); + + da_dlg->ui->decodeAsTreeWidget->addTopLevelItem(item); } void DecodeAsDialog::buildDceRpcChangedList(gpointer data, gpointer user_data) { + Q_UNUSED(data); Q_UNUSED(user_data); - decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)data; - qDebug() << "=bdcecl" << binding->ifname; + // decode_dcerpc_bind_values_t *binding = (decode_dcerpc_bind_values_t *)data; +} + +void DecodeAsDialog::addRecord(bool copy_from_current) +{ + QTreeWidgetItem *cur_ti = NULL; + + if (copy_from_current) { + cur_ti = ui->decodeAsTreeWidget->currentItem(); + if (!cur_ti) return; + } + + QTreeWidgetItem *ti = new QTreeWidgetItem(); + ui->decodeAsTreeWidget->addTopLevelItem(ti); + + if (cur_ti) { + ti->setText(table_col_, cur_ti->text(table_col_)); + ti->setText(selector_col_, cur_ti->text(selector_col_)); + ti->setText(default_col_, cur_ti->text(default_col_)); + ti->setText(proto_col_, cur_ti->text(proto_col_)); + } + + activateLastItem(); +} + +void DecodeAsDialog::fillTypeColumn(QTreeWidgetItem *item) +{ + if (!item) return; + const char *table_name = ui_name_to_name_[item->text(table_col_)]; + + ftenum_t selector_type = get_dissector_table_selector_type(table_name); + + if (selector_type == FT_STRING || selector_type == FT_STRINGZ) { + item->setText(type_col_, tr("String")); + } else { + QString type_desc = tr("Integer, base "); + switch (get_dissector_table_base(table_name)) { + case BASE_OCT: + type_desc.append("8"); + break; + case BASE_DEC: + type_desc.append("10"); + break; + case BASE_HEX: + type_desc.append("16"); + break; + default: + type_desc.append(tr("unkown")); + } + item->setText(type_col_, type_desc); + } +} + +void DecodeAsDialog::on_newToolButton_clicked() +{ + addRecord(); +} + +void DecodeAsDialog::on_deleteToolButton_clicked() +{ + QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem(); + if (!item) return; + delete item; +} + +void DecodeAsDialog::on_copyToolButton_clicked() +{ + addRecord(true); +} + +void DecodeAsDialog::tableNamesDestroyed() +{ + table_names_combo_box_ = NULL; +} + +void DecodeAsDialog::decodeAddProtocol(const gchar *table_name, const gchar *proto_name, gpointer value, gpointer user_data) +{ + Q_UNUSED(table_name); + Q_UNUSED(value); + + QSet *proto_set = (QSet *)user_data; + if (!proto_set) return; + + proto_set->insert(proto_name); +} + +void DecodeAsDialog::tableNamesCurrentIndexChanged(const QString &text) +{ + QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem(); + if (!item || text.isEmpty() || !selector_combo_box_ || !cur_proto_combo_box_) return; + + QString current_text = item->text(proto_col_); + if (current_text.isEmpty()) current_text = default_proto_; + + item->setText(table_col_, text); + item->setText(selector_col_, QString()); + fillTypeColumn(item); + + selector_combo_box_->clear(); + + QSet proto_set; // We want a unique list + GList *cur; + for (cur = decode_as_list; cur; cur = cur->next) { + decode_as_t *entry = (decode_as_t *) cur->data; + if (g_strcmp0(ui_name_to_name_[text], entry->table_name) == 0) { + if (cap_file_ && cap_file_->edt) { + for (uint ni = 0; ni < entry->num_items; ni++) { + if (entry->values[ni].num_values == 1) { // Skip over multi-value ("both") entries + selector_combo_box_->addItem(entryString(entry->table_name, + entry->values[ni].build_values[0](&cap_file_->edt->pi))); + } + } + selector_combo_box_->setCurrentIndex(entry->default_index_value); + } + entry->populate_list(entry->table_name, decodeAddProtocol, &proto_set); + } + } + if (selector_combo_box_->count() > 0) { + selector_combo_box_->setCurrentIndex(0); + } else { + ftenum_t selector_type = get_dissector_table_selector_type(ui_name_to_name_[text]); + if (selector_type == FT_STRING || selector_type == FT_STRINGZ) { + selector_combo_box_->setEditText(default_str_selector_); + } else { + selector_combo_box_->setEditText(default_int_selector_); + } + } + + QList proto_list = proto_set.toList(); + qSort(proto_list); + cur_proto_combo_box_->clear(); + cur_proto_combo_box_->addItem(DECODE_AS_NONE); + cur_proto_combo_box_->insertSeparator(cur_proto_combo_box_->count()); + cur_proto_combo_box_->addItems(proto_list); + cur_proto_combo_box_->setCurrentText(current_text); +} + +void DecodeAsDialog::selectorDestroyed() +{ + selector_combo_box_ = NULL; +} + +void DecodeAsDialog::selectorEditTextChanged(const QString &text) +{ + QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem(); + if (!item || !table_names_combo_box_ || !selector_combo_box_) return; + + const char *table_name = ui_name_to_name_[table_names_combo_box_->currentText()]; + if (!table_name) return; + + item->setText(selector_col_, text); + ftenum_t selector_type = get_dissector_table_selector_type(table_name); + dissector_handle_t dissector; + + if (selector_type == FT_STRING || selector_type == FT_STRINGZ) { + dissector = dissector_get_default_string_handle(table_name, text.toUtf8().constData()); + } else { + dissector = dissector_get_default_uint_handle(table_name, text.toInt(NULL, 0)); + } + + if (dissector) { + item->setText(default_col_, dissector_handle_get_short_name(dissector)); + } else { + item->setText(default_col_, DECODE_AS_NONE); + } +} + +void DecodeAsDialog::curProtoCurrentIndexChanged(const QString &text) +{ + QTreeWidgetItem *item = ui->decodeAsTreeWidget->currentItem(); + if (!item) return; + item->setText(proto_col_, text); +} + +void DecodeAsDialog::curProtoDestroyed() +{ + cur_proto_combo_box_ = NULL; +} + +void DecodeAsDialog::on_buttonBox_accepted() +{ + FILE *da_file = decode_as_open(); + if (!da_file) return; + + for (int i = 0; i < ui->decodeAsTreeWidget->topLevelItemCount(); i++) { + QTreeWidgetItem *item = ui->decodeAsTreeWidget->topLevelItem(i); + + decode_as_write_entry(da_file, + ui_name_to_name_[item->text(table_col_)], + item->text(selector_col_).toUtf8().constData(), + item->text(default_col_).toUtf8().constData(), + item->text(proto_col_).toUtf8().constData()); + } + fclose(da_file); +} + +void DecodeAsDialog::on_buttonBox_helpRequested() +{ + wsApp->helpTopicAction(HELP_DECODE_AS_SHOW_DIALOG); } /* diff --git a/ui/qt/decode_as_dialog.h b/ui/qt/decode_as_dialog.h index c51c78625a..f7157e8d97 100644 --- a/ui/qt/decode_as_dialog.h +++ b/ui/qt/decode_as_dialog.h @@ -30,7 +30,10 @@ #include "cfile.h" +#include #include +#include +#include namespace Ui { class DecodeAsDialog; @@ -51,13 +54,38 @@ private: Ui::DecodeAsDialog *ui; capture_file *cap_file_; + QComboBox *table_names_combo_box_; + QComboBox *selector_combo_box_; + QComboBox *cur_proto_combo_box_; + QMap ui_name_to_name_; + QString entryString(const gchar *table_name, gpointer value); static void buildChangedList(const gchar *table_name, ftenum_t selector_type, gpointer key, gpointer value, gpointer user_data); static void buildDceRpcChangedList(gpointer data, gpointer user_data); + static void decodeAddProtocol(const gchar *table_name, const gchar *proto_name, gpointer value, gpointer user_data); + void addRecord(bool copy_from_current = false); + void fillTypeColumn(QTreeWidgetItem *item); private slots: void fillTable(); + void activateLastItem(); + + void on_decodeAsTreeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + void on_decodeAsTreeWidget_itemActivated(QTreeWidgetItem *item, int column = 0); + void on_decodeAsTreeWidget_itemSelectionChanged(); + void on_newToolButton_clicked(); + void on_deleteToolButton_clicked(); + void on_copyToolButton_clicked(); + + void tableNamesDestroyed(); + void tableNamesCurrentIndexChanged(const QString & text); + void selectorDestroyed(); + void selectorEditTextChanged(const QString & text); + void curProtoCurrentIndexChanged(const QString & text); + void curProtoDestroyed(); + void on_buttonBox_accepted(); + void on_buttonBox_helpRequested(); }; #endif // DECODE_AS_DIALOG_H diff --git a/ui/qt/decode_as_dialog.ui b/ui/qt/decode_as_dialog.ui index ad6eee0617..d089933c16 100644 --- a/ui/qt/decode_as_dialog.ui +++ b/ui/qt/decode_as_dialog.ui @@ -7,34 +7,57 @@ 0 0 750 - 600 + 460 Wireshark: Decode As - + + + 0 + + + true + Field + + Match using this field + Value + + Current "Decode As" behavior + + + + + Type + Default + + Default "Decode As" behavior + Current + + Change behavior when the protocol field matches this value + @@ -43,13 +66,13 @@ - Create a new profile using default settings. + Change the dissection behavior for a protocol. - + :/stock/plus-8.png:/stock/plus-8.png @@ -57,10 +80,10 @@ - Remove this profile. + Remove this dissection behavior. - + :/stock/minus-8.png:/stock/minus-8.png @@ -68,13 +91,13 @@ - Copy this profile. + Copy this dissection behavior. - + :/stock/copy-8.png:/stock/copy-8.png @@ -132,7 +155,9 @@
elided_label.h
- + + + buttonBox diff --git a/ui/qt/preferences_dialog.ui b/ui/qt/preferences_dialog.ui index cc9b0c7d92..750cd8d59d 100644 --- a/ui/qt/preferences_dialog.ui +++ b/ui/qt/preferences_dialog.ui @@ -81,7 +81,7 @@ - 0 + 6 @@ -120,6 +120,9 @@
+ + 0 + true diff --git a/ui/qt/stats_tree_dialog.cpp b/ui/qt/stats_tree_dialog.cpp index 0bb6691952..76c2fd8acf 100644 --- a/ui/qt/stats_tree_dialog.cpp +++ b/ui/qt/stats_tree_dialog.cpp @@ -44,6 +44,7 @@ // To do: // - Add help +// - Update to match bug 9452 / r53657 #include diff --git a/ui/qt/wireshark_application.cpp b/ui/qt/wireshark_application.cpp index 1e63bf6b5a..f867459e2d 100644 --- a/ui/qt/wireshark_application.cpp +++ b/ui/qt/wireshark_application.cpp @@ -25,11 +25,11 @@ #include "wsutil/filesystem.h" -#include "epan/decode_as.h" #include "epan/disabled_protos.h" #include "epan/tap.h" #include "epan/timestamp.h" +#include "ui/decode_as_utils.h" #include "ui/preference_utils.h" #include "ui/recent.h" #include "ui/simple_dialog.h" -- 2.34.1