forked from osmocom/wireshark
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). svn path=/trunk/; revision=53910
This commit is contained in:
parent
5fa7d37e37
commit
17a67c3b5c
210
epan/decode_as.c
210
epan/decode_as.c
|
@ -24,28 +24,14 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#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
|
||||
*
|
||||
|
|
|
@ -94,44 +94,11 @@ 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!!! ***/
|
||||
|
||||
/** List of registered decode_as_t structs.
|
||||
* For UI code only. Should not be directly accessed by 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.
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include <wsutil/filesystem.h>
|
||||
#include <epan/address.h>
|
||||
#include <epan/addr_resolv.h>
|
||||
#include <epan/decode_as.h>
|
||||
#include <epan/oids.h>
|
||||
#ifdef HAVE_GEOIP
|
||||
#include <epan/geoip_db.h>
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
/* decode_as_utils.c
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Routines to modify dissector tables on the fly.
|
||||
*
|
||||
* By David Hampton <dhampton@mac.com>
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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:
|
||||
*/
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/* decode_as_utils.h
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* "Decode As" UI utility routines.
|
||||
*
|
||||
* By David Hampton <dhampton@mac.com>
|
||||
* 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__ */
|
|
@ -22,7 +22,6 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
|
@ -32,11 +31,10 @@
|
|||
|
||||
#include <epan/packet.h>
|
||||
#include <epan/epan_dissect.h>
|
||||
#include <wsutil/filesystem.h>
|
||||
#include <epan/decode_as.h>
|
||||
#include <epan/dissectors/packet-dcerpc.h>
|
||||
#include <wsutil/file_util.h>
|
||||
|
||||
#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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <QTreeWidgetItem>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
#include <QLineEdit>
|
||||
|
||||
#include <QDebug>
|
||||
// To do:
|
||||
// - Ranges
|
||||
// - Add DCERPC support (or make DCERPC use a regular dissector table?)
|
||||
// - Fix string (BER) selectors
|
||||
|
||||
const int field_col_ = 0;
|
||||
const int value_col_ = 1;
|
||||
const int default_col_ = 2;
|
||||
const int current_col_ = 3;
|
||||
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 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<QString> 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<QString> 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<QString> *proto_set = (QSet<QString> *)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<QString> 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<QString> 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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -30,7 +30,10 @@
|
|||
|
||||
#include "cfile.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QMap>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
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<QString, const char *> 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
|
||||
|
|
|
@ -7,34 +7,57 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>750</width>
|
||||
<height>600</height>
|
||||
<height>460</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Wireshark: Decode As</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="decodeAsTreeWidget">
|
||||
<property name="indentation">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Field</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Match using this field</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Current "Decode As" behavior</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Type</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Default</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Default "Decode As" behavior</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Current</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change behavior when the protocol field matches this value</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -43,13 +66,13 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="newToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Create a new profile using default settings.</string>
|
||||
<string>Change the dissection behavior for a protocol.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../../image/toolbar.qrc">
|
||||
<normaloff>:/stock/plus-8.png</normaloff>:/stock/plus-8.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -57,10 +80,10 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="deleteToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Remove this profile.</string>
|
||||
<string>Remove this dissection behavior.</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../../image/toolbar.qrc">
|
||||
<normaloff>:/stock/minus-8.png</normaloff>:/stock/minus-8.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -68,13 +91,13 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="copyToolButton">
|
||||
<property name="toolTip">
|
||||
<string>Copy this profile.</string>
|
||||
<string>Copy this dissection behavior.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<iconset resource="../../image/toolbar.qrc">
|
||||
<normaloff>:/stock/copy-8.png</normaloff>:/stock/copy-8.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -132,7 +155,9 @@
|
|||
<header>elided_label.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="../../image/toolbar.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>6</number>
|
||||
</property>
|
||||
<widget class="MainWindowPreferencesFrame" name="appearanceFrame"/>
|
||||
<widget class="LayoutPreferencesFrame" name="layoutFrame"/>
|
||||
|
@ -120,6 +120,9 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="advancedTree">
|
||||
<property name="indentation">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
|
||||
// To do:
|
||||
// - Add help
|
||||
// - Update to match bug 9452 / r53657
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue