Get the "Decode As" dialog working, albeit with a few warts. It differs
authorgerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 10 Dec 2013 19:23:26 +0000 (19:23 +0000)
committergerald <gerald@f5534014-38df-0310-8fa8-9805f1628bb7>
Tue, 10 Dec 2013 19:23:26 +0000 (19:23 +0000)
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

19 files changed:
epan/decode_as.c
epan/decode_as.h
epan/dissectors/packet-ber.c
epan/dissectors/packet-dcerpc.c
epan/packet.c
epan/packet.h
epan/prefs.c
ui/CMakeLists.txt
ui/Makefile.common
ui/decode_as_utils.c [new file with mode: 0644]
ui/decode_as_utils.h [new file with mode: 0644]
ui/gtk/decode_as_dlg.c
ui/gtk/main.c
ui/qt/decode_as_dialog.cpp
ui/qt/decode_as_dialog.h
ui/qt/decode_as_dialog.ui
ui/qt/preferences_dialog.ui
ui/qt/stats_tree_dialog.cpp
ui/qt/wireshark_application.cpp

index 9f8791e765de9284de50593a93dbc46e19d226f7..287ffb229ccdb0a276a24b974ba95d1dd05f04a4 100644 (file)
 
 #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
  *
index c28d7d60fdd02b7f7b8583cdfb93c6006dcc43b3..248cdf23bf918820598888b0618e3c357cb57b19 100644 (file)
@@ -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
 }
index ffdc7aad39dede12d46afcf9cf4396bbeb55222b..f8dad6112630095a9cc0a1d6ea03484860cd3294 100644 (file)
@@ -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);
index 86e9b9748a960575cd6ac3dedddb8586c8371f46..6fd3bcdaaa4e433848ca1986a0b4f76b34739eaf 100644 (file)
@@ -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};
 
index 9befce39d1790f7e7e1f2705fa6a9618d98e3cdd..2a1da2a74a6e804a300bd538442836796224b623 100644 (file)
@@ -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;
 }
index 205df7ff3b9a13a42f5198233d8b0621e062c8d0..2b850c37823fc6c1e0993eae078634d46554f951 100644 (file)
@@ -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);
index b3e210df43ad576967dee4c159dc35562fd6359c..cb4daa3bdc4db9daa986481fb9262c3d117a6117 100644 (file)
@@ -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);
 
index 7ddd0e50a280352901c5d2df13f421874d378bb8..b7b768d922411e5cad55f4230e09cc14dc280786 100644 (file)
@@ -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
index 6845b5519f734233072b8f821e2f996dd7e6252c..7cb273164b6f06a79286503c661ae5028348e90b 100644 (file)
@@ -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 (file)
index 0000000..d78c5d8
--- /dev/null
@@ -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:
+ */
+
diff --git a/ui/decode_as_utils.h b/ui/decode_as_utils.h
new file mode 100644 (file)
index 0000000..de050c7
--- /dev/null
@@ -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__ */
index bb676f209d49e04e172ce3c74476d9e8f984a037..9b4ae16c21d021f018f0b88d3014f65fd44267d7 100644 (file)
@@ -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>
 
 #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);
index ba605c8e062316c80cdb9185d04f974821f3a303..774d321dd5d3816a40c92949781288982a0e9c4a 100644 (file)
 #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);
index 284d070ec01a8a799e7abc1a024967109de0fa13..8d36d13dedf10f4bb5cd255118d6c37ed4f3c76a 100644 (file)
 
 #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>
+
+// To do:
+// - Ranges
+// - Add DCERPC support (or make DCERPC use a regular dissector table?)
+// - Fix string (BER) selectors
 
-#include <QDebug>
+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<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);
 }
 
 /*
index c51c78625a4b5ec20b47a603f5da2f70c9c23250..f7157e8d971d225b66774e7e5e27758a9631642a 100644 (file)
 
 #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
index ad6eee0617ea8d8b6a8e5b2e355b086cdaa7c7f7..d089933c16e45876822caa49b155b6f2628e6c59 100644 (file)
@@ -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 &quot;Decode As&quot; 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 &quot;Decode As&quot; 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>
      <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>
      <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>
      <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>
    <header>elided_label.h</header>
   </customwidget>
  </customwidgets>
- <resources/>
+ <resources>
+  <include location="../../image/toolbar.qrc"/>
+ </resources>
  <connections>
   <connection>
    <sender>buttonBox</sender>
index cc9b0c7d92e1af416b80e7ce0a5a3a1b56237f03..750cd8d59d4cfbfc26a9cf835cb8d52e2da75ceb 100644 (file)
@@ -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"/>
         </item>
         <item>
          <widget class="QTreeWidget" name="advancedTree">
+          <property name="indentation">
+           <number>0</number>
+          </property>
           <property name="uniformRowHeights">
            <bool>true</bool>
           </property>
index 0bb669195201fdf39c24cdf2d8f90db37cde9272..76c2fd8acfe8b8b86e860c464057fc865e317932 100644 (file)
@@ -44,6 +44,7 @@
 
 // To do:
 // - Add help
+// - Update to match bug 9452 / r53657
 
 #include <QDebug>
 
index 1e63bf6b5a08ab84aa11f35fa81c632fcc14ac95..f867459e2d0bc40e661d5e1026b2a952cae96cb4 100644 (file)
 
 #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"