summaryrefslogtreecommitdiffstats
path: root/ui/qt/search_frame.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 20:34:10 +0000
commite4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch)
tree68cb5ef9081156392f1dd62a00c6ccc1451b93df /ui/qt/search_frame.cpp
parentInitial commit. (diff)
downloadwireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.tar.xz
wireshark-e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc.zip
Adding upstream version 4.2.2.upstream/4.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ui/qt/search_frame.cpp')
-rw-r--r--ui/qt/search_frame.cpp532
1 files changed, 532 insertions, 0 deletions
diff --git a/ui/qt/search_frame.cpp b/ui/qt/search_frame.cpp
new file mode 100644
index 00000000..95a5b8e8
--- /dev/null
+++ b/ui/qt/search_frame.cpp
@@ -0,0 +1,532 @@
+/* search_frame.cpp
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "search_frame.h"
+#include <ui_search_frame.h>
+
+#include "file.h"
+#include "ui/recent.h"
+
+#include <epan/proto.h>
+#include <epan/strutil.h>
+
+#include <wsutil/utf8_entities.h>
+#include <wsutil/regex.h>
+
+#include "main_application.h"
+#include <QKeyEvent>
+#include <QCheckBox>
+
+enum {
+ in_packet_list_,
+ in_proto_tree_,
+ in_bytes_
+};
+
+enum {
+ df_search_,
+ hex_search_,
+ string_search_,
+ regex_search_
+};
+
+enum {
+ narrow_and_wide_chars_,
+ narrow_chars_,
+ wide_chars_
+};
+
+SearchFrame::SearchFrame(QWidget *parent) :
+ AccordionFrame(parent),
+ sf_ui_(new Ui::SearchFrame),
+ cap_file_(nullptr),
+ regex_(nullptr)
+{
+ sf_ui_->setupUi(this);
+
+#ifdef Q_OS_MAC
+ foreach (QWidget *w, findChildren<QWidget *>()) {
+ w->setAttribute(Qt::WA_MacSmallSize, true);
+ }
+#endif
+
+ applyRecentSearchSettings();
+
+ updateWidgets();
+}
+
+SearchFrame::~SearchFrame()
+{
+ if (regex_) {
+ ws_regex_free(regex_);
+ }
+ delete sf_ui_;
+}
+
+void SearchFrame::animatedShow()
+{
+ AccordionFrame::animatedShow();
+
+ sf_ui_->searchLineEdit->setFocus();
+}
+
+void SearchFrame::findNext()
+{
+ if (!cap_file_) return;
+
+ cap_file_->dir = SD_FORWARD;
+ if (isHidden()) {
+ animatedShow();
+ return;
+ }
+ on_findButton_clicked();
+}
+
+void SearchFrame::findPrevious()
+{
+ if (!cap_file_) return;
+
+ cap_file_->dir = SD_BACKWARD;
+ if (isHidden()) {
+ animatedShow();
+ return;
+ }
+ on_findButton_clicked();
+}
+
+void SearchFrame::setFocus()
+{
+ sf_ui_->searchLineEdit->setFocus();
+ sf_ui_->searchLineEdit->selectAll();
+ cap_file_->dir = SD_FORWARD;
+}
+
+void SearchFrame::setCaptureFile(capture_file *cf)
+{
+ cap_file_ = cf;
+ if (!cf && isVisible()) {
+ animatedHide();
+ }
+ updateWidgets();
+}
+
+void SearchFrame::findFrameWithFilter(QString &filter)
+{
+ animatedShow();
+ sf_ui_->searchLineEdit->setText(filter);
+ sf_ui_->searchLineEdit->setCursorPosition(0);
+ sf_ui_->searchTypeComboBox->setCurrentIndex(df_search_);
+ updateWidgets();
+ on_findButton_clicked();
+}
+
+void SearchFrame::keyPressEvent(QKeyEvent *event)
+{
+ if (event->modifiers() == Qt::NoModifier) {
+ if (event->key() == Qt::Key_Escape) {
+ on_cancelButton_clicked();
+ } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
+ on_findButton_clicked();
+ }
+ }
+
+ AccordionFrame::keyPressEvent(event);
+}
+
+bool SearchFrame::regexCompile()
+{
+ unsigned flags = 0;
+ if (!sf_ui_->caseCheckBox->isChecked()) {
+ flags |= WS_REGEX_CASELESS;
+ }
+
+ if (regex_) {
+ ws_regex_free(regex_);
+ }
+
+ if (sf_ui_->searchLineEdit->text().isEmpty()) {
+ regex_ = nullptr;
+ return false;
+ }
+
+ char *errmsg = nullptr;
+ regex_ = ws_regex_compile_ex(sf_ui_->searchLineEdit->text().toUtf8().constData(), -1,
+ &errmsg, flags);
+
+ if (errmsg != nullptr) {
+ regex_error_ = errmsg;
+ }
+
+ return regex_ ? true : false;
+}
+
+void SearchFrame::applyRecentSearchSettings()
+{
+ int search_in_idx = in_packet_list_;
+ int char_encoding_idx = narrow_and_wide_chars_;
+ int search_type_idx = df_search_;
+
+ switch (recent.gui_search_in) {
+ case SEARCH_IN_PACKET_LIST:
+ search_in_idx = in_packet_list_;
+ break;
+ case SEARCH_IN_PACKET_DETAILS:
+ search_in_idx = in_proto_tree_;
+ break;
+ case SEARCH_IN_PACKET_BYTES:
+ search_in_idx = in_bytes_;
+ break;
+ default:
+ break;
+ }
+
+ switch (recent.gui_search_char_set) {
+ case SEARCH_CHAR_SET_NARROW_AND_WIDE:
+ char_encoding_idx = narrow_and_wide_chars_;
+ break;
+ case SEARCH_CHAR_SET_NARROW:
+ char_encoding_idx = narrow_chars_;
+ break;
+ case SEARCH_CHAR_SET_WIDE:
+ char_encoding_idx = wide_chars_;
+ break;
+ default:
+ break;
+ }
+
+ switch (recent.gui_search_type) {
+ case SEARCH_TYPE_DISPLAY_FILTER:
+ search_type_idx = df_search_;
+ break;
+ case SEARCH_TYPE_HEX_VALUE:
+ search_type_idx = hex_search_;
+ break;
+ case SEARCH_TYPE_STRING:
+ search_type_idx = string_search_;
+ break;
+ case SEARCH_TYPE_REGEX:
+ search_type_idx = regex_search_;
+ break;
+ default:
+ break;
+ }
+
+ sf_ui_->searchInComboBox->setCurrentIndex(search_in_idx);
+ sf_ui_->charEncodingComboBox->setCurrentIndex(char_encoding_idx);
+ sf_ui_->caseCheckBox->setChecked(recent.gui_search_case_sensitive);
+ sf_ui_->searchTypeComboBox->setCurrentIndex(search_type_idx);
+}
+
+void SearchFrame::updateWidgets()
+{
+ if (cap_file_) {
+ setEnabled(true);
+ } else {
+ setEnabled(false);
+ return;
+ }
+
+ int search_type = sf_ui_->searchTypeComboBox->currentIndex();
+ sf_ui_->searchInComboBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
+ sf_ui_->caseCheckBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
+ sf_ui_->charEncodingComboBox->setEnabled(search_type == string_search_);
+
+ switch (search_type) {
+ case df_search_:
+ sf_ui_->searchLineEdit->checkDisplayFilter(sf_ui_->searchLineEdit->text());
+ break;
+ case hex_search_:
+ if (sf_ui_->searchLineEdit->text().isEmpty()) {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
+ } else {
+ guint8 *bytes;
+ size_t nbytes;
+ bytes = convert_string_to_hex(sf_ui_->searchLineEdit->text().toUtf8().constData(), &nbytes);
+ if (bytes == nullptr)
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
+ else {
+ g_free(bytes);
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
+ }
+ }
+ break;
+ case string_search_:
+ if (sf_ui_->searchLineEdit->text().isEmpty()) {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
+ } else {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
+ }
+ break;
+ case regex_search_:
+ if (regexCompile()) {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
+ } else {
+ sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
+ }
+ break;
+ default:
+ // currentIndex is probably -1. Nothing is selected or list is empty.
+ return;
+ }
+
+ if (sf_ui_->searchLineEdit->text().isEmpty() || sf_ui_->searchLineEdit->syntaxState() == SyntaxLineEdit::Invalid) {
+ sf_ui_->findButton->setEnabled(false);
+ } else {
+ sf_ui_->findButton->setEnabled(true);
+ }
+}
+
+void SearchFrame::on_searchInComboBox_currentIndexChanged(int idx)
+{
+ switch (idx) {
+ case in_packet_list_:
+ recent.gui_search_in = SEARCH_IN_PACKET_LIST;
+ break;
+ case in_proto_tree_:
+ recent.gui_search_in = SEARCH_IN_PACKET_DETAILS;
+ break;
+ case in_bytes_:
+ recent.gui_search_in = SEARCH_IN_PACKET_BYTES;
+ break;
+ default:
+ break;
+ }
+}
+
+void SearchFrame::on_charEncodingComboBox_currentIndexChanged(int idx)
+{
+ switch (idx) {
+ case narrow_and_wide_chars_:
+ recent.gui_search_char_set = SEARCH_CHAR_SET_NARROW_AND_WIDE;
+ break;
+ case narrow_chars_:
+ recent.gui_search_char_set = SEARCH_CHAR_SET_NARROW;
+ break;
+ case wide_chars_:
+ recent.gui_search_char_set = SEARCH_CHAR_SET_WIDE;
+ break;
+ default:
+ break;
+ }
+}
+
+void SearchFrame::on_caseCheckBox_toggled(bool checked)
+{
+ recent.gui_search_case_sensitive = checked;
+ regexCompile();
+}
+
+void SearchFrame::on_searchTypeComboBox_currentIndexChanged(int idx)
+{
+ switch (idx) {
+ case df_search_:
+ recent.gui_search_type = SEARCH_TYPE_DISPLAY_FILTER;
+ break;
+ case hex_search_:
+ recent.gui_search_type = SEARCH_TYPE_HEX_VALUE;
+ break;
+ case string_search_:
+ recent.gui_search_type = SEARCH_TYPE_STRING;
+ break;
+ case regex_search_:
+ recent.gui_search_type = SEARCH_TYPE_REGEX;
+ break;
+ default:
+ break;
+ }
+
+ // Enable completion only for display filter search.
+ sf_ui_->searchLineEdit->allowCompletion(idx == df_search_);
+
+ if (idx == df_search_) {
+ sf_ui_->searchLineEdit->checkFilter();
+ } else {
+ sf_ui_->searchLineEdit->setToolTip(QString());
+ mainApp->popStatus(MainApplication::FilterSyntax);
+ }
+
+ updateWidgets();
+}
+
+void SearchFrame::on_searchLineEdit_textChanged(const QString &)
+{
+ updateWidgets();
+}
+
+void SearchFrame::on_findButton_clicked()
+{
+ guint8 *bytes = nullptr;
+ size_t nbytes = 0;
+ char *string = nullptr;
+ dfilter_t *dfp = nullptr;
+ gboolean found_packet = FALSE;
+ QString err_string;
+
+ if (!cap_file_) {
+ return;
+ }
+
+ cap_file_->hex = FALSE;
+ cap_file_->string = FALSE;
+ cap_file_->case_type = FALSE;
+ cap_file_->regex = nullptr;
+ cap_file_->packet_data = FALSE;
+ cap_file_->decode_data = FALSE;
+ cap_file_->summary_data = FALSE;
+ cap_file_->scs_type = SCS_NARROW_AND_WIDE;
+
+ int search_type = sf_ui_->searchTypeComboBox->currentIndex();
+ switch (search_type) {
+ case df_search_:
+ if (!dfilter_compile(sf_ui_->searchLineEdit->text().toUtf8().constData(), &dfp, nullptr)) {
+ err_string = tr("Invalid filter.");
+ goto search_done;
+ }
+
+ if (dfp == nullptr) {
+ err_string = tr("That filter doesn't test anything.");
+ goto search_done;
+ }
+ break;
+ case hex_search_:
+ bytes = convert_string_to_hex(sf_ui_->searchLineEdit->text().toUtf8().constData(), &nbytes);
+ if (bytes == nullptr) {
+ err_string = tr("That's not a valid hex string.");
+ goto search_done;
+ }
+ cap_file_->hex = TRUE;
+ break;
+ case string_search_:
+ case regex_search_:
+ if (sf_ui_->searchLineEdit->text().isEmpty()) {
+ err_string = tr("You didn't specify any text for which to search.");
+ goto search_done;
+ }
+ cap_file_->string = TRUE;
+ cap_file_->case_type = sf_ui_->caseCheckBox->isChecked() ? FALSE : TRUE;
+ cap_file_->regex = (search_type == regex_search_ ? regex_ : nullptr);
+ switch (sf_ui_->charEncodingComboBox->currentIndex()) {
+ case narrow_and_wide_chars_:
+ cap_file_->scs_type = SCS_NARROW_AND_WIDE;
+ break;
+ case narrow_chars_:
+ cap_file_->scs_type = SCS_NARROW;
+ break;
+ case wide_chars_:
+ cap_file_->scs_type = SCS_WIDE;
+ break;
+ default:
+ err_string = tr("No valid character set selected. Please report this to the development team.");
+ goto search_done;
+ }
+ string = convert_string_case(sf_ui_->searchLineEdit->text().toUtf8().constData(), cap_file_->case_type);
+ break;
+ default:
+ err_string = tr("No valid search type selected. Please report this to the development team.");
+ goto search_done;
+ }
+
+ switch (sf_ui_->searchInComboBox->currentIndex()) {
+ case in_packet_list_:
+ cap_file_->summary_data = TRUE;
+ break;
+ case in_proto_tree_:
+ cap_file_->decode_data = TRUE;
+ break;
+ case in_bytes_:
+ cap_file_->packet_data = TRUE;
+ break;
+ default:
+ err_string = tr("No valid search area selected. Please report this to the development team.");
+ goto search_done;
+ }
+
+ g_free(cap_file_->sfilter);
+ cap_file_->sfilter = g_strdup(sf_ui_->searchLineEdit->text().toUtf8().constData());
+ mainApp->popStatus(MainApplication::FileStatus);
+ mainApp->pushStatus(MainApplication::FileStatus, tr("Searching for %1…").arg(sf_ui_->searchLineEdit->text()));
+
+ if (cap_file_->hex) {
+ /* Hex value in packet data */
+ found_packet = cf_find_packet_data(cap_file_, bytes, nbytes, cap_file_->dir);
+ g_free(bytes);
+ if (!found_packet) {
+ /* We didn't find a packet */
+ err_string = tr("No packet contained those bytes.");
+ goto search_done;
+ }
+ } else if (cap_file_->string) {
+ if (search_type == regex_search_ && !cap_file_->regex) {
+ err_string = regex_error_;
+ goto search_done;
+ }
+ if (cap_file_->summary_data) {
+ /* String in the Info column of the summary line */
+ found_packet = cf_find_packet_summary_line(cap_file_, string, cap_file_->dir);
+ g_free(string);
+ if (!found_packet) {
+ err_string = tr("No packet contained that string in its Info column.");
+ goto search_done;
+ }
+ } else if (cap_file_->decode_data) {
+ /* String in the protocol tree headings */
+ found_packet = cf_find_packet_protocol_tree(cap_file_, string, cap_file_->dir);
+ g_free(string);
+ if (!found_packet) {
+ err_string = tr("No packet contained that string in its dissected display.");
+ goto search_done;
+ }
+ } else if (cap_file_->packet_data && string) {
+ /* String in the ASCII-converted packet data */
+ found_packet = cf_find_packet_data(cap_file_, (guint8 *) string, strlen(string), cap_file_->dir);
+ g_free(string);
+ if (!found_packet) {
+ err_string = tr("No packet contained that string in its converted data.");
+ goto search_done;
+ }
+ }
+ } else {
+ /* Search via display filter */
+ found_packet = cf_find_packet_dfilter(cap_file_, dfp, cap_file_->dir);
+ dfilter_free(dfp);
+ if (!found_packet) {
+ err_string = tr("No packet matched that filter.");
+ g_free(bytes);
+ goto search_done;
+ }
+ }
+
+ search_done:
+ mainApp->popStatus(MainApplication::FileStatus);
+ if (!err_string.isEmpty()) {
+ mainApp->pushStatus(MainApplication::FilterSyntax, err_string);
+ }
+}
+
+void SearchFrame::on_cancelButton_clicked()
+{
+ mainApp->popStatus(MainApplication::FilterSyntax);
+ animatedHide();
+}
+
+void SearchFrame::changeEvent(QEvent* event)
+{
+ if (event)
+ {
+ switch (event->type())
+ {
+ case QEvent::LanguageChange:
+ sf_ui_->retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+ }
+ AccordionFrame::changeEvent(event);
+}