WSLUA: Add new lua function register_packet_menu()

This adds support to Wireshark for custom context menus for packets, so
that when a packet's context menu is opened (e.g., by right-clicking),
Wireshark can support doing things like "run a program" or
"open a URL" with a field from the packet as a parameter. Note that
this is similar to ArcSight's integration commands feature.

For example, it could be used like the following:

```
ROBTEX_URL = "https://www.robtex.com/dns-lookup/"
local function search_robtex(...)
    local fields = {...};

    for i, field in ipairs( fields ) do
        if (field.name == 'http.host') then
            browser_open_url(ROBTEX_URL .. field.value)
            break
        end
    end
end
register_packet_menu("Search host in Robtex", search_robtex, "http.host");
```

Fixes issue #14998
This commit is contained in:
Moshe Kaplan 2020-12-26 23:15:24 -05:00 committed by AndersBroman
parent eff7cd15b0
commit f413260df9
11 changed files with 609 additions and 30 deletions

View File

@ -34,6 +34,36 @@ static funnel_menu_t* added_menus = NULL;
static funnel_menu_t* removed_menus = NULL;
static gboolean menus_registered = FALSE;
/**
* Represents a single packet menu entry and callback
*/
typedef struct _funnel_packet_menu_t {
char *name; /**< Name to display in the GUI */
char *required_fields; /**< comma-separated list of fields
that must be present for the
packet menu to be displayed */
funnel_packet_menu_callback callback; /**< Lua function to be called on
menu item selection. */
gpointer callback_data; /**< Lua state for the callback
function */
gboolean retap; /**< Whether or not to rescan the
capture file's packets */
struct _funnel_packet_menu_t* next; /**< Pointer to the next
_funnel_packet_menu_t for the
singly-linked list
implemenation */
} funnel_packet_menu_t;
/*
* List of all registered funnel_packet_menu_t's
*/
static funnel_packet_menu_t* registered_packet_menus = NULL;
/*
* TRUE if the packet menus were modified since the last registration
*/
static gboolean packet_menus_modified = FALSE;
static void funnel_clear_packet_menu (funnel_packet_menu_t** menu_list);
const funnel_ops_t* funnel_get_funnel_ops(void) { return ops; }
void funnel_set_funnel_ops(const funnel_ops_t* o) { ops = o; }
@ -120,6 +150,10 @@ void funnel_deregister_menus(funnel_menu_callback callback)
funnel_remove_menu(&registered_menus, m);
funnel_insert_menu(&removed_menus, m);
// Clear and free memory of packet menus
funnel_clear_packet_menu(&registered_packet_menus);
packet_menus_modified = TRUE;
}
void funnel_register_all_menus(funnel_registration_cb_t r_cb)
@ -146,9 +180,103 @@ void funnel_reload_menus(funnel_deregistration_cb_t d_cb,
funnel_clear_menu(&added_menus);
}
/*
* Inserts a funnel_packet_menu_t into a list of funnel_packet_menu_t's
*
* @param menu_list the list of menus that the menu will be added to
* @param menu the menu to add to the list of menus
*/
static void funnel_insert_packet_menu (funnel_packet_menu_t** menu_list, funnel_packet_menu_t *menu)
{
if (!(*menu_list)) {
*menu_list = menu;
} else {
funnel_packet_menu_t* c;
for (c = *menu_list; c->next; c = c->next);
c->next = menu;
}
}
/**
* Entry point for Lua code to register a packet menu
*
* Stores the menu name and callback from the Lua code
* into registered_packet_menus so that the
* Wireshark GUI code can retrieve it with
* funnel_register_all_packet_menus().
*/
void funnel_register_packet_menu(const char *name,
const char *required_fields,
funnel_packet_menu_callback callback,
gpointer callback_data,
gboolean retap)
{
funnel_packet_menu_t* m = g_new0(funnel_packet_menu_t, 1);
m->name = g_strdup(name);
m->required_fields = g_strdup(required_fields);
m->callback = callback;
m->callback_data = callback_data;
m->retap = retap;
m->next = NULL;
funnel_insert_packet_menu(&registered_packet_menus, m);
packet_menus_modified = TRUE;
}
/**
* Clears a list of funnel_packet_menu_t's and free()s all associated memory
*
* @param menu_list the list of menus to clear
*/
static void funnel_clear_packet_menu (funnel_packet_menu_t** menu_list)
{
funnel_packet_menu_t *m;
while (*menu_list) {
m = *menu_list;
*menu_list = m->next;
g_free(m->name);
g_free(m->required_fields);
if (m->callback_data) {
g_free(m->callback_data);
}
g_free(m);
}
*menu_list = NULL;
}
/**
* Entry point for Wireshark GUI to obtain all registered packet menus
*
* Calls the supplied callback for each packet menu registered with
* funnel_register_packet_menu().
*
* @param r_cb the callback function to call with each registered packet menu
*/
void funnel_register_all_packet_menus(funnel_registration_packet_cb_t r_cb)
{
funnel_packet_menu_t* c;
for (c = registered_packet_menus; c; c = c->next) {
r_cb(c->name,c->required_fields,c->callback,c->callback_data,c->retap);
}
packet_menus_modified = FALSE;
}
/**
* Returns whether the packet menus have been modified since they were last registered
*
* @return TRUE if the packet menus were modified since the last registration
*/
gboolean funnel_packet_menus_modified(void)
{
return packet_menus_modified;
}
void funnel_cleanup(void)
{
funnel_clear_menu(&registered_menus);
funnel_clear_packet_menu(&registered_packet_menus);
}
/*

View File

@ -118,6 +118,49 @@ WS_DLL_PUBLIC void funnel_reload_menus(funnel_deregistration_cb_t d_cb,
funnel_registration_cb_t r_cb);
WS_DLL_PUBLIC void funnel_cleanup(void);
/**
* Signature of function that can be called from a custom packet menu entry
*/
typedef void (* funnel_packet_menu_callback)(gpointer, GPtrArray*);
/**
* Signature of callback function to register packet menu entries
*/
typedef void (*funnel_registration_packet_cb_t)(const char *name,
const char *required_fields,
funnel_packet_menu_callback callback,
gpointer callback_data,
gboolean retap);
/**
* Entry point for Wireshark GUI to obtain all registered packet menus
*
* @param r_cb function which will be called to register each packet menu entry
*/
WS_DLL_PUBLIC void funnel_register_all_packet_menus(funnel_registration_packet_cb_t r_cb);
/**
* Entry point for Lua code to register a packet menu
*
* @param name packet menu item's name
* @param required_fields fields required to be present for the packet menu to be displayed
* @param callback function called when the menu item is invoked. The function must take one argument and return nothing.
* @param callback_data Lua state for the callback function
* @param retap whether or not to rescan all packets
*/
WS_DLL_PUBLIC void funnel_register_packet_menu(const char *name,
const char *required_fields,
funnel_packet_menu_callback callback,
gpointer callback_data,
gboolean retap);
/**
* Returns whether the packet menus have been modified since they were last registered
*
* @return TRUE if the packet menus were modified since the last registration
*/
WS_DLL_PUBLIC gboolean funnel_packet_menus_modified(void);
extern void initialize_funnel_ops(void);
extern void funnel_dump_all_text_windows(void);

