forked from osmocom/wireshark
516 lines
14 KiB
C++
516 lines
14 KiB
C++
/* enabled_protocols_model.cpp
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <QSortFilterProxyModel>
|
|
|
|
#include <ui/qt/models/enabled_protocols_model.h>
|
|
#include <epan/packet.h>
|
|
#include <epan/disabled_protos.h>
|
|
|
|
#include <ui/qt/utils/variant_pointer.h>
|
|
#include "wireshark_application.h"
|
|
|
|
#include <QRegExp>
|
|
|
|
class ProtocolTreeItem : public EnabledProtocolItem
|
|
{
|
|
public:
|
|
ProtocolTreeItem(protocol_t* proto, EnabledProtocolItem* parent)
|
|
: EnabledProtocolItem(proto_get_protocol_short_name(proto), proto_get_protocol_long_name(proto), proto_is_protocol_enabled(proto), parent),
|
|
proto_(proto)
|
|
{
|
|
|
|
}
|
|
|
|
virtual ~ProtocolTreeItem() {}
|
|
|
|
protected:
|
|
virtual void applyValuePrivate(gboolean value)
|
|
{
|
|
if (! proto_can_toggle_protocol(proto_get_id(proto_)) || proto_is_pino(proto_)) {
|
|
return;
|
|
}
|
|
proto_set_decoding(proto_get_id(proto_), value);
|
|
}
|
|
|
|
private:
|
|
protocol_t* proto_;
|
|
};
|
|
|
|
class HeuristicTreeItem : public EnabledProtocolItem
|
|
{
|
|
public:
|
|
HeuristicTreeItem(heur_dtbl_entry_t *heuristic, EnabledProtocolItem* parent)
|
|
: EnabledProtocolItem(heuristic->short_name, heuristic->display_name, heuristic->enabled, parent),
|
|
heuristic_table_(heuristic)
|
|
{
|
|
type_ = EnabledProtocolItem::Heuristic;
|
|
}
|
|
|
|
virtual ~HeuristicTreeItem() {}
|
|
|
|
protected:
|
|
virtual void applyValuePrivate(gboolean value)
|
|
{
|
|
heuristic_table_->enabled = value;
|
|
}
|
|
|
|
private:
|
|
heur_dtbl_entry_t *heuristic_table_;
|
|
};
|
|
|
|
|
|
EnabledProtocolItem::EnabledProtocolItem(QString name, QString description, bool enabled, EnabledProtocolItem* parent) :
|
|
ModelHelperTreeItem<EnabledProtocolItem>(parent),
|
|
name_(name),
|
|
description_(description),
|
|
enabled_(enabled),
|
|
enabledInit_(enabled),
|
|
type_(EnabledProtocolItem::Standard)
|
|
{
|
|
}
|
|
|
|
EnabledProtocolItem::~EnabledProtocolItem()
|
|
{
|
|
}
|
|
|
|
EnabledProtocolItem::EnableProtocolType EnabledProtocolItem::type() const
|
|
{
|
|
return type_;
|
|
}
|
|
|
|
bool EnabledProtocolItem::applyValue()
|
|
{
|
|
if (enabledInit_ != enabled_) {
|
|
applyValuePrivate(enabled_);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
EnabledProtocolsModel::EnabledProtocolsModel(QObject *parent) :
|
|
QAbstractItemModel(parent),
|
|
root_(new ProtocolTreeItem(NULL, NULL))
|
|
{
|
|
}
|
|
|
|
EnabledProtocolsModel::~EnabledProtocolsModel()
|
|
{
|
|
delete root_;
|
|
}
|
|
|
|
int EnabledProtocolsModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
EnabledProtocolItem *parent_item;
|
|
if (parent.column() > 0)
|
|
return 0;
|
|
|
|
if (!parent.isValid())
|
|
parent_item = root_;
|
|
else
|
|
parent_item = static_cast<EnabledProtocolItem*>(parent.internalPointer());
|
|
|
|
if (parent_item == NULL)
|
|
return 0;
|
|
|
|
return parent_item->childCount();
|
|
}
|
|
|
|
int EnabledProtocolsModel::columnCount(const QModelIndex&) const
|
|
{
|
|
return colLast;
|
|
}
|
|
|
|
QVariant EnabledProtocolsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
|
|
|
switch ((enum EnabledProtocolsColumn)section) {
|
|
case colProtocol:
|
|
return tr("Protocol");
|
|
case colDescription:
|
|
return tr("Description");
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return QVariant();
|
|
}
|
|
|
|
QModelIndex EnabledProtocolsModel::parent(const QModelIndex& index) const
|
|
{
|
|
if (!index.isValid())
|
|
return QModelIndex();
|
|
|
|
EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
|
|
if (item != NULL) {
|
|
EnabledProtocolItem* parent_item = item->parentItem();
|
|
if (parent_item != NULL) {
|
|
if (parent_item == root_)
|
|
return QModelIndex();
|
|
|
|
return createIndex(parent_item->row(), 0, parent_item);
|
|
}
|
|
}
|
|
|
|
return QModelIndex();
|
|
}
|
|
|
|
QModelIndex EnabledProtocolsModel::index(int row, int column, const QModelIndex& parent) const
|
|
{
|
|
if (!hasIndex(row, column, parent))
|
|
return QModelIndex();
|
|
|
|
EnabledProtocolItem *parent_item, *child_item;
|
|
|
|
if (!parent.isValid())
|
|
parent_item = root_;
|
|
else
|
|
parent_item = static_cast<EnabledProtocolItem*>(parent.internalPointer());
|
|
|
|
Q_ASSERT(parent_item);
|
|
|
|
child_item = parent_item->child(row);
|
|
if (child_item) {
|
|
return createIndex(row, column, child_item);
|
|
}
|
|
|
|
return QModelIndex();
|
|
}
|
|
|
|
Qt::ItemFlags EnabledProtocolsModel::flags(const QModelIndex &index) const
|
|
{
|
|
if (!index.isValid())
|
|
return Qt::ItemFlags();
|
|
|
|
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
|
|
switch(index.column())
|
|
{
|
|
case colProtocol:
|
|
flags |= Qt::ItemIsUserCheckable;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
QVariant EnabledProtocolsModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
|
|
if (item == NULL)
|
|
return QVariant();
|
|
|
|
switch (role)
|
|
{
|
|
case Qt::DisplayRole:
|
|
switch ((enum EnabledProtocolsColumn)index.column())
|
|
{
|
|
case colProtocol:
|
|
return item->name();
|
|
case colDescription:
|
|
return item->description();
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case Qt::CheckStateRole:
|
|
switch ((enum EnabledProtocolsColumn)index.column())
|
|
{
|
|
case colProtocol:
|
|
return item->enabled() ? Qt::Checked : Qt::Unchecked;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case DATA_PROTOCOL_TYPE:
|
|
return QVariant::fromValue(item->type());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
bool EnabledProtocolsModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
{
|
|
if (!index.isValid())
|
|
return false;
|
|
|
|
if ((role != Qt::EditRole) &&
|
|
((index.column() == colProtocol) && (role != Qt::CheckStateRole)))
|
|
return false;
|
|
|
|
if (data(index, role) == value) {
|
|
// Data appears unchanged, do not do additional checks.
|
|
return true;
|
|
}
|
|
|
|
EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
|
|
if (item == NULL)
|
|
return false;
|
|
|
|
item->setEnabled(value == Qt::Checked ? true : false);
|
|
|
|
QVector<int> roles;
|
|
roles << role;
|
|
|
|
emit dataChanged(index, index, roles);
|
|
|
|
return true;
|
|
}
|
|
|
|
static void addHeuristicItem(gpointer data, gpointer user_data)
|
|
{
|
|
heur_dtbl_entry_t* heur = (heur_dtbl_entry_t*)data;
|
|
ProtocolTreeItem* protocol_item = (ProtocolTreeItem*)user_data;
|
|
|
|
HeuristicTreeItem* heuristic_row = new HeuristicTreeItem(heur, protocol_item);
|
|
protocol_item->prependChild(heuristic_row);
|
|
}
|
|
|
|
void EnabledProtocolsModel::populate()
|
|
{
|
|
void *cookie;
|
|
protocol_t *protocol;
|
|
|
|
emit beginResetModel();
|
|
|
|
// Iterate over all the protocols
|
|
for (int i = proto_get_first_protocol(&cookie); i != -1; i = proto_get_next_protocol(&cookie))
|
|
{
|
|
if (proto_can_toggle_protocol(i))
|
|
{
|
|
protocol = find_protocol_by_id(i);
|
|
ProtocolTreeItem* protocol_row = new ProtocolTreeItem(protocol, root_);
|
|
root_->prependChild(protocol_row);
|
|
|
|
proto_heuristic_dissector_foreach(protocol, addHeuristicItem, protocol_row);
|
|
}
|
|
}
|
|
|
|
emit endResetModel();
|
|
}
|
|
|
|
void EnabledProtocolsModel::applyChanges(bool writeChanges)
|
|
{
|
|
bool redissect = false;
|
|
|
|
for (int proto_index = 0; proto_index < root_->childCount(); proto_index++) {
|
|
EnabledProtocolItem* proto = root_->child(proto_index);
|
|
redissect |= proto->applyValue();
|
|
for (int heur_index = 0; heur_index < proto->childCount(); heur_index++) {
|
|
EnabledProtocolItem* heur = proto->child(heur_index);
|
|
redissect |= heur->applyValue();
|
|
}
|
|
}
|
|
|
|
if (redissect) {
|
|
saveChanges(writeChanges);
|
|
}
|
|
}
|
|
|
|
void EnabledProtocolsModel::disableProtocol(struct _protocol *protocol)
|
|
{
|
|
ProtocolTreeItem disabled_proto(protocol, NULL);
|
|
disabled_proto.setEnabled(false);
|
|
if (disabled_proto.applyValue()) {
|
|
saveChanges();
|
|
}
|
|
}
|
|
|
|
void EnabledProtocolsModel::saveChanges(bool writeChanges)
|
|
{
|
|
if (writeChanges) {
|
|
save_enabled_and_disabled_lists();
|
|
}
|
|
wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
|
|
}
|
|
|
|
|
|
EnabledProtocolsProxyModel::EnabledProtocolsProxyModel(QObject * parent)
|
|
: QSortFilterProxyModel(parent),
|
|
type_(EnabledProtocolsProxyModel::EveryWhere),
|
|
protocolType_(EnabledProtocolItem::Any),
|
|
filter_()
|
|
{}
|
|
|
|
bool EnabledProtocolsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
|
{
|
|
//Use EnabledProtocolItem directly for better performance
|
|
EnabledProtocolItem* left_item = static_cast<EnabledProtocolItem*>(left.internalPointer());
|
|
EnabledProtocolItem* right_item = static_cast<EnabledProtocolItem*>(right.internalPointer());
|
|
|
|
if ((left_item != NULL) && (right_item != NULL)) {
|
|
|
|
int compare_ret = 0;
|
|
|
|
if (left.column() == EnabledProtocolsModel::colProtocol)
|
|
compare_ret = left_item->name().compare(right_item->name(), Qt::CaseInsensitive);
|
|
else if (left.column() == EnabledProtocolsModel::colDescription)
|
|
compare_ret = left_item->description().compare(right_item->description(), Qt::CaseInsensitive);
|
|
|
|
if (compare_ret < 0)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Qt::ItemFlags EnabledProtocolsProxyModel::flags(const QModelIndex &index) const
|
|
{
|
|
Qt::ItemFlags flags = Qt::NoItemFlags;
|
|
if (index.isValid())
|
|
{
|
|
QModelIndex source = mapToSource(index);
|
|
if (filterAcceptsSelf(source.row(), source.parent()) )
|
|
{
|
|
flags = Qt::ItemIsEnabled;
|
|
flags |= Qt::ItemIsSelectable;
|
|
flags |= Qt::ItemIsUserCheckable;
|
|
}
|
|
}
|
|
|
|
return flags;
|
|
}
|
|
|
|
bool EnabledProtocolsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
|
{
|
|
if (filterAcceptsSelf(sourceRow, sourceParent))
|
|
return true;
|
|
|
|
#if 0
|
|
QModelIndex parent = sourceParent;
|
|
while (parent.isValid())
|
|
{
|
|
if (filterAcceptsSelf(parent.row(), parent.parent()))
|
|
return true;
|
|
parent = parent.parent();
|
|
}
|
|
#endif
|
|
|
|
if (filterAcceptsChild(sourceRow, sourceParent))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EnabledProtocolsProxyModel::filterAcceptsSelf(int sourceRow, const QModelIndex &sourceParent) const
|
|
{
|
|
QModelIndex nameIdx = sourceModel()->index(sourceRow, EnabledProtocolsModel::colProtocol, sourceParent);
|
|
if (! nameIdx.isValid())
|
|
return false;
|
|
EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(nameIdx.internalPointer());
|
|
if (! item)
|
|
return false;
|
|
|
|
QRegExp regex(filter_, Qt::CaseInsensitive);
|
|
|
|
if ((type_ != EnabledProtocolsProxyModel::EnabledItems && type_ != EnabledProtocolsProxyModel::DisabledItems) &&
|
|
(protocolType_ == EnabledProtocolItem::Any || protocolType_ == item->type()) )
|
|
{
|
|
if (! filter_.isEmpty())
|
|
{
|
|
if (item->name().contains(regex) && type_ != OnlyDescription)
|
|
return true;
|
|
|
|
if (item->description().contains(regex) && type_ != OnlyProtocol)
|
|
return true;
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
else if (type_ == EnabledProtocolsProxyModel::EnabledItems && item->enabled())
|
|
return true;
|
|
else if (type_ == EnabledProtocolsProxyModel::DisabledItems && ! item->enabled())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EnabledProtocolsProxyModel::filterAcceptsChild(int sourceRow, const QModelIndex &sourceParent) const
|
|
{
|
|
QModelIndex item = sourceModel()->index(sourceRow, EnabledProtocolsModel::colProtocol, sourceParent);
|
|
if (! item.isValid())
|
|
return false;
|
|
|
|
int childCount = item.model()->rowCount(item);
|
|
if (childCount == 0)
|
|
return false;
|
|
|
|
for (int i = 0; i < childCount; i++)
|
|
{
|
|
if (filterAcceptsSelf(i, item))
|
|
return true;
|
|
#if 0
|
|
/* Recursive search disabled for performance reasons */
|
|
if (filterAcceptsChild(i, item))
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void EnabledProtocolsProxyModel::setFilter(const QString& filter, EnabledProtocolsProxyModel::SearchType type,
|
|
EnabledProtocolItem::EnableProtocolType protocolType)
|
|
{
|
|
filter_ = filter;
|
|
type_ = type;
|
|
protocolType_ = protocolType;
|
|
invalidateFilter();
|
|
}
|
|
|
|
void EnabledProtocolsProxyModel::setItemsEnable(EnabledProtocolsProxyModel::EnableType enableType, QModelIndex parent)
|
|
{
|
|
if (! sourceModel())
|
|
return;
|
|
|
|
if (! parent.isValid())
|
|
emit beginResetModel();
|
|
|
|
for (int row = 0; row < rowCount(parent); row++)
|
|
{
|
|
QModelIndex idx = index(row, EnabledProtocolsModel::colProtocol, parent);
|
|
|
|
QModelIndex sIdx = mapToSource(idx);
|
|
if (sIdx.isValid())
|
|
{
|
|
EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(sIdx.internalPointer());
|
|
if (item && (protocolType_ == EnabledProtocolItem::Any || protocolType_ == item->type()) )
|
|
{
|
|
Qt::CheckState enable = idx.data(Qt::CheckStateRole).value<Qt::CheckState>();
|
|
if (enableType == Enable)
|
|
enable = Qt::Checked;
|
|
else if (enableType == Disable)
|
|
enable = Qt::Unchecked;
|
|
else
|
|
enable = enable == Qt::Checked ? Qt::Unchecked : Qt::Checked;
|
|
|
|
sourceModel()->setData(mapToSource(idx), QVariant::fromValue(enable), Qt::CheckStateRole);
|
|
}
|
|
}
|
|
|
|
setItemsEnable(enableType, idx);
|
|
}
|
|
|
|
|
|
if (! parent.isValid())
|
|
emit endResetModel();
|
|
}
|