2013-08-08 00:26:57 +00:00
|
|
|
|
/* capture_filter_edit.cpp
|
|
|
|
|
*
|
|
|
|
|
* Wireshark - Network traffic analyzer
|
|
|
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
|
|
|
* Copyright 1998 Gerald Combs
|
|
|
|
|
*
|
2018-04-30 07:47:58 +00:00
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
*/
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
|
|
|
|
|
#include <epan/proto.h>
|
|
|
|
|
|
|
|
|
|
#include "capture_opts.h"
|
2015-05-19 17:18:54 +00:00
|
|
|
|
|
|
|
|
|
#include <ui/capture_globals.h>
|
2023-02-06 23:08:14 +00:00
|
|
|
|
#include <wsutil/filter_files.h>
|
2015-10-04 17:10:29 +00:00
|
|
|
|
#include <wsutil/utf8_entities.h>
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
2017-07-25 14:15:18 +00:00
|
|
|
|
#include <ui/qt/widgets/capture_filter_edit.h>
|
2015-06-03 23:26:00 +00:00
|
|
|
|
#include "capture_filter_syntax_worker.h"
|
2016-01-27 20:33:24 +00:00
|
|
|
|
#include "filter_dialog.h"
|
2017-07-25 14:15:18 +00:00
|
|
|
|
#include <ui/qt/widgets/stock_icon_tool_button.h>
|
2022-02-01 03:30:09 +00:00
|
|
|
|
#include "main_application.h"
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
|
#include <QComboBox>
|
|
|
|
|
#include <QCompleter>
|
2016-01-27 20:33:24 +00:00
|
|
|
|
#include <QMenu>
|
|
|
|
|
#include <QMessageBox>
|
2013-08-08 00:26:57 +00:00
|
|
|
|
#include <QPainter>
|
2015-05-19 17:18:54 +00:00
|
|
|
|
#include <QStringListModel>
|
2013-08-08 00:26:57 +00:00
|
|
|
|
#include <QStyleOptionFrame>
|
|
|
|
|
|
2017-07-25 14:15:18 +00:00
|
|
|
|
#include <ui/qt/utils/qt_ui_utils.h>
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
|
// To do:
|
|
|
|
|
// - This duplicates some DisplayFilterEdit code.
|
|
|
|
|
// - We need simplified (button- and dropdown-free) versions for use in dialogs and field-only checking.
|
|
|
|
|
|
|
|
|
|
static const QString libpcap_primitive_chars_ = "-0123456789abcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
|
2018-02-21 18:56:05 +00:00
|
|
|
|
// Primitives are from pcap-filter.manmisc
|
2015-05-19 17:18:54 +00:00
|
|
|
|
static const QStringList libpcap_primitives_ = QStringList()
|
2018-02-21 18:56:05 +00:00
|
|
|
|
// "Abbreviations for..."
|
|
|
|
|
<< "ether proto"
|
|
|
|
|
<< "ip" << "ip6" << "arp" << "rarp" << "atalk" << "aarp" << "decnet" << "iso" << "stp" << "ipx" << "netbeui"
|
|
|
|
|
<< "moprc" << "mopdl"
|
|
|
|
|
// ip proto
|
|
|
|
|
<< "tcp" << "udp" << "icmp"
|
|
|
|
|
// iso proto
|
|
|
|
|
<< "clnp" << "esis" << "isis"
|
|
|
|
|
// IS‐IS PDU types
|
|
|
|
|
<< "l1" << "l2" << "iih" << "lsp" << "snp" << "csnp" << "psnp"
|
|
|
|
|
|
|
|
|
|
// grep -E '^\.IP "\\fB.*\\f(R"|P)$' pcap-filter.manmisc | sed -e 's/^\.IP "\\fB/<< "/' -e 's/ *\\f.*/"/' | sort -u
|
|
|
|
|
<< "action"
|
|
|
|
|
<< "clnp"
|
|
|
|
|
<< "decnet dst"
|
|
|
|
|
<< "decnet host"
|
|
|
|
|
<< "decnet src"
|
|
|
|
|
<< "dir"
|
|
|
|
|
<< "dst host"
|
|
|
|
|
<< "dst net"
|
|
|
|
|
<< "dst port"
|
|
|
|
|
<< "dst portrange"
|
|
|
|
|
<< "ether broadcast"
|
|
|
|
|
<< "ether dst"
|
|
|
|
|
<< "ether host"
|
|
|
|
|
<< "ether multicast"
|
|
|
|
|
<< "ether src"
|
|
|
|
|
<< "gateway"
|
|
|
|
|
<< "greater"
|
|
|
|
|
<< "host"
|
|
|
|
|
<< "ifname"
|
|
|
|
|
<< "ip broadcast"
|
|
|
|
|
<< "ip multicast"
|
|
|
|
|
<< "ip proto"
|
|
|
|
|
<< "ip protochain"
|
|
|
|
|
<< "ip6 multicast"
|
|
|
|
|
<< "ip6 proto"
|
|
|
|
|
<< "ip6 protochain"
|
|
|
|
|
<< "iso proto"
|
|
|
|
|
<< "l1"
|
|
|
|
|
<< "lat"
|
|
|
|
|
<< "less"
|
|
|
|
|
<< "mpls"
|
|
|
|
|
<< "net"
|
|
|
|
|
<< "on"
|
|
|
|
|
<< "port"
|
|
|
|
|
<< "portrange"
|
|
|
|
|
<< "reason"
|
|
|
|
|
<< "rnr"
|
|
|
|
|
<< "rset"
|
|
|
|
|
<< "rulenum"
|
|
|
|
|
<< "ruleset"
|
|
|
|
|
<< "src host"
|
|
|
|
|
<< "src net"
|
|
|
|
|
<< "src port"
|
|
|
|
|
<< "src portrange"
|
|
|
|
|
<< "srnr"
|
|
|
|
|
<< "subrulenum"
|
|
|
|
|
<< "subtype"
|
|
|
|
|
<< "type"
|
|
|
|
|
<< "vlan"
|
|
|
|
|
<< "wlan addr1"
|
|
|
|
|
<< "wlan addr2"
|
|
|
|
|
<< "wlan addr3"
|
|
|
|
|
<< "wlan addr4"
|
|
|
|
|
<< "wlan ra"
|
|
|
|
|
<< "wlan ta"
|
|
|
|
|
;
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
|
|
|
|
CaptureFilterEdit::CaptureFilterEdit(QWidget *parent, bool plain) :
|
|
|
|
|
SyntaxLineEdit(parent),
|
|
|
|
|
plain_(plain),
|
|
|
|
|
field_name_only_(false),
|
2016-01-27 20:33:24 +00:00
|
|
|
|
enable_save_action_(false),
|
|
|
|
|
save_action_(NULL),
|
|
|
|
|
remove_action_(NULL),
|
2019-11-04 14:43:16 +00:00
|
|
|
|
actions_(Q_NULLPTR),
|
2015-06-03 23:26:00 +00:00
|
|
|
|
bookmark_button_(NULL),
|
|
|
|
|
clear_button_(NULL),
|
2013-08-08 00:26:57 +00:00
|
|
|
|
apply_button_(NULL)
|
|
|
|
|
{
|
|
|
|
|
setAccessibleName(tr("Capture filter entry"));
|
|
|
|
|
|
2015-05-19 17:18:54 +00:00
|
|
|
|
completion_model_ = new QStringListModel(this);
|
|
|
|
|
setCompleter(new QCompleter(completion_model_, this));
|
|
|
|
|
setCompletionTokenChars(libpcap_primitive_chars_);
|
|
|
|
|
|
2016-02-23 18:04:16 +00:00
|
|
|
|
setConflict(false);
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
2015-06-03 23:26:00 +00:00
|
|
|
|
if (!plain_) {
|
2016-01-30 00:45:04 +00:00
|
|
|
|
bookmark_button_ = new StockIconToolButton(this, "x-capture-filter-bookmark");
|
2015-06-03 23:26:00 +00:00
|
|
|
|
bookmark_button_->setCursor(Qt::ArrowCursor);
|
2017-04-19 21:11:43 +00:00
|
|
|
|
bookmark_button_->setMenu(new QMenu(bookmark_button_));
|
2015-09-10 21:42:07 +00:00
|
|
|
|
bookmark_button_->setPopupMode(QToolButton::InstantPopup);
|
|
|
|
|
bookmark_button_->setToolTip(tr("Manage saved bookmarks."));
|
|
|
|
|
bookmark_button_->setIconSize(QSize(14, 14));
|
|
|
|
|
bookmark_button_->setStyleSheet(
|
|
|
|
|
"QToolButton {"
|
|
|
|
|
" border: none;"
|
|
|
|
|
" background: transparent;" // Disables platform style on Windows.
|
|
|
|
|
" padding: 0 0 0 0;"
|
|
|
|
|
"}"
|
|
|
|
|
"QToolButton::menu-indicator { image: none; }"
|
2013-08-08 00:26:57 +00:00
|
|
|
|
);
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(bookmark_button_, &StockIconToolButton::clicked, this, &CaptureFilterEdit::bookmarkClicked);
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
2015-09-10 21:42:07 +00:00
|
|
|
|
clear_button_ = new StockIconToolButton(this, "x-filter-clear");
|
2015-06-03 23:26:00 +00:00
|
|
|
|
clear_button_->setCursor(Qt::ArrowCursor);
|
2015-09-10 21:42:07 +00:00
|
|
|
|
clear_button_->setToolTip(QString());
|
|
|
|
|
clear_button_->setIconSize(QSize(14, 14));
|
2015-06-03 23:26:00 +00:00
|
|
|
|
clear_button_->setStyleSheet(
|
2015-09-10 21:42:07 +00:00
|
|
|
|
"QToolButton {"
|
|
|
|
|
" border: none;"
|
|
|
|
|
" background: transparent;" // Disables platform style on Windows.
|
|
|
|
|
" padding: 0 0 0 0;"
|
|
|
|
|
" margin-left: 1px;"
|
|
|
|
|
"}"
|
|
|
|
|
);
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(clear_button_, &StockIconToolButton::clicked, this, &CaptureFilterEdit::clearFilter);
|
2015-06-03 23:26:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(this, &CaptureFilterEdit::textChanged, this,
|
|
|
|
|
static_cast<void (CaptureFilterEdit::*)(const QString &)>(&CaptureFilterEdit::checkFilter));
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
2016-01-27 20:33:24 +00:00
|
|
|
|
#if 0
|
|
|
|
|
// Disable the apply button for now
|
2013-08-08 00:26:57 +00:00
|
|
|
|
if (!plain_) {
|
2015-09-10 21:42:07 +00:00
|
|
|
|
apply_button_ = new StockIconToolButton(this, "x-filter-apply");
|
2013-08-08 00:26:57 +00:00
|
|
|
|
apply_button_->setCursor(Qt::ArrowCursor);
|
|
|
|
|
apply_button_->setEnabled(false);
|
2015-09-10 21:42:07 +00:00
|
|
|
|
apply_button_->setToolTip(tr("Apply this filter string to the display."));
|
|
|
|
|
apply_button_->setIconSize(QSize(24, 14));
|
2013-08-08 00:26:57 +00:00
|
|
|
|
apply_button_->setStyleSheet(
|
2015-09-10 21:42:07 +00:00
|
|
|
|
"QToolButton {"
|
|
|
|
|
" border: none;"
|
|
|
|
|
" background: transparent;" // Disables platform style on Windows.
|
|
|
|
|
" padding: 0 0 0 0;"
|
2013-08-08 00:26:57 +00:00
|
|
|
|
"}"
|
|
|
|
|
);
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(apply_button_, &StockIconToolButton::clicked, this, &CaptureFilterEdit::applyCaptureFilter);
|
2013-08-08 00:26:57 +00:00
|
|
|
|
}
|
2016-01-27 20:33:24 +00:00
|
|
|
|
#endif
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(this, &CaptureFilterEdit::returnPressed, this, &CaptureFilterEdit::applyCaptureFilter);
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
|
|
|
|
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
2015-06-03 23:26:00 +00:00
|
|
|
|
QSize bksz;
|
|
|
|
|
if (bookmark_button_) bksz = bookmark_button_->sizeHint();
|
|
|
|
|
QSize cbsz;
|
|
|
|
|
if (clear_button_) cbsz = clear_button_->sizeHint();
|
2013-08-08 00:26:57 +00:00
|
|
|
|
QSize apsz;
|
2015-06-03 23:26:00 +00:00
|
|
|
|
if (apply_button_) apsz = apply_button_->sizeHint();
|
|
|
|
|
|
2013-08-08 00:26:57 +00:00
|
|
|
|
setStyleSheet(QString(
|
|
|
|
|
"CaptureFilterEdit {"
|
|
|
|
|
" padding-left: %1px;"
|
|
|
|
|
" margin-left: %2px;"
|
|
|
|
|
" margin-right: %3px;"
|
|
|
|
|
"}"
|
|
|
|
|
)
|
|
|
|
|
.arg(frameWidth + 1)
|
|
|
|
|
.arg(bksz.width())
|
|
|
|
|
.arg(cbsz.width() + apsz.width() + frameWidth + 1)
|
|
|
|
|
);
|
|
|
|
|
|
2016-02-25 18:15:14 +00:00
|
|
|
|
QComboBox *cf_combo = qobject_cast<QComboBox *>(parent);
|
|
|
|
|
if (cf_combo) {
|
2020-05-31 15:25:36 +00:00
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
|
|
|
|
connect(cf_combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::textActivated),
|
|
|
|
|
this, &CaptureFilterEdit::textEdited);
|
|
|
|
|
#else
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(cf_combo, static_cast<void (QComboBox::*)(const QString &)>(&QComboBox::activated),
|
|
|
|
|
this, &CaptureFilterEdit::textEdited);
|
2020-05-31 15:25:36 +00:00
|
|
|
|
#endif
|
2016-02-25 18:15:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-04 13:09:50 +00:00
|
|
|
|
syntax_thread_ = new QThread;
|
2013-08-08 00:26:57 +00:00
|
|
|
|
syntax_worker_ = new CaptureFilterSyntaxWorker;
|
2021-04-04 13:09:50 +00:00
|
|
|
|
syntax_worker_->moveToThread(syntax_thread_);
|
2022-02-01 03:30:09 +00:00
|
|
|
|
connect(mainApp, &MainApplication::appInitialized, this, &CaptureFilterEdit::updateBookmarkMenu);
|
|
|
|
|
connect(mainApp, &MainApplication::captureFilterListChanged, this, &CaptureFilterEdit::updateBookmarkMenu);
|
2021-04-04 13:09:50 +00:00
|
|
|
|
connect(syntax_thread_, &QThread::started, this,
|
2018-12-21 19:03:34 +00:00
|
|
|
|
static_cast<void (CaptureFilterEdit::*)()>(&CaptureFilterEdit::checkFilter));
|
|
|
|
|
connect(syntax_worker_, &CaptureFilterSyntaxWorker::syntaxResult,
|
|
|
|
|
this, &CaptureFilterEdit::setFilterSyntaxState);
|
2021-04-04 13:09:50 +00:00
|
|
|
|
connect(this, &CaptureFilterEdit::captureFilterChanged, syntax_worker_, &CaptureFilterSyntaxWorker::checkFilter);
|
|
|
|
|
syntax_thread_->start();
|
2016-11-10 15:51:41 +00:00
|
|
|
|
updateBookmarkMenu();
|
2013-08-08 00:26:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-04 13:09:50 +00:00
|
|
|
|
CaptureFilterEdit::~CaptureFilterEdit()
|
|
|
|
|
{
|
|
|
|
|
syntax_thread_->quit();
|
|
|
|
|
syntax_thread_->wait();
|
|
|
|
|
delete syntax_thread_;
|
|
|
|
|
delete syntax_worker_;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-08 00:26:57 +00:00
|
|
|
|
void CaptureFilterEdit::paintEvent(QPaintEvent *evt) {
|
|
|
|
|
SyntaxLineEdit::paintEvent(evt);
|
|
|
|
|
|
2016-01-27 20:33:24 +00:00
|
|
|
|
if (bookmark_button_) {
|
|
|
|
|
// Draw the right border by hand. We could try to do this in the
|
|
|
|
|
// style sheet but it's a pain.
|
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
|
QColor divider_color = Qt::gray;
|
|
|
|
|
#else
|
|
|
|
|
QColor divider_color = palette().shadow().color();
|
|
|
|
|
#endif
|
|
|
|
|
QPainter painter(this);
|
|
|
|
|
painter.setPen(divider_color);
|
|
|
|
|
QRect cr = contentsRect();
|
|
|
|
|
QSize bksz = bookmark_button_->size();
|
2022-06-21 17:54:08 +00:00
|
|
|
|
painter.drawLine(bksz.width(), cr.top(), bksz.width(), cr.bottom() + 1);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
|
|
|
|
void CaptureFilterEdit::resizeEvent(QResizeEvent *)
|
|
|
|
|
{
|
2015-06-03 23:26:00 +00:00
|
|
|
|
QSize cbsz;
|
|
|
|
|
if (clear_button_) cbsz = clear_button_->sizeHint();
|
2013-08-08 00:26:57 +00:00
|
|
|
|
QSize apsz;
|
2015-06-03 23:26:00 +00:00
|
|
|
|
if (apply_button_) apsz = apply_button_->sizeHint();
|
|
|
|
|
|
2013-08-08 00:26:57 +00:00
|
|
|
|
int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
|
2015-06-03 23:26:00 +00:00
|
|
|
|
if (clear_button_) {
|
|
|
|
|
clear_button_->move(contentsRect().right() - frameWidth - cbsz.width() - apsz.width(),
|
|
|
|
|
contentsRect().top());
|
2015-09-10 21:42:07 +00:00
|
|
|
|
clear_button_->setMinimumHeight(contentsRect().height());
|
2015-06-03 23:26:00 +00:00
|
|
|
|
clear_button_->setMaximumHeight(contentsRect().height());
|
|
|
|
|
}
|
2013-08-08 00:26:57 +00:00
|
|
|
|
if (apply_button_) {
|
|
|
|
|
apply_button_->move(contentsRect().right() - frameWidth - apsz.width(),
|
|
|
|
|
contentsRect().top());
|
2015-09-10 21:42:07 +00:00
|
|
|
|
apply_button_->setMinimumHeight(contentsRect().height());
|
2013-08-08 00:26:57 +00:00
|
|
|
|
apply_button_->setMaximumHeight(contentsRect().height());
|
|
|
|
|
}
|
2015-06-03 23:26:00 +00:00
|
|
|
|
if (bookmark_button_) {
|
2015-09-10 21:42:07 +00:00
|
|
|
|
bookmark_button_->setMinimumHeight(contentsRect().height());
|
2015-06-03 23:26:00 +00:00
|
|
|
|
bookmark_button_->setMaximumHeight(contentsRect().height());
|
|
|
|
|
}
|
2013-08-08 00:26:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-23 18:04:16 +00:00
|
|
|
|
void CaptureFilterEdit::setConflict(bool conflict)
|
|
|
|
|
{
|
|
|
|
|
if (conflict) {
|
|
|
|
|
//: This is a very long concept that needs to fit into a short space.
|
|
|
|
|
placeholder_text_ = tr("Multiple filters selected. Override them here or leave this blank to preserve them.");
|
|
|
|
|
setToolTip(tr("<p>The interfaces you have selected have different capture filters."
|
|
|
|
|
" Typing a filter here will override them. Doing nothing will"
|
|
|
|
|
" preserve them.</p>"));
|
|
|
|
|
} else {
|
|
|
|
|
placeholder_text_ = QString(tr("Enter a capture filter %1")).arg(UTF8_HORIZONTAL_ELLIPSIS);
|
|
|
|
|
setToolTip(QString());
|
|
|
|
|
}
|
|
|
|
|
setPlaceholderText(placeholder_text_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX Make this private along with setConflict.
|
|
|
|
|
QPair<const QString, bool> CaptureFilterEdit::getSelectedFilter()
|
|
|
|
|
{
|
|
|
|
|
QString user_filter;
|
|
|
|
|
bool filter_conflict = false;
|
|
|
|
|
#ifdef HAVE_LIBPCAP
|
|
|
|
|
int selected_devices = 0;
|
|
|
|
|
|
|
|
|
|
for (guint i = 0; i < global_capture_opts.all_ifaces->len; i++) {
|
2017-08-24 14:16:34 +00:00
|
|
|
|
interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
|
|
|
|
|
if (device->selected) {
|
2016-02-23 18:04:16 +00:00
|
|
|
|
selected_devices++;
|
|
|
|
|
if (selected_devices == 1) {
|
2017-08-24 14:16:34 +00:00
|
|
|
|
user_filter = device->cfilter;
|
2016-02-23 18:04:16 +00:00
|
|
|
|
} else {
|
2017-08-24 14:16:34 +00:00
|
|
|
|
if (user_filter.compare(device->cfilter)) {
|
2016-02-23 18:04:16 +00:00
|
|
|
|
filter_conflict = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif // HAVE_LIBPCAP
|
|
|
|
|
return QPair<const QString, bool>(user_filter, filter_conflict);
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-07 17:27:13 +00:00
|
|
|
|
void CaptureFilterEdit::checkFilter(const QString& filter)
|
2013-08-08 00:26:57 +00:00
|
|
|
|
{
|
2019-11-17 19:02:20 +00:00
|
|
|
|
if (text().length() == 0 && actions_ && actions_->checkedAction())
|
2019-11-04 14:43:16 +00:00
|
|
|
|
actions_->checkedAction()->setChecked(false);
|
|
|
|
|
|
2016-01-07 17:27:13 +00:00
|
|
|
|
setSyntaxState(Busy);
|
2022-02-01 03:30:09 +00:00
|
|
|
|
mainApp->popStatus(MainApplication::FilterSyntax);
|
2018-12-05 23:37:27 +00:00
|
|
|
|
setToolTip(QString());
|
2016-01-07 17:27:13 +00:00
|
|
|
|
bool empty = filter.isEmpty();
|
2013-08-08 00:26:57 +00:00
|
|
|
|
|
2016-02-23 18:04:16 +00:00
|
|
|
|
setConflict(false);
|
2015-06-03 23:26:00 +00:00
|
|
|
|
if (bookmark_button_) {
|
2016-01-27 20:33:24 +00:00
|
|
|
|
bool match = false;
|
|
|
|
|
|
2019-11-04 14:43:16 +00:00
|
|
|
|
FilterListModel model(FilterListModel::Capture);
|
|
|
|
|
QModelIndex idx = model.findByExpression(text());
|
2019-11-17 19:02:20 +00:00
|
|
|
|
if (idx.isValid()) {
|
2019-11-04 14:43:16 +00:00
|
|
|
|
match = true;
|
2016-01-27 20:33:24 +00:00
|
|
|
|
|
|
|
|
|
bookmark_button_->setStockIcon("x-filter-matching-bookmark");
|
|
|
|
|
if (remove_action_) {
|
|
|
|
|
remove_action_->setData(text());
|
2019-11-04 14:43:16 +00:00
|
|
|
|
remove_action_->setEnabled(true);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2016-01-30 00:45:04 +00:00
|
|
|
|
bookmark_button_->setStockIcon("x-capture-filter-bookmark");
|
2016-01-27 20:33:24 +00:00
|
|
|
|
if (remove_action_) {
|
2019-11-04 14:43:16 +00:00
|
|
|
|
remove_action_->setEnabled(false);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enable_save_action_ = (!match && !filter.isEmpty());
|
|
|
|
|
if (save_action_) {
|
|
|
|
|
save_action_->setEnabled(false);
|
|
|
|
|
}
|
2015-06-03 23:26:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-08 00:26:57 +00:00
|
|
|
|
if (apply_button_) {
|
|
|
|
|
apply_button_->setEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-03 23:26:00 +00:00
|
|
|
|
if (clear_button_) {
|
|
|
|
|
clear_button_->setVisible(!empty);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-08 00:26:57 +00:00
|
|
|
|
if (empty) {
|
2016-01-07 17:27:13 +00:00
|
|
|
|
setFilterSyntaxState(filter, Empty, QString());
|
2013-08-08 00:26:57 +00:00
|
|
|
|
} else {
|
2021-04-04 13:09:50 +00:00
|
|
|
|
emit captureFilterChanged(filter);
|
2013-08-08 00:26:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CaptureFilterEdit::checkFilter()
|
|
|
|
|
{
|
|
|
|
|
checkFilter(text());
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-27 20:33:24 +00:00
|
|
|
|
void CaptureFilterEdit::updateBookmarkMenu()
|
|
|
|
|
{
|
|
|
|
|
if (!bookmark_button_)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QMenu *bb_menu = bookmark_button_->menu();
|
|
|
|
|
bb_menu->clear();
|
|
|
|
|
|
|
|
|
|
save_action_ = bb_menu->addAction(tr("Save this filter"));
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(save_action_, &QAction::triggered, this, &CaptureFilterEdit::saveFilter);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
remove_action_ = bb_menu->addAction(tr("Remove this filter"));
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(remove_action_, &QAction::triggered, this, &CaptureFilterEdit::removeFilter);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
QAction *manage_action = bb_menu->addAction(tr("Manage Capture Filters"));
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(manage_action, &QAction::triggered, this, &CaptureFilterEdit::showFilters);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
bb_menu->addSeparator();
|
|
|
|
|
|
2019-11-04 14:43:16 +00:00
|
|
|
|
FilterListModel model(FilterListModel::Capture);
|
|
|
|
|
QModelIndex idx = model.findByExpression(text());
|
|
|
|
|
|
|
|
|
|
int one_em = bb_menu->fontMetrics().height();
|
|
|
|
|
|
2019-11-17 19:02:20 +00:00
|
|
|
|
if (! actions_)
|
2019-11-04 14:43:16 +00:00
|
|
|
|
actions_ = new QActionGroup(this);
|
|
|
|
|
|
2019-11-17 19:02:20 +00:00
|
|
|
|
for (int row = 0; row < model.rowCount(); row++)
|
2019-11-04 14:43:16 +00:00
|
|
|
|
{
|
|
|
|
|
QModelIndex nameIdx = model.index(row, FilterListModel::ColumnName);
|
|
|
|
|
QString name = nameIdx.data().toString();
|
|
|
|
|
QString expr = model.index(row, FilterListModel::ColumnExpression).data().toString();
|
|
|
|
|
QString prep_text = QString("%1: %2").arg(name).arg(expr);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
|
|
|
|
|
prep_text = bb_menu->fontMetrics().elidedText(prep_text, Qt::ElideRight, one_em * 40);
|
2019-11-04 14:43:16 +00:00
|
|
|
|
QAction * prep_action = bb_menu->addAction(prep_text);
|
|
|
|
|
prep_action->setCheckable(true);
|
2019-11-17 19:02:20 +00:00
|
|
|
|
if (nameIdx == idx)
|
2019-11-04 14:43:16 +00:00
|
|
|
|
prep_action->setChecked(true);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
|
2019-11-04 14:43:16 +00:00
|
|
|
|
actions_->addAction(prep_action);
|
|
|
|
|
prep_action->setProperty("capture_filter", expr);
|
2018-12-21 19:03:34 +00:00
|
|
|
|
connect(prep_action, &QAction::triggered, this, &CaptureFilterEdit::prepareFilter);
|
2016-01-27 20:33:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkFilter();
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-01 17:00:19 +00:00
|
|
|
|
void CaptureFilterEdit::setFilterSyntaxState(QString filter, int state, QString err_msg)
|
2013-08-08 00:26:57 +00:00
|
|
|
|
{
|
|
|
|
|
if (filter.compare(text()) == 0) { // The user hasn't changed the filter
|
2016-01-01 17:00:19 +00:00
|
|
|
|
setSyntaxState((SyntaxState)state);
|
2016-01-05 14:39:05 +00:00
|
|
|
|
if (!err_msg.isEmpty()) {
|
2022-02-01 03:30:09 +00:00
|
|
|
|
mainApp->pushStatus(MainApplication::FilterSyntax, err_msg);
|
2018-12-05 23:37:27 +00:00
|
|
|
|
setToolTip(err_msg);
|
2013-08-08 00:26:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-07 17:27:13 +00:00
|
|
|
|
bool valid = (state != Invalid);
|
|
|
|
|
|
|
|
|
|
if (valid) {
|
2016-01-27 20:33:24 +00:00
|
|
|
|
if (save_action_) {
|
|
|
|
|
save_action_->setEnabled(enable_save_action_);
|
2015-06-03 23:26:00 +00:00
|
|
|
|
}
|
2013-08-08 00:26:57 +00:00
|
|
|
|
if (apply_button_) {
|
|
|
|
|
apply_button_->setEnabled(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit captureFilterSyntaxChanged(valid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CaptureFilterEdit::bookmarkClicked()
|
|
|
|
|
{
|
|
|
|
|
emit addBookmark(text());
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 18:15:14 +00:00
|
|
|
|
void CaptureFilterEdit::clearFilter()
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
emit textEdited(text());
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-19 11:14:57 +00:00
|
|
|
|
void CaptureFilterEdit::buildCompletionList(const QString &primitive_word, const QString &preamble _U_)
|
2015-05-19 17:18:54 +00:00
|
|
|
|
{
|
|
|
|
|
if (primitive_word.length() < 1) {
|
|
|
|
|
completion_model_->setStringList(QStringList());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Grab matching capture filters from our parent combo and from the
|
|
|
|
|
// saved capture filters file. Skip ones that look like single fields
|
|
|
|
|
// and assume they will be added below.
|
|
|
|
|
QStringList complex_list;
|
|
|
|
|
QComboBox *cf_combo = qobject_cast<QComboBox *>(parent());
|
|
|
|
|
if (cf_combo) {
|
|
|
|
|
for (int i = 0; i < cf_combo->count() ; i++) {
|
|
|
|
|
QString recent_filter = cf_combo->itemText(i);
|
|
|
|
|
|
|
|
|
|
if (isComplexFilter(recent_filter)) {
|
|
|
|
|
complex_list << recent_filter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-04 14:43:16 +00:00
|
|
|
|
FilterListModel model(FilterListModel::Capture);
|
|
|
|
|
for (int row = 0; row < model.rowCount(); row++)
|
|
|
|
|
{
|
|
|
|
|
QString saved_filter = model.index(row, FilterListModel::ColumnExpression).data().toString();
|
2015-05-19 17:18:54 +00:00
|
|
|
|
|
|
|
|
|
if (isComplexFilter(saved_filter) && !complex_list.contains(saved_filter)) {
|
|
|
|
|
complex_list << saved_filter;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-21 19:12:40 +00:00
|
|
|
|
// libpcap has a small number of primitives so we just add the whole list
|
|
|
|
|
// sans the current word.
|
|
|
|
|
QStringList primitive_list = libpcap_primitives_;
|
|
|
|
|
primitive_list.removeAll(primitive_word);
|
|
|
|
|
|
|
|
|
|
completion_model_->setStringList(complex_list + primitive_list);
|
2015-05-19 17:18:54 +00:00
|
|
|
|
completer()->setCompletionPrefix(primitive_word);
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-08 00:26:57 +00:00
|
|
|
|
void CaptureFilterEdit::applyCaptureFilter()
|
|
|
|
|
{
|
|
|
|
|
if (syntaxState() == Invalid) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit startCapture();
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-27 20:33:24 +00:00
|
|
|
|
void CaptureFilterEdit::saveFilter()
|
|
|
|
|
{
|
2019-09-29 09:39:40 +00:00
|
|
|
|
FilterDialog *capture_filter_dlg = new FilterDialog(window(), FilterDialog::CaptureFilter, text());
|
|
|
|
|
capture_filter_dlg->setWindowModality(Qt::ApplicationModal);
|
|
|
|
|
capture_filter_dlg->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
capture_filter_dlg->show();
|
2016-01-27 20:33:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CaptureFilterEdit::removeFilter()
|
|
|
|
|
{
|
2019-12-09 10:18:43 +00:00
|
|
|
|
if (! actions_ || ! actions_->checkedAction())
|
2019-11-04 14:43:16 +00:00
|
|
|
|
return;
|
2016-01-27 20:33:24 +00:00
|
|
|
|
|
2019-11-04 14:43:16 +00:00
|
|
|
|
QAction *ra = actions_->checkedAction();
|
2019-11-17 19:02:20 +00:00
|
|
|
|
if (ra->property("capture_filter").toString().isEmpty())
|
2019-11-04 14:43:16 +00:00
|
|
|
|
return;
|
2016-01-27 20:33:24 +00:00
|
|
|
|
|
2019-11-04 14:43:16 +00:00
|
|
|
|
QString remove_filter = ra->property("capture_filter").toString();
|
2016-01-27 20:33:24 +00:00
|
|
|
|
|
2019-11-04 14:43:16 +00:00
|
|
|
|
FilterListModel model(FilterListModel::Capture);
|
|
|
|
|
QModelIndex idx = model.findByExpression(remove_filter);
|
2019-11-17 19:02:20 +00:00
|
|
|
|
if (idx.isValid())
|
2019-11-04 14:43:16 +00:00
|
|
|
|
{
|
|
|
|
|
model.removeFilter(idx);
|
|
|
|
|
model.saveList();
|
2016-01-27 20:33:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updateBookmarkMenu();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CaptureFilterEdit::showFilters()
|
|
|
|
|
{
|
2019-09-29 09:39:40 +00:00
|
|
|
|
FilterDialog *capture_filter_dlg = new FilterDialog(window(), FilterDialog::CaptureFilter);
|
|
|
|
|
capture_filter_dlg->setWindowModality(Qt::ApplicationModal);
|
|
|
|
|
capture_filter_dlg->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
|
capture_filter_dlg->show();
|
2016-01-27 20:33:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CaptureFilterEdit::prepareFilter()
|
|
|
|
|
{
|
|
|
|
|
QAction *pa = qobject_cast<QAction*>(sender());
|
2019-11-17 19:02:20 +00:00
|
|
|
|
if (! pa || pa->property("capture_filter").toString().isEmpty())
|
2019-11-04 14:43:16 +00:00
|
|
|
|
return;
|
2016-01-27 20:33:24 +00:00
|
|
|
|
|
2019-11-04 14:43:16 +00:00
|
|
|
|
QString filter = pa->property("capture_filter").toString();
|
2016-01-27 20:33:24 +00:00
|
|
|
|
setText(filter);
|
2019-11-04 14:43:16 +00:00
|
|
|
|
|
2016-01-27 20:33:24 +00:00
|
|
|
|
emit textEdited(filter);
|
|
|
|
|
}
|