View File

@ -137,6 +137,93 @@ void wslua_deregister_menus(void) {
funnel_deregister_menus(lua_menu_callback);
}
/**
* Error handler used by lua_custom_packet_menu_callback when calling the user-supplied callback
*
* @param L State of the Lua interpreter
* @return Always returns 0
*/
static int packet_menu_cb_error_handler(lua_State* L) {
const gchar* error = lua_tostring(L,1);
report_failure("Lua: Error During execution of Packet Menu Callback:\n %s",error);
return 0;
}
/**
* Wrapper used to call the user-supplied Lua callback when a custom packet
* context menu is clicked.
*
* @param data Lua menu data
* @param finfo_array packet data
*/
static void lua_custom_packet_menu_callback(gpointer data, GPtrArray *finfo_array) {
// _lua_menu_data is State + the integer index of a callback.
struct _lua_menu_data* md = (struct _lua_menu_data *)data;
lua_State* L = md->L;
lua_settop(L,0);
lua_pushcfunction(L,packet_menu_cb_error_handler);
lua_rawgeti(L, LUA_REGISTRYINDEX, md->cb_ref);
// Push the packet data as arguments to the Lua callback:
int items_found = 0;
for (guint i = finfo_array->len - 1; i > 0 ; i --) {
field_info *fi = (field_info *)g_ptr_array_index (finfo_array, i);
push_FieldInfo(L, fi);
items_found++;
}
switch ( lua_pcall(L,items_found,0,1) ) {
case 0:
break;
case LUA_ERRRUN:
g_warning("Runtime error while calling custom_packet_menu callback");
break;
case LUA_ERRMEM:
g_warning("Memory alloc error while calling custom_packet_menu callback");
break;
default:
g_assert_not_reached();
break;
}
return;
}
/**
* Lua function exposed to users: register_packet_menu
*/
WSLUA_FUNCTION wslua_register_packet_menu(lua_State* L) { /* Register a menu item in the packet list. */
#define WSLUA_ARG_register_packet_menu_NAME 1 /* The name of the menu item. Use slashes to separate submenus. (e.g. level1/level2/name). (string) */
#define WSLUA_ARG_register_packet_menu_ACTION 2 /* The function to be called when the menu item is invoked. The function must take one argument and return nothing. */
#define WSLUA_OPTARG_register_packet_menu_REQUIRED_FIELDS 3 /* A comma-separated list of packet fields (e.g., http.host,dns.qry.name) which all must be present for the menu to be displayed (default: always display)*/
const gchar* name = luaL_checkstring(L,WSLUA_ARG_register_packet_menu_NAME);
const gchar* required_fields = luaL_optstring(L,WSLUA_OPTARG_register_packet_menu_REQUIRED_FIELDS,"");
struct _lua_menu_data* md;
gboolean retap = FALSE;
if (!lua_isfunction(L,WSLUA_ARG_register_packet_menu_ACTION)) {
WSLUA_ARG_ERROR(register_packet_menu,ACTION,"Must be a function");
return 0;
}
md = g_new0(struct _lua_menu_data, 1);
md->L = L;
lua_pushvalue(L, 2);
md->cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
lua_remove(L,2);
funnel_register_packet_menu(name,
required_fields,
lua_custom_packet_menu_callback,
md,
retap);
WSLUA_RETURN(0);
}
struct _dlg_cb_data {
lua_State* L;
int func_ref;

View File

@ -748,8 +748,11 @@ libwireshark.so.0 libwireshark0 #MINVER#
ftype_pretty_name@Base 1.9.1
funnel_cleanup@Base 2.9.1
funnel_get_funnel_ops@Base 1.9.1
funnel_packet_menus_modified@Base 4.1.0
funnel_register_all_menus@Base 1.9.1
funnel_register_all_packet_menus@Base 4.1.0
funnel_register_menu@Base 1.9.1
funnel_register_packet_menu@Base 4.1.0
funnel_reload_menus@Base 1.99.9
funnel_set_funnel_ops@Base 1.9.1
fvalue_from_literal@Base 3.7.0

View File

@ -21,6 +21,7 @@
#include "ui/progress_dlg.h"
#include "ui/simple_dialog.h"
#include <ui/qt/main_window.h>
#include "funnel_statistics.h"
#include "funnel_string_dialog.h"
@ -30,6 +31,7 @@
#include <QClipboard>
#include <QDebug>
#include <QDesktopServices>
#include <QMenu>
#include <QUrl>
#include "main_application.h"
@ -61,48 +63,138 @@ static void progress_window_update(struct progdlg *progress_dialog, float percen
static void progress_window_destroy(struct progdlg *progress_dialog);
}
class FunnelAction : public QAction
{
public:
FunnelAction(QString title, funnel_menu_callback callback, gpointer callback_data, gboolean retap, QObject *parent = nullptr) :
FunnelAction::FunnelAction(QString title, funnel_menu_callback callback, gpointer callback_data, gboolean retap, QObject *parent = nullptr) :
QAction(parent),
title_(title),
callback_(callback),
callback_data_(callback_data),
retap_(retap)
{
// Use "&&" to get a real ampersand in the menu item.
title.replace('&', "&&");
setText(title);
setObjectName(FunnelStatistics::actionName());
packetRequiredFields_ = QSet<QString>();
}
FunnelAction::FunnelAction(QString title, funnel_packet_menu_callback callback, gpointer callback_data, gboolean retap, const char *packet_required_fields, QObject *parent = nullptr) :
QAction(parent),
title_(title),
callback_data_(callback_data),
retap_(retap),
packetCallback_(callback),
packetRequiredFields_(QSet<QString>())
{
// Use "&&" to get a real ampersand in the menu item.
title.replace('&', "&&");
QStringList menuComponents = title.split(QString("/"));
// Set the menu's text to the rightmost component, set the path to being everything to the left:
setText("(empty)");
packetSubmenu_ = "";
if (!menuComponents.isEmpty())
{
// Use "&&" to get a real ampersand in the menu item.
title.replace('&', "&&");
setText(title);
setObjectName(FunnelStatistics::actionName());
setText(menuComponents.last());
menuComponents.removeLast();
packetSubmenu_ = menuComponents.join("/");
}
funnel_menu_callback callback() const {
return callback_;
}
setObjectName(FunnelStatistics::actionName());
setPacketRequiredFields(packet_required_fields);
}
QString title() const {
return title_;
}
FunnelAction::~FunnelAction(){
}
void triggerCallback() {
if (callback_) {
callback_(callback_data_);
funnel_menu_callback FunnelAction::callback() const {
return callback_;
}
QString FunnelAction::title() const {
return title_;
}
void FunnelAction::triggerCallback() {
if (callback_) {
callback_(callback_data_);
}
}
void FunnelAction::setPacketCallback(funnel_packet_menu_callback packet_callback) {
packetCallback_ = packet_callback;
}
void FunnelAction::setPacketRequiredFields(const char *required_fields_str) {
packetRequiredFields_.clear();
// If multiple fields are required to be present, they're split by commas
// Also remove leading and trailing spaces, in case someone writes
// "http, dns" instead of "http,dns"
QString requiredFieldsJoined = QString(required_fields_str);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList requiredFieldsSplit = requiredFieldsJoined.split(",", Qt::SkipEmptyParts);
#else
QStringList requiredFieldsSplit = requiredFieldsJoined.split(",", QString::SkipEmptyParts);
#endif
foreach (QString requiredField, requiredFieldsSplit) {
QString trimmedFieldName = requiredField.trimmed();
if (! trimmedFieldName.isEmpty()) {
packetRequiredFields_.insert(trimmedFieldName);
}
}
}
bool retap() {
if (retap_) return true;
return false;
const QSet<QString> FunnelAction::getPacketRequiredFields() {
return packetRequiredFields_;
}
void FunnelAction::setPacketData(GPtrArray* finfos) {
packetData_ = finfos;
}
void FunnelAction::addToMenu(QMenu * ctx_menu, QHash<QString, QMenu *> menuTextToMenus) {
QString submenusText = this->getPacketSubmenus();
if (submenusText.isEmpty()) {
ctx_menu->addAction(this);
} else {
// If the action has a submenu, ensure that the
// the full submenu chain exists:
QStringList menuComponents = submenusText.split("/");
QString menuSubComponentsStringPrior = NULL;
for (int menuIndex=0; menuIndex < menuComponents.size(); menuIndex++) {
QStringList menuSubComponents = menuComponents.mid(0, menuIndex+1);
QString menuSubComponentsString = menuSubComponents.join("/");
if (!menuTextToMenus.contains(menuSubComponentsString)) {
// Create a new menu object under the prior object
QMenu *previousSubmenu = menuTextToMenus.value(menuSubComponentsStringPrior);
QMenu *submenu = previousSubmenu->addMenu(menuComponents.at(menuIndex));
menuTextToMenus.insert(menuSubComponentsString, submenu);
}
menuSubComponentsStringPrior = menuSubComponentsString;
}
// Then add the action to the relevant submenu
QMenu *parentMenu = menuTextToMenus.value(submenusText);
parentMenu->addAction(this);
}
private:
QString title_;
funnel_menu_callback callback_;
gpointer callback_data_;
gboolean retap_;
};
}
void FunnelAction::triggerPacketCallback() {
if (packetCallback_) {
packetCallback_(callback_data_, packetData_);
}
}
bool FunnelAction::retap() {
if (retap_) return true;
return false;
}
QString FunnelAction::getPacketSubmenus() {
return packetSubmenu_;
}
static QHash<int, QList<FunnelAction *> > funnel_actions_;
const QString FunnelStatistics::action_name_ = "FunnelStatisticsAction";
@ -368,6 +460,33 @@ static void register_menu_cb(const char *name,
funnel_actions_[group] << funnel_action;
}
/*
* Callback used to register packet menus in the GUI.
*
* Creates a new FunnelAction with the Lua
* callback and stores it in the Wireshark GUI with
* appendPacketMenu() so it can be retrieved when
* the packet's context menu is open.
*
* @param name packet menu item's name
* @param required_fields fields required to be present for the packet menu to be displayed
* @param callback function called when the menu item is invoked. The function must take one argument and return nothing.
* @param callback_data Lua state for the callback function
* @param retap whether or not to rescan all packets
*/
static void register_packet_menu_cb(const char *name,
const char *required_fields,
funnel_packet_menu_callback callback,
gpointer callback_data,
gboolean retap)
{
FunnelAction *funnel_action = new FunnelAction(name, callback, callback_data, retap, required_fields, mainApp);
MainWindow * mainwindow = qobject_cast<MainWindow *>(mainApp->mainWindow());
if (mainwindow) {
mainwindow->appendPacketMenu(funnel_action);
}
}
static void deregister_menu_cb(funnel_menu_callback callback)
{
foreach (int group, funnel_actions_.keys()) {
@ -397,6 +516,29 @@ void
funnel_statistics_reload_menus(void)
{
funnel_reload_menus(deregister_menu_cb, register_menu_cb);
funnel_statistics_load_packet_menus();
}
/**
* Returns whether the packet menus have been modified since they were last registered
*
* @return TRUE if the packet menus were modified since the last registration
*/
gboolean
funnel_statistics_packet_menus_modified(void)
{
return funnel_packet_menus_modified();
}
/*
* Loads all registered_packet_menus into the
* Wireshark GUI.
*/
void
funnel_statistics_load_packet_menus(void)
{
funnel_register_all_packet_menus(register_packet_menu_cb);
}
} // extern "C"

View File

@ -11,13 +11,21 @@
#define FUNNELSTATISTICS_H
#include <QObject>
#include <QAction>
#include <QSet>
#include <epan/funnel.h>
#include "capture_file.h"
#include <ui/qt/filter_action.h>
struct _funnel_ops_t;
struct progdlg;
/**
* Signature of function that can be called from a custom packet menu entry
*/
typedef void (* funnel_packet_menu_callback)(gpointer, GPtrArray*);
class FunnelStatistics : public QObject
{
Q_OBJECT
@ -53,8 +61,42 @@ private:
QString prepared_filter_;
};
class FunnelAction : public QAction
{
Q_OBJECT
public:
FunnelAction(QString title, funnel_menu_callback callback, gpointer callback_data, gboolean retap, QObject *parent);
FunnelAction(QString title, funnel_packet_menu_callback callback, gpointer callback_data, gboolean retap, const char *packet_required_fields, QObject *parent);
~FunnelAction();
funnel_menu_callback callback() const;
QString title() const;
void triggerCallback();
void setPacketCallback(funnel_packet_menu_callback packet_callback);
void setPacketData(GPtrArray* finfos);
void addToMenu(QMenu * ctx_menu, QHash<QString, QMenu *> menuTextToMenus);
void setPacketRequiredFields(const char *required_fields_str);
const QSet<QString> getPacketRequiredFields();
bool retap();
QString getPacketSubmenus();
public slots:
void triggerPacketCallback();
private:
QString title_;
QString packetSubmenu_;
funnel_menu_callback callback_;
gpointer callback_data_;
gboolean retap_;
funnel_packet_menu_callback packetCallback_;
GPtrArray* packetData_;
QSet<QString> packetRequiredFields_;
};
extern "C" {
void funnel_statistics_reload_menus(void);
void funnel_statistics_load_packet_menus(void);
gboolean funnel_statistics_packet_menus_modified(void);
} // extern "C"
#endif // FUNNELSTATISTICS_H

View File

@ -15,9 +15,13 @@
#include "main_window.h"
#include "funnel_statistics.h"
#include "packet_list.h"
#include "widgets/display_filter_combo.h"
// Packet Menu actions
static QList<QAction *> dynamic_packet_menu_actions;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
main_stack_(nullptr),
@ -33,6 +37,11 @@ MainWindow::MainWindow(QWidget *parent) :
}
MainWindow::~MainWindow()
{
clearAddedPacketMenus();
}
bool MainWindow::hasSelection()
{
if (packet_list_)
@ -89,4 +98,96 @@ void MainWindow::setDisplayFilter(QString filter, FilterAction::Action action, F
emit filterAction(filter, action, filterType);
}
/*
* Used for registering custom packet menus
*
* @param funnel_action a custom packet menu action
*/
void MainWindow::appendPacketMenu(QAction* funnel_action)
{
dynamic_packet_menu_actions.append(funnel_action);
connect(funnel_action, SIGNAL(triggered(bool)), funnel_action, SLOT(triggerPacketCallback()));
}
/*
* Returns the list of registered packet menu actions
*
* After ensuring that all stored custom packet menu actions
* are registered with the Wireshark GUI, it returns them as a list
* so that they can potentially be displayed to a user.
*
* @return the list of registered packet menu actions
*/
QList<QAction *> MainWindow::getPacketMenuActions()
{
if (funnel_statistics_packet_menus_modified()) {
// If the packet menus were modified, we need to clear the already
// loaded packet menus to avoid duplicates
this->clearAddedPacketMenus();
funnel_statistics_load_packet_menus();
}
return dynamic_packet_menu_actions;
}
/*
* Clears the list of registered packet menu actions
*
* Clears the list of registered packet menu actions
* and frees all associated memory.
*/
void MainWindow::clearAddedPacketMenus()
{
for( int i=0; i<dynamic_packet_menu_actions.count(); ++i )
{
delete dynamic_packet_menu_actions[i];
}
dynamic_packet_menu_actions.clear();
}
/*
* Adds the custom packet menus to the supplied QMenu
*
* This method takes in QMenu and the selected packet's data
* and adds all applicable custom packet menus to it.
*
* @param ctx_menu The menu to add the packet menu entries to
* @param finfo_array The data in the selected packet
* @return true if a packet menu was added to the ctx_menu
*/
bool MainWindow::addPacketMenus(QMenu * ctx_menu, GPtrArray *finfo_array)
{
bool insertedPacketMenu = false;
QList<QAction *> myPacketMenuActions = this->getPacketMenuActions();
if (myPacketMenuActions.isEmpty()) {
return insertedPacketMenu;
}
// Build a set of fields present for efficient lookups
QSet<QString> fieldsPresent = QSet<QString>();
for (guint fieldInfoIndex = 0; fieldInfoIndex < finfo_array->len; fieldInfoIndex++) {
field_info *fi = (field_info *)g_ptr_array_index (finfo_array, fieldInfoIndex);
fieldsPresent.insert(QString(fi->hfinfo->abbrev));
}
// Place actions in the relevant (sub)menu
// The 'root' menu is the ctx_menu, so map NULL to that
QHash<QString, QMenu *> menuTextToMenus;
menuTextToMenus.insert(NULL, ctx_menu);
foreach (QAction * action, myPacketMenuActions) {
if (! qobject_cast<FunnelAction *>(action)) {
continue;
}
FunnelAction * packetAction = qobject_cast<FunnelAction *>(action);
// Only display a menu if all required fields are present
if (!fieldsPresent.contains(packetAction->getPacketRequiredFields())) {
continue;
}
packetAction->setPacketData(finfo_array);
packetAction->addToMenu(ctx_menu, menuTextToMenus);
insertedPacketMenu = true;
}
return insertedPacketMenu;
}

View File

@ -41,6 +41,7 @@ class MainWindow : public QMainWindow
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
bool hasSelection();
QList<int> selectedRows(bool useFrameNum = false);
void insertColumn(QString name, QString abbrev, gint pos = -1);
@ -50,6 +51,12 @@ public:
QString getFilter();
MainStatusBar *statusBar();
// Used for managing custom packet menus
void appendPacketMenu(QAction* funnel_action);
QList<QAction*> getPacketMenuActions();
void clearAddedPacketMenus();
bool addPacketMenus(QMenu * ctx_menu, GPtrArray *finfo_array);
public slots:
void setDisplayFilter(QString filter, FilterAction::Action action, FilterAction::ActionType filterType);
virtual void filterPackets(QString, bool) = 0;

View File

@ -56,6 +56,7 @@
#include <ui/qt/widgets/drag_label.h>
#include <ui/qt/filter_action.h>
#include <ui/qt/decode_as_dialog.h>
#include <ui/qt/wireshark_main_window.h>
#include <QAction>
#include <QActionGroup>
@ -206,7 +207,8 @@ PacketList::PacketList(QWidget *parent) :
set_column_visibility_(false),
frozen_rows_(QModelIndexList()),
cur_history_(-1),
in_history_(false)
in_history_(false),
finfo_array(NULL)
{
setItemsExpandable(false);
setRootIsDecorated(false);
@ -263,6 +265,14 @@ PacketList::PacketList(QWidget *parent) :
connect(verticalScrollBar(), SIGNAL(actionTriggered(int)), this, SLOT(vScrollBarActionTriggered(int)));
}
PacketList::~PacketList()
{
if (finfo_array)
{
g_ptr_array_free(finfo_array, TRUE);
}
}
void PacketList::colorsChanged()
{
const QString c_active = "active";
@ -569,8 +579,13 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
proto_prefs_menus_.clear();
if (finfo_array)
{
g_ptr_array_free(finfo_array, TRUE);
finfo_array = NULL;
}
if (cap_file_ && cap_file_->edt && cap_file_->edt->tree) {
GPtrArray *finfo_array = proto_all_finfos(cap_file_->edt->tree);
finfo_array = proto_all_finfos(cap_file_->edt->tree);
QList<QString> added_proto_prefs;
for (guint i = 0; i < finfo_array->len; i++) {
@ -599,7 +614,6 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
added_proto_prefs << module_name;
}
}
g_ptr_array_free(finfo_array, TRUE);
}
QModelIndex ctxIndex = indexAt(event->pos());
@ -623,6 +637,15 @@ void PacketList::contextMenuEvent(QContextMenuEvent *event)
ctx_menu->addSeparator();
// Code for custom context menus from Lua's register_packet_menu()
MainWindow * mainWindow = qobject_cast<MainWindow *>(mainApp->mainWindow());
if (cap_file_ && cap_file_->edt && cap_file_->edt->tree && mainWindow) {
bool insertedPacketMenu = mainWindow->addPacketMenus(ctx_menu, finfo_array);
if (insertedPacketMenu) {
ctx_menu->addSeparator();
}
}
ctx_menu->addAction(window()->findChild<QAction *>("actionViewEditResolvedName"));
ctx_menu->addSeparator();

View File

@ -40,6 +40,7 @@ class PacketList : public QTreeView
Q_OBJECT
public:
explicit PacketList(QWidget *parent = 0);
~PacketList();
enum SummaryCopyType {
CopyAsText,
@ -142,6 +143,7 @@ private:
QVector<int> selection_history_;
int cur_history_;
bool in_history_;
GPtrArray *finfo_array; // Packet data from the last selected packet entry
void setFrameReftime(gboolean set, frame_data *fdata);
void setColumnVisibility();

View File

@ -1547,6 +1547,7 @@ void WiresharkMainWindow::reloadLuaPlugins()
mainApp->setReloadingLua(true);
wslua_reload_plugins(NULL, NULL);
this->clearAddedPacketMenus();
funnel_statistics_reload_menus();
reloadDynamicMenus();
closePacketDialogs();