diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:34:10 +0000 |
commit | e4ba6dbc3f1e76890b22773807ea37fe8fa2b1bc (patch) | |
tree | 68cb5ef9081156392f1dd62a00c6ccc1451b93df /ui/qt/bluetooth_hci_summary_dialog.cpp | |
parent | Initial commit. (diff) | |
download | wireshark-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/bluetooth_hci_summary_dialog.cpp')
-rw-r--r-- | ui/qt/bluetooth_hci_summary_dialog.cpp | 935 |
1 files changed, 935 insertions, 0 deletions
diff --git a/ui/qt/bluetooth_hci_summary_dialog.cpp b/ui/qt/bluetooth_hci_summary_dialog.cpp new file mode 100644 index 00000000..15d2df5e --- /dev/null +++ b/ui/qt/bluetooth_hci_summary_dialog.cpp @@ -0,0 +1,935 @@ +/* bluetooth_hci_summary_dialog.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "bluetooth_hci_summary_dialog.h" +#include <ui_bluetooth_hci_summary_dialog.h> + +#include "bluetooth_device_dialog.h" + +#include <ui/qt/utils/color_utils.h> + +#include "epan/epan.h" +#include "epan/addr_resolv.h" +#include "epan/to_str.h" +#include "epan/epan_dissect.h" +#include "epan/prefs.h" +#include "epan/dissectors/packet-bluetooth.h" +#include "epan/dissectors/packet-bthci_cmd.h" +#include "epan/dissectors/packet-bthci_evt.h" + +#include <ui/qt/utils/variant_pointer.h> + +#include "ui/simple_dialog.h" +#include "ui/qt/widgets/wireshark_file_dialog.h" + +#include <QClipboard> +#include <QContextMenuEvent> +#include <QPushButton> +#include <QTreeWidget> + +static const int column_number_name = 0; +static const int column_number_ogf = 1; +static const int column_number_ocf = 2; +static const int column_number_opcode = 3; +static const int column_number_event = 4; +static const int column_number_subevent = 5; +static const int column_number_status = 6; +static const int column_number_reason = 7; +static const int column_number_hardware_error = 8; +static const int column_number_occurrence = 9; + +static tap_packet_status +bluetooth_hci_summary_tap_packet(void *tapinfo_ptr, packet_info *pinfo, epan_dissect_t *edt, const void* data, tap_flags_t flags) +{ + bluetooth_hci_summary_tapinfo_t *tapinfo = (bluetooth_hci_summary_tapinfo_t *) tapinfo_ptr; + + if (tapinfo->tap_packet) + tapinfo->tap_packet(tapinfo, pinfo, edt, data, flags); + + return TAP_PACKET_REDRAW; +} + +static void +bluetooth_hci_summary_tap_reset(void *tapinfo_ptr) +{ + bluetooth_hci_summary_tapinfo_t *tapinfo = (bluetooth_hci_summary_tapinfo_t *) tapinfo_ptr; + + if (tapinfo->tap_reset) + tapinfo->tap_reset(tapinfo); +} + +static void +bluetooth_hci_summary_tap_init(void *data) +{ + GString *error_string; + + error_string = register_tap_listener("bluetooth.hci_summary", data, NULL, + 0, + bluetooth_hci_summary_tap_reset, + bluetooth_hci_summary_tap_packet, + NULL, + NULL + ); + + if (error_string != NULL) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "%s", error_string->str); + g_string_free(error_string, TRUE); + } +} + + +BluetoothHciSummaryDialog::BluetoothHciSummaryDialog(QWidget &parent, CaptureFile &cf) : + WiresharkDialog(parent, cf), + ui(new Ui::BluetoothHciSummaryDialog) +{ + ui->setupUi(this); + loadGeometry(parent.width() * 4 / 5, parent.height() * 2 / 3); + + connect(ui->tableTreeWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(tableContextMenu(const QPoint &))); + connect(ui->tableTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem *)), this, SLOT(tableItemExpanded(QTreeWidgetItem *))); + connect(ui->tableTreeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem *)), this, SLOT(tableItemCollapsed(QTreeWidgetItem *))); + + connect(ui->interfaceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(interfaceCurrentIndexChanged(int))); + connect(ui->adapterComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(adapterCurrentIndexChanged(int))); + connect(ui->displayFilterLineEdit, SIGNAL(returnPressed()), this, SLOT(displayFilterLineEditAccepted())); + connect(ui->resultsFilterLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(resultsFilterLineEditChanged(const QString &))); + + for (int i = 0; i < ui->tableTreeWidget->columnCount(); i++) { + ui->tableTreeWidget->resizeColumnToContents(i); + } + + ui->tableTreeWidget->setStyleSheet("QTreeView::item:hover{background-color:lightyellow; color:black;}"); + + context_menu_.addActions(QList<QAction *>() << ui->actionMark_Unmark_Cell); + context_menu_.addActions(QList<QAction *>() << ui->actionMark_Unmark_Row); + context_menu_.addActions(QList<QAction *>() << ui->actionCopy_Cell); + context_menu_.addActions(QList<QAction *>() << ui->actionCopy_Rows); + context_menu_.addActions(QList<QAction *>() << ui->actionCopy_All); + context_menu_.addActions(QList<QAction *>() << ui->actionSave_as_image); + + tapinfo_.tap_packet = tapPacket; + tapinfo_.tap_reset = tapReset; + tapinfo_.ui = this; + + item_link_control_ = ui->tableTreeWidget->topLevelItem(0); + item_link_policy_ = ui->tableTreeWidget->topLevelItem(1); + item_controller_and_baseband_ = ui->tableTreeWidget->topLevelItem(2); + item_informational_ = ui->tableTreeWidget->topLevelItem(3); + item_status_parameters_ = ui->tableTreeWidget->topLevelItem(4); + item_testing_ = ui->tableTreeWidget->topLevelItem(5); + item_low_energy_ = ui->tableTreeWidget->topLevelItem(6); + item_logo_testing_ = ui->tableTreeWidget->topLevelItem(7); + item_vendor_ = ui->tableTreeWidget->topLevelItem(8); + item_unknown_ogf_ = ui->tableTreeWidget->topLevelItem(9); + item_events_ = ui->tableTreeWidget->topLevelItem(10); + item_status_ = ui->tableTreeWidget->topLevelItem(11); + item_reason_ = ui->tableTreeWidget->topLevelItem(12); + item_hardware_errors_ = ui->tableTreeWidget->topLevelItem(13); + + bluetooth_hci_summary_tap_init(&tapinfo_); + + cap_file_.retapPackets(); +} + + +BluetoothHciSummaryDialog::~BluetoothHciSummaryDialog() +{ + delete ui; + + remove_tap_listener(&tapinfo_); +} + + +void BluetoothHciSummaryDialog::captureFileClosing() +{ + remove_tap_listener(&tapinfo_); + + WiresharkDialog::captureFileClosing(); +} + + +void BluetoothHciSummaryDialog::captureFileClosed() +{ + ui->interfaceComboBox->setEnabled(FALSE); + ui->adapterComboBox->setEnabled(FALSE); + + WiresharkDialog::captureFileClosed(); +} + + +void BluetoothHciSummaryDialog::changeEvent(QEvent *event) +{ + if (0 != event) + { + switch (event->type()) + { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } + } + QDialog::changeEvent(event); +} + + +void BluetoothHciSummaryDialog::keyPressEvent(QKeyEvent *event) +{ +/* NOTE: Do nothing*, but in real it "takes focus" from button_box so allow user + * to use Enter button to jump to frame from tree widget */ +/* * - reimplement shortcuts from contex menu */ + + if (event->modifiers() & Qt::ControlModifier && event->key()== Qt::Key_M) + on_actionMark_Unmark_Row_triggered(); +} + + +void BluetoothHciSummaryDialog::tableContextMenu(const QPoint &pos) +{ + context_menu_.popup(ui->tableTreeWidget->viewport()->mapToGlobal(pos)); +} + +void BluetoothHciSummaryDialog::tableItemExpanded(QTreeWidgetItem *) +{ + for (int i = 0; i < ui->tableTreeWidget->columnCount(); i++) { + ui->tableTreeWidget->resizeColumnToContents(i); + } +} + +void BluetoothHciSummaryDialog::tableItemCollapsed(QTreeWidgetItem *) +{ + for (int i = 0; i < ui->tableTreeWidget->columnCount(); i++) { + ui->tableTreeWidget->resizeColumnToContents(i); + } +} + +void BluetoothHciSummaryDialog::on_actionMark_Unmark_Cell_triggered() +{ + QBrush fg; + QBrush bg; + + if (ui->tableTreeWidget->currentItem()->background(ui->tableTreeWidget->currentColumn()) == QBrush(ColorUtils::fromColorT(&prefs.gui_marked_bg))) { + fg = QBrush(); + bg = QBrush(); + } else { + fg = QBrush(ColorUtils::fromColorT(&prefs.gui_marked_fg)); + bg = QBrush(ColorUtils::fromColorT(&prefs.gui_marked_bg)); + } + + ui->tableTreeWidget->currentItem()->setForeground(ui->tableTreeWidget->currentColumn(), fg); + ui->tableTreeWidget->currentItem()->setBackground(ui->tableTreeWidget->currentColumn(), bg); +} + +void BluetoothHciSummaryDialog::on_actionMark_Unmark_Row_triggered() +{ + QBrush fg; + QBrush bg; + bool is_marked = TRUE; + + for (int i = 0; i < ui->tableTreeWidget->columnCount(); i += 1) { + if (ui->tableTreeWidget->currentItem()->background(i) != QBrush(ColorUtils::fromColorT(&prefs.gui_marked_bg))) + is_marked = FALSE; + } + + if (is_marked) { + fg = QBrush(); + bg = QBrush(); + } else { + fg = QBrush(ColorUtils::fromColorT(&prefs.gui_marked_fg)); + bg = QBrush(ColorUtils::fromColorT(&prefs.gui_marked_bg)); + } + + for (int i = 0; i < ui->tableTreeWidget->columnCount(); i += 1) { + ui->tableTreeWidget->currentItem()->setForeground(i, fg); + ui->tableTreeWidget->currentItem()->setBackground(i, bg); + } +} + +void BluetoothHciSummaryDialog::on_actionCopy_Cell_triggered() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString copy; + + copy = QString(ui->tableTreeWidget->currentItem()->text(ui->tableTreeWidget->currentColumn())); + + clipboard->setText(copy); +} + + +void BluetoothHciSummaryDialog::on_actionCopy_Rows_triggered() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString copy; + QList<QTreeWidgetItem *> items; + QList<QTreeWidgetItem *>::iterator i_item; + + items = ui->tableTreeWidget->selectedItems(); + + for (i_item = items.begin(); i_item != items.end(); ++i_item) { + copy += QString("%1 %2 %3 %4 %5 %6 %7 %8 %9\n") + .arg((*i_item)->text(column_number_name), -60) + .arg((*i_item)->text(column_number_ogf), -10) + .arg((*i_item)->text(column_number_ocf), -10) + .arg((*i_item)->text(column_number_opcode), -10) + .arg((*i_item)->text(column_number_event), -10) + .arg((*i_item)->text(column_number_subevent), -10) + .arg((*i_item)->text(column_number_status), -10) + .arg((*i_item)->text(column_number_reason), -10) + .arg((*i_item)->text(column_number_hardware_error), -15) + .arg((*i_item)->text(column_number_occurrence), -10); + } + + clipboard->setText(copy); +} + +void BluetoothHciSummaryDialog::tapReset(void *tapinfo_ptr) +{ + bluetooth_hci_summary_tapinfo_t *tapinfo = (bluetooth_hci_summary_tapinfo_t *) tapinfo_ptr; + BluetoothHciSummaryDialog *dialog = static_cast<BluetoothHciSummaryDialog *>(tapinfo->ui); + + dialog->item_link_control_->takeChildren(); + dialog->item_link_control_->setText(column_number_occurrence, "0"); + + dialog->item_link_policy_->takeChildren(); + dialog->item_link_policy_->setText(column_number_occurrence, "0"); + + dialog->item_controller_and_baseband_->takeChildren(); + dialog->item_controller_and_baseband_->setText(column_number_occurrence, "0"); + + dialog->item_informational_->takeChildren(); + dialog->item_informational_->setText(column_number_occurrence, "0"); + + dialog->item_status_parameters_->takeChildren(); + dialog->item_status_parameters_->setText(column_number_occurrence, "0"); + + dialog->item_testing_->takeChildren(); + dialog->item_testing_->setText(column_number_occurrence, "0"); + + dialog->item_low_energy_->takeChildren(); + dialog->item_low_energy_->setText(column_number_occurrence, "0"); + + dialog->item_logo_testing_->takeChildren(); + dialog->item_logo_testing_->setText(column_number_occurrence, "0"); + + dialog->item_vendor_->takeChildren(); + dialog->item_vendor_->setText(column_number_occurrence, "0"); + + dialog->item_unknown_ogf_->takeChildren(); + dialog->item_unknown_ogf_->setText(column_number_occurrence, "0"); + + dialog->item_events_->takeChildren(); + dialog->item_events_->setText(column_number_occurrence, "0"); + + dialog->item_status_->takeChildren(); + dialog->item_status_->setText(column_number_occurrence, "0"); + + dialog->item_reason_->takeChildren(); + dialog->item_reason_->setText(column_number_occurrence, "0"); + + dialog->item_hardware_errors_->takeChildren(); + dialog->item_hardware_errors_->setText(column_number_occurrence, "0"); +} + +tap_packet_status BluetoothHciSummaryDialog::tapPacket(void *tapinfo_ptr, packet_info *pinfo, epan_dissect_t *, const void *data, tap_flags_t) +{ + bluetooth_hci_summary_tapinfo_t *tapinfo = static_cast<bluetooth_hci_summary_tapinfo_t *>(tapinfo_ptr); + BluetoothHciSummaryDialog *dialog = static_cast<BluetoothHciSummaryDialog *>(tapinfo->ui); + bluetooth_hci_summary_tap_t *tap_hci = static_cast<bluetooth_hci_summary_tap_t *>(const_cast<void *>(data)); + QTreeWidgetItem *main_item = NULL; + QTreeWidgetItem *item = NULL; + QTreeWidgetItem *frame_item = NULL; + QTreeWidgetItem *meta_item = NULL; + bluetooth_item_data_t *item_data = NULL; + QString adapter; + QString name; + + if (dialog->file_closed_) + return TAP_PACKET_DONT_REDRAW; + + if (pinfo->rec->rec_type != REC_TYPE_PACKET) + return TAP_PACKET_DONT_REDRAW; + + name = tr("Unknown"); + + if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) { + gchar *interface; + const char *interface_name; + + interface_name = epan_get_interface_name(pinfo->epan, pinfo->rec->rec_header.packet_header.interface_id); + interface = wmem_strdup_printf(pinfo->pool, "%u: %s", pinfo->rec->rec_header.packet_header.interface_id, interface_name); + + if (dialog->ui->interfaceComboBox->findText(interface) == -1) + dialog->ui->interfaceComboBox->addItem(interface); + + if (interface && dialog->ui->interfaceComboBox->currentIndex() > 0) { + if (dialog->ui->interfaceComboBox->currentText() != interface) + return TAP_PACKET_REDRAW; + } + } + + adapter = QString(tr("Adapter %1")).arg(tap_hci->adapter_id); + + if (dialog->ui->adapterComboBox->findText(adapter) == -1) { + dialog->ui->adapterComboBox->addItem(adapter); + } + + if (dialog->ui->adapterComboBox->currentIndex() > 0) { + if (dialog->ui->adapterComboBox->currentText() != adapter) + return TAP_PACKET_REDRAW; + } + + switch (tap_hci->type) { + case BLUETOOTH_HCI_SUMMARY_OPCODE: + case BLUETOOTH_HCI_SUMMARY_EVENT_OPCODE: + case BLUETOOTH_HCI_SUMMARY_VENDOR_OPCODE: + case BLUETOOTH_HCI_SUMMARY_VENDOR_EVENT_OPCODE: + switch (tap_hci->ogf) { + case HCI_OGF_LINK_CONTROL: + main_item = dialog->item_link_control_; + break; + case HCI_OGF_LINK_POLICY: + main_item = dialog->item_link_policy_; + break; + case HCI_OGF_HOST_CONTROLLER: + main_item = dialog->item_controller_and_baseband_; + break; + case HCI_OGF_INFORMATIONAL: + main_item = dialog->item_informational_; + break; + case HCI_OGF_STATUS: + main_item = dialog->item_status_parameters_; + break; + case HCI_OGF_TESTING: + main_item = dialog->item_testing_; + break; + case HCI_OGF_LOW_ENERGY: + main_item = dialog->item_low_energy_; + break; + case HCI_OGF_LOGO_TESTING: + main_item = dialog->item_logo_testing_; + break; + case HCI_OGF_VENDOR_SPECIFIC: + main_item = dialog->item_vendor_; + break; + default: + main_item = dialog->item_unknown_ogf_; + } + + for (int i_item = 0; i_item < main_item->childCount(); i_item +=1) { + if (main_item->child(i_item)->text(column_number_opcode) == + QString("0x%1").arg(tap_hci->ogf << 10 | tap_hci->ocf, 4, 16, QChar('0'))) { + item = main_item->child(i_item); + if (tap_hci->type == BLUETOOTH_HCI_SUMMARY_VENDOR_OPCODE && tap_hci->name) { + item->setText(column_number_name, tap_hci->name); + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() - 1)); + } + break; + } + } + + if (!item) { + item = new QTreeWidgetItem(); + if (tap_hci->name) + name = tap_hci->name; + + item->setText(column_number_name, name); + item->setText(column_number_ogf, QString("0x%1").arg(tap_hci->ogf, 2, 16, QChar('0'))); + item->setText(column_number_ocf, QString("0x%1").arg(tap_hci->ocf, 4, 16, QChar('0'))); + item->setText(column_number_opcode, + QString("0x%1").arg(tap_hci->ogf << 10 | tap_hci->ocf, 4, 16, QChar('0'))); + if (tap_hci->type == BLUETOOTH_HCI_SUMMARY_OPCODE) + item->setText(column_number_occurrence, "0"); + else + item->setText(column_number_occurrence, "1"); + + main_item->addChild(item); + item->setHidden(!name.contains(dialog->ui->resultsFilterLineEdit->text(), Qt::CaseInsensitive)); + main_item->sortChildren(column_number_opcode, Qt::AscendingOrder); + + main_item->setText(column_number_occurrence, QString::number(main_item->text(column_number_occurrence).toInt() + 1)); + } + + if (tap_hci->type != BLUETOOTH_HCI_SUMMARY_EVENT_OPCODE && tap_hci->type != BLUETOOTH_HCI_SUMMARY_VENDOR_EVENT_OPCODE) + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + + /* I believe bthci_cmd/bthci_evt already add frame item */ + if (tap_hci->type == BLUETOOTH_HCI_SUMMARY_VENDOR_OPCODE || + tap_hci->type == BLUETOOTH_HCI_SUMMARY_VENDOR_EVENT_OPCODE) + break; + + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Frame %1")).arg(pinfo->num)); + frame_item->setText(column_number_ogf, QString("0x%1").arg(tap_hci->ogf, 2, 16, QChar('0'))); + frame_item->setText(column_number_ocf, QString("0x%1").arg(tap_hci->ocf, 4, 16, QChar('0'))); + frame_item->setText(column_number_opcode, QString("0x%1") + .arg(tap_hci->ogf << 10 | tap_hci->ocf, 4, 16, QChar('0'))); + if (tap_hci->type == BLUETOOTH_HCI_SUMMARY_EVENT_OPCODE) + frame_item->setText(column_number_event, QString("0x%1").arg(tap_hci->event, 2, 16, QChar('0'))); + item->addChild(frame_item); + + item_data = wmem_new(wmem_file_scope(), bluetooth_item_data_t); + item_data->interface_id = tap_hci->interface_id; + item_data->adapter_id = tap_hci->adapter_id; + item_data->frame_number = pinfo->num; + frame_item->setData(0, Qt::UserRole, VariantPointer<bluetooth_item_data_t>::asQVariant(item_data)); + + break; + case BLUETOOTH_HCI_SUMMARY_EVENT: + case BLUETOOTH_HCI_SUMMARY_VENDOR_EVENT: + main_item = dialog->item_events_; + + for (int i_item = 0; i_item < main_item->childCount(); i_item +=1) { + if (main_item->child(i_item)->text(column_number_event) == + QString("0x%1").arg(tap_hci->event, 2, 16, QChar('0'))) { + item = main_item->child(i_item); + if (tap_hci->type == BLUETOOTH_HCI_SUMMARY_VENDOR_EVENT && tap_hci->name) + item->setText(column_number_name, tap_hci->name); + break; + } + } + + if (!item) { + item = new QTreeWidgetItem(); + if (tap_hci->name) + name = tap_hci->name; + + item->setText(column_number_name, name); + item->setText(column_number_event, QString("0x%1").arg(tap_hci->event, 2, 16, QChar('0'))); + item->setText(column_number_occurrence, QString::number(0)); + + main_item->addChild(item); + item->setHidden(!name.contains(dialog->ui->resultsFilterLineEdit->text(), Qt::CaseInsensitive)); + main_item->sortChildren(column_number_event, Qt::AscendingOrder); + main_item->setText(column_number_occurrence, QString::number(main_item->text(column_number_occurrence).toInt() + 1)); + } + + /* I believe bthci_cmd/bthci_evt already add frame item */ + if (tap_hci->type == BLUETOOTH_HCI_SUMMARY_VENDOR_EVENT) + break; + + if (tap_hci->event == 0x3E) { /* LE Meta */ + int i_item; + for (i_item = 0; i_item < item->childCount(); i_item +=1) { + if (item->child(i_item)->text(column_number_name) != QString(tr("Unknown"))) + continue; + } + + if (i_item >= item->childCount()) { + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Unknown"))); + frame_item->setText(column_number_occurrence, QString::number(1)); + item->addChild(frame_item); + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + + item = frame_item; + } else { + item = item->child(i_item); + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + } + } else { + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + } + + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Frame %1")).arg(pinfo->num)); + frame_item->setText(column_number_event, QString("0x%1").arg(tap_hci->event, 2, 16, QChar('0'))); + item->addChild(frame_item); + + item_data = wmem_new(wmem_file_scope(), bluetooth_item_data_t); + item_data->interface_id = tap_hci->interface_id; + item_data->adapter_id = tap_hci->adapter_id; + item_data->frame_number = pinfo->num; + frame_item->setData(0, Qt::UserRole, VariantPointer<bluetooth_item_data_t>::asQVariant(item_data)); + + break; + case BLUETOOTH_HCI_SUMMARY_SUBEVENT: + main_item = dialog->item_events_; + + meta_item = NULL; + + for (int i_item = 0; i_item < main_item->childCount(); i_item +=1) { + if (main_item->child(i_item)->text(column_number_event) != + QString("0x%1").arg(tap_hci->event, 2, 16, QChar('0'))) { + continue; + } + + meta_item = main_item->child(i_item); + break; + } + + if (meta_item == NULL) + break; + + item = NULL; + + for (int i_item = 0; i_item < meta_item->childCount(); i_item +=1) { + if (meta_item->child(i_item)->text(column_number_subevent) != + QString("0x%1").arg(tap_hci->subevent, 2, 16, QChar('0'))) { + continue; + } + + item = meta_item->child(i_item); + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + + break; + } + + if (item == NULL) { + item = new QTreeWidgetItem(); + item->setText(column_number_name, tap_hci->name); + item->setText(column_number_subevent, QString("0x%1").arg(tap_hci->subevent, 2, 16, QChar('0'))); + item->setText(column_number_occurrence, QString::number(1)); + + meta_item->addChild(item); + meta_item->setText(column_number_occurrence, QString::number(meta_item->text(column_number_occurrence).toInt() + 1)); + meta_item->sortChildren(column_number_subevent, Qt::AscendingOrder); + } + + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Frame %1")).arg(pinfo->num)); + frame_item->setText(column_number_event, QString("0x%1").arg(tap_hci->event, 2, 16, QChar('0'))); + frame_item->setText(column_number_subevent, QString("0x%1").arg(tap_hci->subevent, 2, 16, QChar('0'))); + + item_data = wmem_new(wmem_file_scope(), bluetooth_item_data_t); + item_data->interface_id = tap_hci->interface_id; + item_data->adapter_id = tap_hci->adapter_id; + item_data->frame_number = pinfo->num; + + frame_item->setData(0, Qt::UserRole, VariantPointer<bluetooth_item_data_t>::asQVariant(item_data)); + + item->addChild(frame_item); + + /* Remove item that is known now */ + for (int i_item = 0; i_item < meta_item->childCount(); i_item +=1) { + if (meta_item->child(i_item)->text(column_number_name) != QString(tr("Unknown"))) + continue; + + item = meta_item->child(i_item); + for (int ii_item = 0; ii_item < item->childCount(); ii_item +=1) { + if (item->child(ii_item)->text(column_number_name) != QString(tr("Frame %1")).arg(pinfo->num)) + continue; + + delete item->child(ii_item); + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() - 1)); + if (item->childCount() == 0) { + delete item; + meta_item->setText(column_number_occurrence, QString::number(meta_item->text(column_number_occurrence).toInt() - 1)); + } + + break; + } + break; + } + + break; + case BLUETOOTH_HCI_SUMMARY_STATUS: + main_item = dialog->item_status_; + + for (int i_item = 0; i_item < main_item->childCount(); i_item +=1) { + if (main_item->child(i_item)->text(column_number_status) == + QString("0x%1").arg(tap_hci->status, 2, 16, QChar('0'))) { + item = main_item->child(i_item); + break; + } + } + + if (!item) { + if (tap_hci->name) + name = tap_hci->name; + + item = new QTreeWidgetItem(); + item->setText(column_number_name, name); + item->setText(column_number_status, QString("0x%1").arg(tap_hci->status, 2, 16, QChar('0'))); + + main_item->addChild(item); + item->setHidden(!name.contains(dialog->ui->resultsFilterLineEdit->text(), Qt::CaseInsensitive)); + main_item->sortChildren(column_number_event, Qt::AscendingOrder); + main_item->setText(column_number_occurrence, QString::number(main_item->text(column_number_occurrence).toInt() + 1)); + } + + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Frame %1")).arg(pinfo->num)); + frame_item->setText(column_number_status, QString("0x%1").arg(tap_hci->status, 2, 16, QChar('0'))); + item->addChild(frame_item); + + item_data = wmem_new(wmem_file_scope(), bluetooth_item_data_t); + item_data->interface_id = tap_hci->interface_id; + item_data->adapter_id = tap_hci->adapter_id; + item_data->frame_number = pinfo->num; + frame_item->setData(0, Qt::UserRole, VariantPointer<bluetooth_item_data_t>::asQVariant(item_data)); + + break; + case BLUETOOTH_HCI_SUMMARY_STATUS_PENDING: + main_item = dialog->item_status_; + + for (int i_item = 0; i_item < main_item->childCount(); i_item +=1) { + if (main_item->child(i_item)->text(column_number_status) == QString::number(tap_hci->status)) { + item = main_item->child(i_item); + break; + } + } + + if (!item) { + item = new QTreeWidgetItem(); + item->setText(column_number_name, tr("Pending")); + item->setText(column_number_status, QString::number(tap_hci->status)); + + main_item->addChild(item); + item->setHidden(!name.contains(dialog->ui->resultsFilterLineEdit->text(), Qt::CaseInsensitive)); + main_item->sortChildren(column_number_event, Qt::AscendingOrder); + main_item->setText(column_number_occurrence, QString::number(main_item->text(column_number_occurrence).toInt() + 1)); + } + + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Frame %1")).arg(pinfo->num)); + frame_item->setText(column_number_status, QString::number(tap_hci->status)); + item->addChild(frame_item); + + item_data = wmem_new(wmem_file_scope(), bluetooth_item_data_t); + item_data->interface_id = tap_hci->interface_id; + item_data->adapter_id = tap_hci->adapter_id; + item_data->frame_number = pinfo->num; + frame_item->setData(0, Qt::UserRole, VariantPointer<bluetooth_item_data_t>::asQVariant(item_data)); + + break; + case BLUETOOTH_HCI_SUMMARY_REASON: + main_item = dialog->item_reason_; + + for (int i_item = 0; i_item < main_item->childCount(); i_item +=1) { + if (main_item->child(i_item)->text(column_number_reason) == + QString("0x%1").arg(tap_hci->reason, 2, 16, QChar('0'))) { + item = main_item->child(i_item); + break; + } + } + + if (!item) { + if (tap_hci->name) + name = tap_hci->name; + + item = new QTreeWidgetItem(); + item->setText(column_number_name, name); + item->setText(column_number_reason, QString("0x%1").arg(tap_hci->reason, 2, 16, QChar('0'))); + + main_item->addChild(item); + item->setHidden(!name.contains(dialog->ui->resultsFilterLineEdit->text(), Qt::CaseInsensitive)); + main_item->sortChildren(column_number_event, Qt::AscendingOrder); + main_item->setText(column_number_occurrence, QString::number(main_item->text(column_number_occurrence).toInt() + 1)); + } + + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Frame %1")).arg(pinfo->num)); + frame_item->setText(column_number_reason, QString("0x%1").arg(tap_hci->reason, 2, 16, QChar('0'))); + item->addChild(frame_item); + + item_data = wmem_new(wmem_file_scope(), bluetooth_item_data_t); + item_data->interface_id = tap_hci->interface_id; + item_data->adapter_id = tap_hci->adapter_id; + item_data->frame_number = pinfo->num; + frame_item->setData(0, Qt::UserRole, VariantPointer<bluetooth_item_data_t>::asQVariant(item_data)); + + break; + case BLUETOOTH_HCI_SUMMARY_HARDWARE_ERROR: + main_item = dialog->item_hardware_errors_; + + for (int i_item = 0; i_item < main_item->childCount(); i_item +=1) { + if (main_item->child(i_item)->text(column_number_hardware_error) == + QString("0x%1").arg(tap_hci->hardware_error, 2, 16, QChar('0'))) { + item = main_item->child(i_item); + break; + } + } + + if (!item) { + item = new QTreeWidgetItem(); + const QString error = QString("0x%1").arg(tap_hci->hardware_error, 2, 16, QChar('0')); + item->setText(column_number_name, QString("Hardware error %1").arg(error)); + item->setText(column_number_hardware_error, error); + + main_item->addChild(item); + item->setHidden(!name.contains(dialog->ui->resultsFilterLineEdit->text(), Qt::CaseInsensitive)); + main_item->sortChildren(column_number_event, Qt::AscendingOrder); + main_item->setText(column_number_occurrence, QString::number(main_item->text(column_number_occurrence).toInt() + 1)); + } + + item->setText(column_number_occurrence, QString::number(item->text(column_number_occurrence).toInt() + 1)); + + frame_item = new QTreeWidgetItem(); + frame_item->setText(column_number_name, QString(tr("Frame %1")).arg(pinfo->num)); + frame_item->setText(column_number_hardware_error, QString("0x%1").arg(tap_hci->hardware_error, 2, 16, QChar('0'))); + item->addChild(frame_item); + + item_data = wmem_new(wmem_file_scope(), bluetooth_item_data_t); + item_data->interface_id = tap_hci->interface_id; + item_data->adapter_id = tap_hci->adapter_id; + item_data->frame_number = pinfo->num; + frame_item->setData(0, Qt::UserRole, VariantPointer<bluetooth_item_data_t>::asQVariant(item_data)); + + break; + } + + for (int i = 0; i < dialog->ui->tableTreeWidget->columnCount(); i++) { + dialog->ui->tableTreeWidget->resizeColumnToContents(i); + } + + return TAP_PACKET_REDRAW; +} + +void BluetoothHciSummaryDialog::interfaceCurrentIndexChanged(int) +{ + cap_file_.retapPackets(); +} + +void BluetoothHciSummaryDialog::adapterCurrentIndexChanged(int) +{ + cap_file_.retapPackets(); +} + +void BluetoothHciSummaryDialog::on_tableTreeWidget_itemActivated(QTreeWidgetItem *item, int) +{ + if (file_closed_) + return; + + bluetooth_item_data_t *item_data = VariantPointer<bluetooth_item_data_t>::asPtr(item->data(0, Qt::UserRole)); + + if (item_data) + emit goToPacket(item_data->frame_number); +} + + +void BluetoothHciSummaryDialog::recursiveCopyTreeItems(QTreeWidgetItem *item, QString ©, int ident_level) +{ + QTreeWidgetItem *child_item; + + if (!item->isExpanded()) return; + + for (int i_item = 0; i_item < item->childCount(); i_item += 1) { + child_item = item->child(i_item); + + copy.append(QString(" ").repeated(ident_level)); + copy += QString("%1 %2 %3 %4 %5 %6 %7 %8 %9\n") + .arg(child_item->text(column_number_name), -60 + 4 * ident_level) + .arg(child_item->text(column_number_ogf), -10) + .arg(child_item->text(column_number_ocf), -10) + .arg(child_item->text(column_number_opcode), -10) + .arg(child_item->text(column_number_event), -10) + .arg(child_item->text(column_number_subevent), -10) + .arg(child_item->text(column_number_status), -10) + .arg(child_item->text(column_number_reason), -10) + .arg(child_item->text(column_number_hardware_error), -15) + .arg(child_item->text(column_number_occurrence), -10); + + recursiveCopyTreeItems(child_item, copy, ident_level + 1); + } +} + +void BluetoothHciSummaryDialog::on_actionCopy_All_triggered() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString copy; + QTreeWidgetItem *item; + + item = ui->tableTreeWidget->headerItem(); + + copy += QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10\n") + .arg(item->text(column_number_name), -60) + .arg(item->text(column_number_ogf), -10) + .arg(item->text(column_number_ocf), -10) + .arg(item->text(column_number_opcode), -10) + .arg(item->text(column_number_event), -10) + .arg(item->text(column_number_subevent), -10) + .arg(item->text(column_number_status), -10) + .arg(item->text(column_number_reason), -10) + .arg(item->text(column_number_hardware_error), -15) + .arg(item->text(column_number_occurrence), -10); + + for (int i_item = 0; i_item < ui->tableTreeWidget->topLevelItemCount(); ++i_item) { + item = ui->tableTreeWidget->topLevelItem(i_item); + + copy += QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10\n") + .arg(item->text(column_number_name), -60) + .arg(item->text(column_number_ogf), -10) + .arg(item->text(column_number_ocf), -10) + .arg(item->text(column_number_opcode), -10) + .arg(item->text(column_number_event), -10) + .arg(item->text(column_number_subevent), -10) + .arg(item->text(column_number_status), -10) + .arg(item->text(column_number_reason), -10) + .arg(item->text(column_number_hardware_error), -15) + .arg(item->text(column_number_occurrence), -10); + + recursiveCopyTreeItems(ui->tableTreeWidget->topLevelItem(i_item), copy, 1); + } + + clipboard->setText(copy); +} + +void BluetoothHciSummaryDialog::on_actionSave_as_image_triggered() +{ + QPixmap image; + + QString fileName = WiresharkFileDialog::getSaveFileName(this, + tr("Save Table Image"), + "bluetooth_hci_summary.png", + tr("PNG Image (*.png)")); + + if (fileName.isEmpty()) return; + + image = ui->tableTreeWidget->grab(); + image.save(fileName, "PNG"); +} + +void BluetoothHciSummaryDialog::on_buttonBox_clicked(QAbstractButton *) +{ +/* if (button == foo_button_) */ +} + +void BluetoothHciSummaryDialog::displayFilterLineEditAccepted() +{ + GString *error_string; + + remove_tap_listener(&tapinfo_); + error_string = register_tap_listener("bluetooth.hci_summary", &tapinfo_, + ui->displayFilterLineEdit->text().toUtf8().constData(), + 0, + bluetooth_hci_summary_tap_reset, + bluetooth_hci_summary_tap_packet, + NULL, + NULL + ); + + if (error_string != NULL) { + simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, + "%s", error_string->str); + g_string_free(error_string, TRUE); + } + + cap_file_.retapPackets(); +} + +void BluetoothHciSummaryDialog::resultsFilterLineEditChanged(const QString &text) +{ + for (int i_item = 0; i_item < ui->tableTreeWidget->topLevelItemCount(); ++i_item) { + QTreeWidgetItem *item = ui->tableTreeWidget->topLevelItem(i_item); + + for (int i_child = 0; i_child < item->childCount(); i_child += 1) { + QTreeWidgetItem *child_item = item->child(i_child); + QString name = child_item->text(column_number_name); + child_item->setHidden(!name.contains(text, Qt::CaseInsensitive)); + } + } +} |