forked from osmocom/wireshark
Plugin Interface: Add GUI callbacks
Rename ext_menubar to a more appropriate plugin_if. External menus can be implemented by plugins to present additional menus for deep-packet analysis. One side-effect of such menus being implemented as plugins is, that they are being executed in different threads and therefore can only use limited access to the main GUI. Also, there is no safe cross-gui (GTK and Qt) way for many features. This patch implements a first functionality, by which a plugin implemented using ext_menubar can apply a display filter to the main view. For now the implementation supports filtering, as well as saving a preference. Change-Id: Iffe4caa954bbeb8ce356352de4dae348a50efba9 Reviewed-on: https://code.wireshark.org/review/8773 Reviewed-by: Roland Knall <rknall@gmail.com> Petri-Dish: Anders Broman <a.broman58@gmail.com> Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
parent
d4aa1a1c24
commit
acc581081e
|
@ -321,12 +321,14 @@ is encouraged to update their plugins as outlined below:
|
|||
the DOCSIS plugin.
|
||||
|
||||
|
||||
6 How to implement a plugin related menu
|
||||
6 How to plugin related interface options
|
||||
|
||||
6.1 Implement a plugin GUI menu
|
||||
|
||||
A plugin (as well as built-in dissectors) may implement a menu within
|
||||
Wireshark to be used to trigger options, start tools, open Websites, ...
|
||||
|
||||
This menu structure is built using the ext_menubar.h interface and it's
|
||||
This menu structure is built using the plugin_if.h interface and it's
|
||||
corresponding functions.
|
||||
|
||||
The menu items all call a callback provided by the plugin, which takes
|
||||
|
@ -365,7 +367,25 @@ Using the Gtk Version and a Mac OSX operating system, this will not work, and
|
|||
the Gtk interface is currently not supported on this plattform. The Qt interface
|
||||
on Mac provides the menu.
|
||||
|
||||
For a more detailed information, please refer to ext_menubar.h
|
||||
For a more detailed information, please refer to plugin_if.h
|
||||
|
||||
6.2 Implement interactions with the main interface
|
||||
|
||||
Due to memory constraints on most plattforms, plugin functionality cannot be
|
||||
called directly from a DLL context. Instead special functions will be used, which
|
||||
will implement certain options for plugins to utilize.
|
||||
|
||||
The following methods exist so far:
|
||||
|
||||
/* Applies the given filter string as display filter */
|
||||
WS_DLL_PUBLIC void plugin_if_apply_filter
|
||||
(const char * filter_string, gboolean force);
|
||||
|
||||
/* Saves the given preference to the main preference storage */
|
||||
WS_DLL_PUBLIC void plugin_if_save_preference
|
||||
(const char * pref_module, const char * pref_key, const char * pref_value);
|
||||
|
||||
|
||||
|
||||
----------------
|
||||
|
||||
|
|
|
@ -1600,7 +1600,7 @@ set(LIBWIRESHARK_FILES
|
|||
except.c
|
||||
expert.c
|
||||
exported_pdu.c
|
||||
ext_menubar.c
|
||||
plugin_if.c
|
||||
filter_expressions.c
|
||||
follow.c
|
||||
frame_data.c
|
||||
|
|
|
@ -51,7 +51,7 @@ LIBWIRESHARK_SRC = \
|
|||
except.c \
|
||||
expert.c \
|
||||
exported_pdu.c \
|
||||
ext_menubar.c \
|
||||
plugin_if.c \
|
||||
filter_expressions.c \
|
||||
follow.c \
|
||||
frame_data.c \
|
||||
|
@ -192,7 +192,7 @@ LIBWIRESHARK_INCLUDES = \
|
|||
exceptions.h \
|
||||
expert.h \
|
||||
exported_pdu.h \
|
||||
ext_menubar.h \
|
||||
plugin_if.h \
|
||||
filter_expressions.h \
|
||||
follow.h \
|
||||
frame_data.h \
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
/* ext_menubar.c
|
||||
* A menubar API for Wireshark dissectors
|
||||
/* plugin_if.c
|
||||
* An API for Wireshark plugins
|
||||
*
|
||||
* This enables wireshark dissectors, especially those implemented by plugins
|
||||
* to register menubar entries, which then will call a pre-defined callback
|
||||
* function for the dissector or plugin
|
||||
* function for the dissector or plugin.
|
||||
*
|
||||
* Also it implements additional methods, which allow plugins to interoperate
|
||||
* with the main GUI.
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
|
@ -30,7 +33,7 @@
|
|||
#include <epan/epan.h>
|
||||
#include <epan/proto.h>
|
||||
|
||||
#include "ext_menubar.h"
|
||||
#include "plugin_if.h"
|
||||
|
||||
static GList * menubar_entries = NULL;
|
||||
static GList * menubar_menunames = NULL;
|
||||
|
@ -158,6 +161,84 @@ extern void ext_menubar_add_separator(ext_menu_t *parent)
|
|||
ext_menubar_add_generic_entry ( EXT_MENUBAR_SEPARATOR, parent, g_strdup("-"), NULL, NULL, NULL );
|
||||
}
|
||||
|
||||
/* Implementation of GUI callback methods follows.
|
||||
* This is a necessity, as using modern UI systems, gui interfaces often operate
|
||||
* in different threads then the calling application. Even more so, if the calling
|
||||
* application is implemented using a separate plugin. Therefore the external menubars
|
||||
* cannot call gui functionality directly, the gui has to perform the function within
|
||||
* it' own scope. */
|
||||
|
||||
static GHashTable * plugin_if_callback_functions;
|
||||
|
||||
static void
|
||||
plugin_if_init_hashtable(void)
|
||||
{
|
||||
if ( plugin_if_callback_functions == 0 )
|
||||
plugin_if_callback_functions = g_hash_table_new(g_int_hash, g_int_equal);
|
||||
}
|
||||
|
||||
static void plugin_if_call_gui_cb(plugin_if_callback_t actionType, GHashTable * dataSet)
|
||||
{
|
||||
plugin_if_gui_cb action;
|
||||
gint * key = 0;
|
||||
|
||||
key = (gint *)g_malloc0(sizeof(gint));
|
||||
*key = (gint) actionType;
|
||||
|
||||
plugin_if_init_hashtable();
|
||||
|
||||
if ( g_hash_table_size(plugin_if_callback_functions) != 0 )
|
||||
{
|
||||
if ( g_hash_table_contains(plugin_if_callback_functions, key) )
|
||||
{
|
||||
action = (plugin_if_gui_cb)g_hash_table_lookup(plugin_if_callback_functions, key);
|
||||
if ( action != NULL )
|
||||
action(dataSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void plugin_if_apply_filter(const char * filter_string, gboolean force)
|
||||
{
|
||||
plugin_if_callback_t actionType;
|
||||
GHashTable * dataSet = NULL;
|
||||
|
||||
actionType = ( force == TRUE ) ? PLUGIN_IF_FILTER_ACTION_APPLY : PLUGIN_IF_FILTER_ACTION_PREPARE;
|
||||
dataSet = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
g_hash_table_insert( dataSet, g_strdup("action_type"), (gpointer) &actionType );
|
||||
g_hash_table_insert( dataSet, g_strdup("filter_string"), g_strdup(filter_string) );
|
||||
g_hash_table_insert( dataSet, g_strdup("force"), (gpointer) &force );
|
||||
|
||||
plugin_if_call_gui_cb(actionType, dataSet);
|
||||
}
|
||||
|
||||
extern void plugin_if_save_preference(const char * pref_module, const char * pref_key, const char * pref_value)
|
||||
{
|
||||
GHashTable * dataSet = NULL;
|
||||
|
||||
dataSet = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
|
||||
g_hash_table_insert( dataSet, g_strdup("pref_module"), g_strdup(pref_module) );
|
||||
g_hash_table_insert( dataSet, g_strdup("pref_key"), g_strdup(pref_key) );
|
||||
g_hash_table_insert( dataSet, g_strdup("pref_value"), g_strdup(pref_value) );
|
||||
|
||||
plugin_if_call_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, dataSet);
|
||||
}
|
||||
|
||||
extern void plugin_if_register_gui_cb(plugin_if_callback_t actionType, plugin_if_gui_cb callback)
|
||||
{
|
||||
gint * key = 0;
|
||||
|
||||
key = (gint *)g_malloc0(sizeof(gint));
|
||||
*key = actionType;
|
||||
|
||||
plugin_if_init_hashtable();
|
||||
|
||||
if ( ! g_hash_table_contains(plugin_if_callback_functions, key ) )
|
||||
g_hash_table_insert(plugin_if_callback_functions, key, callback);
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
|
@ -1,9 +1,12 @@
|
|||
/* ext_menubar.h
|
||||
* A menubar API for Wireshark dissectors
|
||||
/* plugin_if.h
|
||||
* An API for Wireshark plugins
|
||||
*
|
||||
* This enables wireshark dissectors, especially those implemented by plugins
|
||||
* to register menubar entries, which then will call a pre-defined callback
|
||||
* function for the dissector or plugin
|
||||
* function for the dissector or plugin.
|
||||
*
|
||||
* Also it implements additional methods, which allow plugins to interoperate
|
||||
* with the main GUI.
|
||||
*
|
||||
* Wireshark - Network traffic analyzer
|
||||
* By Gerald Combs <gerald@wireshark.org>
|
||||
|
@ -23,8 +26,8 @@
|
|||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#ifndef EPAN_EXT_MENUBAR_H_
|
||||
#define EPAN_EXT_MENUBAR_H_
|
||||
#ifndef EPAN_PLUGIN_IF_H
|
||||
#define EPAN_PLUGIN_IF_H
|
||||
|
||||
#include <config.h>
|
||||
|
||||
|
@ -146,6 +149,33 @@ WS_DLL_PUBLIC void ext_menubar_add_separator(ext_menu_t *parent_menu);
|
|||
WS_DLL_PUBLIC void ext_menubar_add_website(ext_menu_t * parent, const gchar *label,
|
||||
const gchar *tooltip, const gchar *url);
|
||||
|
||||
|
||||
/*
|
||||
* Enumeration of possible actions, which are registered in GUI interfaces
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
/* Applies a given string as filter */
|
||||
PLUGIN_IF_FILTER_ACTION_APPLY,
|
||||
|
||||
/* Prepares the given string as filter */
|
||||
PLUGIN_IF_FILTER_ACTION_PREPARE,
|
||||
|
||||
/* Saves a preference entry */
|
||||
PLUGIN_IF_PREFERENCE_SAVE
|
||||
} plugin_if_callback_t;
|
||||
|
||||
|
||||
typedef void (*plugin_if_gui_cb)(gconstpointer user_data);
|
||||
|
||||
WS_DLL_PUBLIC void plugin_if_register_gui_cb(plugin_if_callback_t actionType, plugin_if_gui_cb callback);
|
||||
|
||||
/* Applies the given filter string as display filter */
|
||||
WS_DLL_PUBLIC void plugin_if_apply_filter(const char * filter_string, gboolean force);
|
||||
|
||||
/* Saves the given preference to the main preference storage */
|
||||
WS_DLL_PUBLIC void plugin_if_save_preference(const char * pref_module, const char * pref_key, const char * pref_value);
|
||||
|
||||
/* Private Method for retrieving the menubar entries
|
||||
*
|
||||
* Is only to be used by the UI interfaces to retrieve the menu entries
|
||||
|
@ -156,7 +186,7 @@ WS_DLL_PUBLIC GList * ext_menubar_get_entries(void);
|
|||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* EPAN_EXT_MENUBAR_H_ */
|
||||
#endif /* EPAN_PLUGIN_IF_H */
|
||||
|
||||
/*
|
||||
* Editor modelines
|
|
@ -39,6 +39,7 @@
|
|||
#include "filter_autocomplete.h"
|
||||
|
||||
#include "epan/prefs.h"
|
||||
#include "epan/plugin_if.h"
|
||||
|
||||
#include "keys.h"
|
||||
#include "gtkglobals.h"
|
||||
|
@ -109,6 +110,26 @@ filter_save_cb(GtkWidget *w _U_, GtkWindow *parent_w)
|
|||
filter_expression_save_dlg(parent_w);
|
||||
}
|
||||
|
||||
static void
|
||||
plugin_if_filter_apply(gconstpointer filter_text)
|
||||
{
|
||||
/* code is derived from voip_calls_dlg.c::voip_calls_on_filter */
|
||||
|
||||
int pos = 0;
|
||||
size_t filter_length;
|
||||
size_t max_filter_length = 2048;
|
||||
gchar *filter_string;
|
||||
|
||||
if ( main_display_filter_widget != 0 )
|
||||
{
|
||||
filter_string = g_strndup((const char *)filter_text, max_filter_length);
|
||||
filter_length = strlen(filter_string);
|
||||
pos = (int)filter_length;
|
||||
|
||||
if ( filter_length < max_filter_length )
|
||||
gtk_editable_insert_text(GTK_EDITABLE(main_display_filter_widget), filter_string, -1, &pos);
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
filter_toolbar_new(void)
|
||||
|
@ -279,6 +300,9 @@ filter_toolbar_new(void)
|
|||
/* make current preferences effective */
|
||||
toolbar_redraw_all();
|
||||
|
||||
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_APPLY, plugin_if_filter_apply );
|
||||
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_PREPARE, plugin_if_filter_apply );
|
||||
|
||||
return filter_tb;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include <epan/epan_dissect.h>
|
||||
#include <epan/column.h>
|
||||
#include <epan/stats_tree_priv.h>
|
||||
#include <epan/ext_menubar.h>
|
||||
#include <epan/plugin_if.h>
|
||||
|
||||
#include "globals.h"
|
||||
#include "color_filters.h"
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <epan/packet.h>
|
||||
#include <epan/column.h>
|
||||
#include <epan/strutil.h>
|
||||
#include <epan/plugin_if.h>
|
||||
|
||||
#include "ui/main_statusbar.h"
|
||||
#include "ui/packet_list_utils.h"
|
||||
|
@ -91,6 +92,7 @@ static void show_cell_data_func(GtkTreeViewColumn *col,
|
|||
static gint row_number_from_iter(GtkTreeIter *iter);
|
||||
static void scroll_to_current(void);
|
||||
static gboolean query_packet_list_tooltip_cb(GtkWidget *widget, gint x, gint y, gboolean keyboard_tip, GtkTooltip *tooltip, gpointer data _U_);
|
||||
static void plugin_if_pktlist_preference(gconstpointer user_data);
|
||||
|
||||
GtkWidget *
|
||||
packet_list_create(void)
|
||||
|
@ -105,6 +107,8 @@ packet_list_create(void)
|
|||
|
||||
g_object_set_data(G_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, view);
|
||||
|
||||
plugin_if_register_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, plugin_if_pktlist_preference);
|
||||
|
||||
return scrollwin;
|
||||
}
|
||||
|
||||
|
@ -1730,6 +1734,26 @@ query_packet_list_tooltip_cb(GtkWidget *widget, gint x, gint y, gboolean keyboar
|
|||
return result;
|
||||
}
|
||||
|
||||
void plugin_if_pktlist_preference(gconstpointer user_data)
|
||||
{
|
||||
if ( packetlist != NULL && user_data != NULL )
|
||||
{
|
||||
GHashTable * dataSet = (GHashTable *) user_data;
|
||||
if ( g_hash_table_contains(dataSet, "pref_module" ) &&
|
||||
g_hash_table_contains(dataSet, "pref_value" ) &&
|
||||
g_hash_table_contains(dataSet, "pref_value" ) )
|
||||
{
|
||||
const char * module_name = (const char *)g_hash_table_lookup(dataSet, "pref_module");
|
||||
const char * pref_name = (const char *)g_hash_table_lookup(dataSet, "pref_key");
|
||||
const char * pref_value = (const char *)g_hash_table_lookup(dataSet, "pref_value");
|
||||
|
||||
if ( prefs_store_ext(module_name, pref_name, pref_value) )
|
||||
packet_list_recreate();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Editor modelines - http://www.wireshark.org/tools/modelines.html
|
||||
*
|
||||
|
|
|
@ -273,6 +273,48 @@ prefs_main_write(void)
|
|||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
prefs_store_ext(const char * module_name, const char *pref_name, const char *pref_value)
|
||||
{
|
||||
module_t * module = NULL;
|
||||
pref_t * pref = NULL;
|
||||
gboolean pref_changed = TRUE;
|
||||
|
||||
if ( ! prefs_is_registered_protocol(module_name))
|
||||
return FALSE;
|
||||
|
||||
module = prefs_find_module(module_name);
|
||||
if ( ! module )
|
||||
return FALSE;
|
||||
|
||||
pref = prefs_find_preference(module, pref_name);
|
||||
|
||||
if (!pref)
|
||||
return FALSE;
|
||||
|
||||
if ( pref->type == PREF_STRING )
|
||||
{
|
||||
g_free((void *)pref->stashed_val.string);
|
||||
pref->stashed_val.string = (gchar *) g_strdup(pref_value);
|
||||
/* unstash - taken from preferences_util */
|
||||
if (strcmp(*pref->varp.string, pref->stashed_val.string) != 0)
|
||||
{
|
||||
pref_changed = TRUE;
|
||||
g_free((void *)*pref->varp.string);
|
||||
*pref->varp.string = g_strdup(pref->stashed_val.string);
|
||||
}
|
||||
}
|
||||
|
||||
if ( pref_changed )
|
||||
{
|
||||
prefs_main_write();
|
||||
prefs_apply_all();
|
||||
prefs_to_capture_opts();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gint
|
||||
column_prefs_add_custom(gint fmt, const gchar *title, const gchar *custom_field, gint custom_occurrence)
|
||||
{
|
||||
|
|
|
@ -80,6 +80,16 @@ extern void prefs_to_capture_opts(void);
|
|||
*/
|
||||
extern void prefs_main_write(void);
|
||||
|
||||
/** Convenient function for plugin_if
|
||||
*
|
||||
* @param module the module for the preference
|
||||
* @param key the key for the preference
|
||||
* @param value the new value as string for the preference
|
||||
*
|
||||
* @return true if the value has been stored successfully
|
||||
*/
|
||||
extern gboolean prefs_store_ext(const char * module, const char * key, const char * value);
|
||||
|
||||
/** Add a custom column.
|
||||
*
|
||||
* @param fmt column format
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include <wsutil/filesystem.h>
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/stats_tree_priv.h>
|
||||
#include <epan/ext_menubar.h>
|
||||
#include <epan/plugin_if.h>
|
||||
|
||||
#ifdef HAVE_LIBPCAP
|
||||
#include "ui/capture.h"
|
||||
|
@ -42,6 +42,7 @@
|
|||
#include "ui/main_statusbar.h"
|
||||
#include "ui/recent.h"
|
||||
#include "ui/util.h"
|
||||
#include "ui/preference_utils.h"
|
||||
|
||||
#include "byte_view_tab.h"
|
||||
#include "display_filter_edit.h"
|
||||
|
@ -83,6 +84,42 @@ void pipe_input_set_handler(gint source, gpointer user_data, ws_process_id *chil
|
|||
gbl_cur_main_window_->setPipeInputHandler(source, user_data, child_process, input_cb);
|
||||
}
|
||||
|
||||
void plugin_if_mainwindow_apply_filter(gconstpointer user_data)
|
||||
{
|
||||
if ( gbl_cur_main_window_ != NULL && user_data != NULL )
|
||||
{
|
||||
GHashTable * dataSet = (GHashTable *) user_data;
|
||||
|
||||
if ( g_hash_table_contains(dataSet, "filter_string" ) )
|
||||
{
|
||||
QString filter((const char *)g_hash_table_lookup(dataSet, "filter_string"));
|
||||
gbl_cur_main_window_->filterPackets(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plugin_if_mainwindow_preference(gconstpointer user_data)
|
||||
{
|
||||
if ( gbl_cur_main_window_ != NULL && user_data != NULL )
|
||||
{
|
||||
GHashTable * dataSet = (GHashTable *) user_data;
|
||||
if ( g_hash_table_contains(dataSet, "pref_module" ) &&
|
||||
g_hash_table_contains(dataSet, "pref_value" ) &&
|
||||
g_hash_table_contains(dataSet, "pref_value" ) )
|
||||
{
|
||||
const char * module_name = (const char *)g_hash_table_lookup(dataSet, "pref_module");
|
||||
const char * pref_name = (const char *)g_hash_table_lookup(dataSet, "pref_key");
|
||||
const char * pref_value = (const char *)g_hash_table_lookup(dataSet, "pref_value");
|
||||
|
||||
if ( prefs_store_ext(module_name, pref_name, pref_value) )
|
||||
{
|
||||
wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
|
||||
wsApp->emitAppSignal(WiresharkApplication::PreferencesChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gpointer
|
||||
simple_dialog(ESD_TYPE_E type, gint btn_mask, const gchar *msg_format, ...)
|
||||
{
|
||||
|
@ -479,6 +516,11 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||
this->main_welcome_->getInterfaceTree(), SLOT(interfaceListChanged()));
|
||||
#endif
|
||||
|
||||
/* Create plugin_if hooks */
|
||||
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_APPLY, plugin_if_mainwindow_apply_filter );
|
||||
plugin_if_register_gui_cb(PLUGIN_IF_FILTER_ACTION_PREPARE, plugin_if_mainwindow_apply_filter );
|
||||
plugin_if_register_gui_cb(PLUGIN_IF_PREFERENCE_SAVE, plugin_if_mainwindow_preference);
|
||||
|
||||
main_ui_->mainStack->setCurrentWidget(main_welcome_);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "ui/ui_util.h"
|
||||
|
||||
#include <epan/prefs.h>
|
||||
#include <epan/ext_menubar.h>
|
||||
#include <epan/plugin_if.h>
|
||||
|
||||
#ifdef HAVE_LIBPCAP
|
||||
#include "capture_opts.h"
|
||||
|
|
Loading…
Reference in New Issue