summaryrefslogtreecommitdiffstats
path: root/ui/qt/manuf_dialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ui/qt/manuf_dialog.cpp210
1 files changed, 210 insertions, 0 deletions
diff --git a/ui/qt/manuf_dialog.cpp b/ui/qt/manuf_dialog.cpp
new file mode 100644
index 00000000..0c383af3
--- /dev/null
+++ b/ui/qt/manuf_dialog.cpp
@@ -0,0 +1,210 @@
+/*
+ * manuf_dialog.c
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <config.h>
+#include "manuf_dialog.h"
+#include <ui_manuf_dialog.h>
+
+#include <cstdio>
+#include <cstdint>
+#include <QComboBox>
+#include <QStandardItemModel>
+#include <QPushButton>
+#include <QRegularExpression>
+#include <QClipboard>
+#include <QAction>
+#include <QButtonGroup>
+#include <QCheckBox>
+
+#include "main_application.h"
+#include <epan/manuf.h>
+#include <epan/strutil.h>
+#include <wsutil/regex.h>
+#include <utils/qt_ui_utils.h>
+
+#define PLACEHOLDER_SEARCH_ADDR "Search address"
+#define PLACEHOLDER_SEARCH_NAME "Search name"
+
+ManufDialog::ManufDialog(QWidget &parent, CaptureFile &cf) :
+ WiresharkDialog(parent, cf),
+ ui(new Ui::ManufDialog)
+{
+ ui->setupUi(this);
+ loadGeometry();
+
+ model_ = new ManufTableModel(this);
+ proxy_model_ = new ManufSortFilterProxyModel(this);
+ proxy_model_->setSourceModel(model_);
+
+ ui->manufTableView->setModel(proxy_model_);
+ ui->manufTableView->setContextMenuPolicy(Qt::ActionsContextMenu);
+ ui->manufTableView->setColumnHidden(ManufTableModel::COL_SHORT_NAME, true);
+
+ QAction *select_action = new QAction(tr("Select all"), ui->manufTableView);
+ ui->manufTableView->addAction(select_action);
+ connect(select_action, &QAction::triggered, ui->manufTableView, &QTableView::selectAll);
+
+ QAction *copy_action = new QAction(tr("Copy"), ui->manufTableView);
+ ui->manufTableView->addAction(copy_action);
+ connect(copy_action, &QAction::triggered, this, &ManufDialog::copyToClipboard);
+
+ QPushButton *find_button = ui->buttonBox->addButton(tr("Find"), QDialogButtonBox::ActionRole);
+ find_button->setDefault(true);
+ connect(find_button, &QPushButton::clicked, this, &ManufDialog::on_editingFinished);
+
+ QPushButton *clear_button = ui->buttonBox->addButton(tr("Clear"), QDialogButtonBox::ActionRole);
+ connect(clear_button, &QPushButton::clicked, this, &ManufDialog::clearFilter);
+
+ QPushButton *copy_button = ui->buttonBox->addButton(tr("Copy"), QDialogButtonBox::ApplyRole);
+ connect(copy_button, &QPushButton::clicked, this, &ManufDialog::copyToClipboard);
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ connect(ui->radioButtonGroup, &QButtonGroup::buttonClicked, this, &ManufDialog::on_searchToggled);
+ connect(ui->radioButtonGroup, &QButtonGroup::buttonClicked, this, &ManufDialog::on_editingFinished);
+#else
+ connect(ui->radioButtonGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &ManufDialog::on_searchToggled);
+ connect(ui->radioButtonGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &ManufDialog::on_editingFinished);
+#endif
+ connect(ui->checkShortNameButton, &QCheckBox::stateChanged, this, &ManufDialog::on_shortNameStateChanged);
+
+ ui->manufLineEdit->setPlaceholderText(tr(PLACEHOLDER_SEARCH_ADDR));
+
+ ui->hintLabel->clear();
+}
+
+ManufDialog::~ManufDialog()
+{
+ delete ui;
+}
+
+void ManufDialog::searchVendor(QString &text)
+{
+ QRegularExpression name_re;
+
+ name_re = QRegularExpression(text, QRegularExpression::CaseInsensitiveOption);
+ if (!name_re.isValid()) {
+ ui->hintLabel->setText(QString("<small><i>Invalid regular expression: %1</i></small>").arg(name_re.errorString()));
+ return;
+ }
+
+ proxy_model_->setFilterName(name_re);
+ ui->hintLabel->setText(QString("<small><i>Found %1 matches for \"%2\"</i></small>").arg(proxy_model_->rowCount()).arg(text));
+}
+
+static QByteArray convertMacAddressToByteArray(const QString &bytesString)
+{
+ GByteArray *bytes = g_byte_array_new();
+
+ if (!hex_str_to_bytes(qUtf8Printable(bytesString), bytes, FALSE)
+ || bytes->len == 0 || bytes->len > 6) {
+ g_byte_array_free(bytes, TRUE);
+ return QByteArray();
+ }
+
+ /* Mask out multicast/locally administered flags. */
+ bytes->data[0] &= 0xFC;
+
+ return gbytearray_free_to_qbytearray(bytes);
+}
+
+QString convertToMacAddress(const QByteArray& byteArray) {
+ QString macAddress;
+ for (int i = 0; i < byteArray.size(); ++i) {
+ macAddress += QString("%1").arg(static_cast<quint8>(byteArray[i]), 2, 16, QChar('0'));
+ if (i != byteArray.size() - 1) {
+ macAddress += ":";
+ }
+ }
+ return macAddress.toUpper();
+}
+
+void ManufDialog::searchPrefix(QString &text)
+{
+ QByteArray addr;
+
+ addr = convertMacAddressToByteArray(text);
+ if (addr.isEmpty()) {
+ ui->hintLabel->setText(QString("<small><i>\"%1\" is not a valid MAC address</i></small>").arg(text));
+ return;
+ }
+
+ proxy_model_->setFilterAddress(addr);
+ ui->hintLabel->setText(QString("<small><i>Found %1 matches for \"%2\"</i></small>").arg(proxy_model_->rowCount()).arg(convertToMacAddress(addr)));
+}
+
+void ManufDialog::on_searchToggled(void)
+{
+ if (ui->ouiRadioButton->isChecked())
+ ui->manufLineEdit->setPlaceholderText(tr(PLACEHOLDER_SEARCH_ADDR));
+ else if (ui->vendorRadioButton->isChecked())
+ ui->manufLineEdit->setPlaceholderText(tr(PLACEHOLDER_SEARCH_NAME));
+ else
+ ws_assert_not_reached();
+}
+
+void ManufDialog::on_editingFinished(void)
+{
+ QString text = ui->manufLineEdit->text();
+
+ if (text.isEmpty())
+ return;
+
+ if (ui->ouiRadioButton->isChecked())
+ searchPrefix(text);
+ else if (ui->vendorRadioButton->isChecked())
+ searchVendor(text);
+ else
+ ws_assert_not_reached();
+}
+
+void ManufDialog::on_shortNameStateChanged(int state)
+{
+ ui->manufTableView->setColumnHidden(ManufTableModel::COL_SHORT_NAME, state ? false : true);
+}
+
+void ManufDialog::clearFilter()
+{
+ proxy_model_->clearFilter();
+ ui->manufLineEdit->clear();
+ ui->hintLabel->clear();
+}
+
+void ManufDialog::copyToClipboard() {
+ QModelIndexList selectedIndexes = ui->manufTableView->selectionModel()->selectedIndexes();
+
+ std::sort(selectedIndexes.begin(), selectedIndexes.end(), [](const QModelIndex &a, const QModelIndex &b) {
+ return a.row() < b.row() || (a.row() == b.row() && a.column() < b.column());
+ });
+
+ QAbstractItemModel *model = ui->manufTableView->model();
+ QString copiedData;
+
+ int previousRow = -1;
+
+ for (const QModelIndex& selectedIndex : selectedIndexes) {
+ // If the row changed, add a newline character
+ if (selectedIndex.row() != previousRow) {
+ if (!copiedData.isEmpty()) {
+ copiedData += "\n";
+ }
+ previousRow = selectedIndex.row();
+ }
+ else {
+ // If not the first column in the row, add a tab character
+ copiedData += "\t";
+ }
+
+ // Add the cell data to the string
+ copiedData += model->data(selectedIndex).toString();
+ }
+
+ QClipboard *clipboard = QApplication::clipboard();
+ clipboard->setText(copiedData);
+}