diff options
author | Gerald Combs <gerald@wireshark.org> | 2014-11-18 16:21:42 -0800 |
---|---|---|
committer | Gerald Combs <gerald@wireshark.org> | 2014-12-09 21:25:33 +0000 |
commit | 4921e559906aee70c4665f1c739057e227787e01 (patch) | |
tree | 4465cb9e9de152bfb57f00852e437994e2d85cd9 /ui/qt | |
parent | 3147087de323c0294b51006f97b641fc408f1b06 (diff) |
Qt: Initial VoIP Calls dialog.
Add Telephony menu items for VoIP Calls and SIP Flows. Put VoIP Calls at
the top, since that seems to be the primary item.
Add configure-time checks for QtMultimediaWidgets in anticipation of
adding a VoIP playback dialog.
Add an icon for the playback button. (Yes, I've been avoiding
GNOME-level gratuitous icons so far but this is one of the rare
occiasions where it makes sense.)
Add a help link define for the VoIP calls dialog.
Change-Id: I5d0799685c598ad9af76fe9667f8ea7d14b66050
Reviewed-on: https://code.wireshark.org/review/5674
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Diffstat (limited to 'ui/qt')
-rw-r--r-- | ui/qt/CMakeLists.txt | 3 | ||||
-rw-r--r-- | ui/qt/Makefile.am | 2 | ||||
-rw-r--r-- | ui/qt/Makefile.common | 8 | ||||
-rw-r--r-- | ui/qt/Wireshark.pro | 13 | ||||
-rw-r--r-- | ui/qt/follow_stream_dialog.cpp | 1 | ||||
-rw-r--r-- | ui/qt/main_window.h | 3 | ||||
-rw-r--r-- | ui/qt/main_window.ui | 18 | ||||
-rw-r--r-- | ui/qt/main_window_slots.cpp | 23 | ||||
-rw-r--r-- | ui/qt/sequence_diagram.cpp | 9 | ||||
-rw-r--r-- | ui/qt/sequence_diagram.h | 2 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.cpp | 101 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.h | 12 | ||||
-rw-r--r-- | ui/qt/sequence_dialog.ui | 251 | ||||
-rw-r--r-- | ui/qt/stock_icon.cpp | 9 | ||||
-rw-r--r-- | ui/qt/voip_calls_dialog.cpp | 508 | ||||
-rw-r--r-- | ui/qt/voip_calls_dialog.h | 107 | ||||
-rw-r--r-- | ui/qt/voip_calls_dialog.ui | 143 |
17 files changed, 1027 insertions, 186 deletions
diff --git a/ui/qt/CMakeLists.txt b/ui/qt/CMakeLists.txt index dcd553c261..32ad0cf112 100644 --- a/ui/qt/CMakeLists.txt +++ b/ui/qt/CMakeLists.txt @@ -97,6 +97,7 @@ set(WIRESHARK_QT_HEADERS time_shift_dialog.h traffic_table_dialog.h uat_dialog.h + voip_calls_dialog.h wireshark_application.h ) @@ -194,6 +195,7 @@ set(WIRESHARK_QT_SRC time_shift_dialog.cpp traffic_table_dialog.cpp uat_dialog.cpp + voip_calls_dialog.cpp wireshark_application.cpp ) @@ -267,6 +269,7 @@ set(WIRESHARK_QT_UI time_shift_dialog.ui traffic_table_dialog.ui uat_dialog.ui + voip_calls_dialog.ui ) if(HAVE_PCAP_REMOTE) diff --git a/ui/qt/Makefile.am b/ui/qt/Makefile.am index c8d7b447bb..a99b9287bc 100644 --- a/ui/qt/Makefile.am +++ b/ui/qt/Makefile.am @@ -214,6 +214,8 @@ traffic_table_dialog.cpp traffic_table_dialog.h: ui_traffic_table_dialog.h uat_dialog.cpp uat_dialog.h: ui_uat_dialog.h +voip_calls_dialog.cpp voip_calls_dialog.h: ui_voip_calls_dialog.h + doxygen: if HAVE_DOXYGEN $(DOXYGEN) doxygen.cfg diff --git a/ui/qt/Makefile.common b/ui/qt/Makefile.common index 251a8f62cf..e7b0d247cb 100644 --- a/ui/qt/Makefile.common +++ b/ui/qt/Makefile.common @@ -75,7 +75,8 @@ NODIST_GENERATED_HEADER_FILES = \ ui_tcp_stream_dialog.h \ ui_time_shift_dialog.h \ ui_traffic_table_dialog.h \ - ui_uat_dialog.h + ui_uat_dialog.h \ + ui_voip_calls_dialog.h # Generated C source files that we want in the distribution. GENERATED_C_FILES = \ @@ -190,6 +191,7 @@ MOC_HDRS = \ time_shift_dialog.h \ traffic_table_dialog.h \ uat_dialog.h \ + voip_calls_dialog.h \ wireshark_application.h @@ -243,7 +245,8 @@ UI_FILES = \ tcp_stream_dialog.ui \ time_shift_dialog.ui \ traffic_table_dialog.ui \ - uat_dialog.ui + uat_dialog.ui \ + voip_calls_dialog.ui # # The .moc.cpp files generated from them. @@ -386,6 +389,7 @@ WIRESHARK_QT_SRC = \ time_shift_dialog.cpp \ traffic_table_dialog.cpp \ uat_dialog.cpp \ + voip_calls_dialog.cpp \ wireshark_application.cpp WIRESHARK_QT_TAP_SRC = \ diff --git a/ui/qt/Wireshark.pro b/ui/qt/Wireshark.pro index 5d42d5b358..34e2db4a42 100644 --- a/ui/qt/Wireshark.pro +++ b/ui/qt/Wireshark.pro @@ -26,7 +26,7 @@ isEqual(QT_MAJOR_VERSION, 4) { QT += core gui } else { - QT += core widgets printsupport + QT += core widgets printsupport multimediawidgets } isEqual(QT_MAJOR_VERSION, 5): greaterThan(QT_MINOR_VERSION, 1): win32 { @@ -252,7 +252,8 @@ FORMS += \ tcp_stream_dialog.ui \ time_shift_dialog.ui \ traffic_table_dialog.ui \ - uat_dialog.ui + uat_dialog.ui \ + voip_calls_dialog.ui HEADERS += $$HEADERS_WS_C \ @@ -302,7 +303,8 @@ HEADERS += $$HEADERS_WS_C \ tango_colors.h \ tcp_stream_dialog.h \ traffic_table_dialog.h \ - uat_dialog.h + uat_dialog.h \ + voip_calls_dialog.h win32 { OBJECTS_WS_C = $$SOURCES_WS_C @@ -423,7 +425,7 @@ win32 { EXTRA_DLLS = QtCored4 QtGuid4 } else: lessThan(QT_MINOR_VERSION, 3) { # The QT lib parts are copied by windeployqt post 5.3 - EXTRA_DLLS = Qt5Cored Qt5Guid Qt5Widgetsd Qt5PrintSupportd + EXTRA_DLLS = Qt5Cored Qt5Guid Qt5Widgetsd Qt5PrintSupportd Qt5MultimediaWidgetsd EXTRA_PLATFORM_DLLS = qwindowsd QMAKE_POST_LINK +=$$quote($(CHK_DIR_EXISTS) $${PLATFORM_DLL_DIR} $(MKDIR) $${PLATFORM_DLL_DIR}$$escape_expand(\\n\\t)) } @@ -433,7 +435,7 @@ win32 { EXTRA_DLLS = QtCore4 QtGui4 } else: lessThan(QT_MINOR_VERSION, 3) { # The QT lib parts are copied by windeployqt post 5.3 - EXTRA_DLLS = Qt5Core Qt5Gui Qt5Widgets Qt5PrintSupport + EXTRA_DLLS = Qt5Core Qt5Gui Qt5Widgets Qt5PrintSupport Qt5MultimediaWidgets EXTRA_PLATFORM_DLLS = qwindows QMAKE_POST_LINK +=$$quote($(CHK_DIR_EXISTS) $${PLATFORM_DLL_DIR} $(MKDIR) $${PLATFORM_DLL_DIR}$$escape_expand(\\n\\t)) } @@ -667,4 +669,5 @@ SOURCES += \ time_shift_dialog.cpp \ traffic_table_dialog.cpp \ uat_dialog.cpp \ + voip_calls_dialog.cpp \ wireshark_application.cpp diff --git a/ui/qt/follow_stream_dialog.cpp b/ui/qt/follow_stream_dialog.cpp index ea80c8980c..3d5d2bd24e 100644 --- a/ui/qt/follow_stream_dialog.cpp +++ b/ui/qt/follow_stream_dialog.cpp @@ -607,7 +607,6 @@ void FollowStreamDialog::setCaptureFile(capture_file *cf) // / (slash), Ctrl-F - Focus and highlight the search box // Ctrl-G, Ctrl-N, F3 - Find next // Should we make it so that typing any text starts searching? -#include <QDebug> bool FollowStreamDialog::eventFilter(QObject *obj, QEvent *event) { Q_UNUSED(obj); diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h index 6bf613d97b..6472e357c4 100644 --- a/ui/qt/main_window.h +++ b/ui/qt/main_window.h @@ -409,10 +409,13 @@ private slots: void on_actionStatisticsIOGraph_triggered(); void on_actionStatisticsSametime_triggered(); + void openVoipCallsDialog(bool all_flows = false); + void on_actionTelephonyVoipCalls_triggered(); void on_actionTelephonyISUPMessages_triggered(); void on_actionTelephonyRTSPPacketCounter_triggered(); void on_actionTelephonySMPPOperations_triggered(); void on_actionTelephonyUCPMessages_triggered(); + void on_actionTelephonySipFlows_triggered(); void changeEvent(QEvent* event); }; diff --git a/ui/qt/main_window.ui b/ui/qt/main_window.ui index fd13b206d5..cbf8922405 100644 --- a/ui/qt/main_window.ui +++ b/ui/qt/main_window.ui @@ -435,10 +435,12 @@ </property> <addaction name="actionTelephonyRTSPPacketCounter"/> </widget> + <addaction name="actionTelephonyVoipCalls"/> <addaction name="actionTelephonyISUPMessages"/> <addaction name="menuRTSP"/> <addaction name="actionTelephonySMPPOperations"/> <addaction name="actionTelephonyUCPMessages"/> + <addaction name="actionTelephonySipFlows"/> </widget> <widget class="QMenu" name="menuEdit"> <property name="title"> @@ -2136,6 +2138,22 @@ <string>Bytes</string> </property> </action> + <action name="actionTelephonyVoipCalls"> + <property name="text"> + <string>&VoIP Calls</string> + </property> + <property name="toolTip"> + <string>All VoIP Calls</string> + </property> + </action> + <action name="actionTelephonySipFlows"> + <property name="text"> + <string>SIP &Flows</string> + </property> + <property name="toolTip"> + <string>SIP Flows</string> + </property> + </action> </widget> <layoutdefault spacing="6" margin="11"/> <customwidgets> diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp index 82fadbe799..056fc0cbf5 100644 --- a/ui/qt/main_window_slots.cpp +++ b/ui/qt/main_window_slots.cpp @@ -96,6 +96,7 @@ #include "stats_tree_dialog.h" #include "tcp_stream_dialog.h" #include "time_shift_dialog.h" +#include "voip_calls_dialog.h" #include "wireshark_application.h" #include <QClipboard> @@ -2342,6 +2343,23 @@ void MainWindow::on_actionStatisticsSametime_triggered() // Telephony Menu +void MainWindow::openVoipCallsDialog(bool all_flows) +{ + VoipCallsDialog *voip_calls_dialog = new VoipCallsDialog(this, cap_file_, all_flows); + connect(voip_calls_dialog, SIGNAL(goToPacket(int)), + packet_list_, SLOT(goToPacket(int))); + connect(voip_calls_dialog, SIGNAL(updateFilter(QString&, bool)), + this, SLOT(filterPackets(QString&, bool))); + connect(this, SIGNAL(setCaptureFile(capture_file*)), + voip_calls_dialog, SLOT(setCaptureFile(capture_file*))); + voip_calls_dialog->show(); +} + +void MainWindow::on_actionTelephonyVoipCalls_triggered() +{ + openVoipCallsDialog(); +} + void MainWindow::on_actionTelephonyISUPMessages_triggered() { openStatisticsTreeDialog("isup_msg"); @@ -2362,6 +2380,11 @@ void MainWindow::on_actionTelephonyUCPMessages_triggered() openStatisticsTreeDialog("ucp_messages"); } +void MainWindow::on_actionTelephonySipFlows_triggered() +{ + openVoipCallsDialog(true); +} + // Help Menu void MainWindow::on_actionHelpContents_triggered() { diff --git a/ui/qt/sequence_diagram.cpp b/ui/qt/sequence_diagram.cpp index 8660c4295c..3bd4c2d724 100644 --- a/ui/qt/sequence_diagram.cpp +++ b/ui/qt/sequence_diagram.cpp @@ -31,8 +31,6 @@ #include <QPen> #include <QPointF> -#include <QDebug> - const int max_comment_em_width_ = 20; // UML-like network node sequence diagrams. @@ -98,8 +96,9 @@ SequenceDiagram::SequenceDiagram(QCPAxis *keyAxis, QCPAxis *valueAxis, QCPAxis * void SequenceDiagram::setData(seq_analysis_info_t *sainfo) { data_->clear(); + sainfo_ = sainfo; + if (!sainfo) return; - WSCPSeqData new_data; double cur_key = 0.0; QVector<double> key_ticks, val_ticks; QVector<QString> key_labels, val_labels, com_labels; @@ -108,6 +107,7 @@ void SequenceDiagram::setData(seq_analysis_info_t *sainfo) for (GList *cur = g_queue_peek_nth_link(sainfo->items, 0); cur; cur = g_list_next(cur)) { seq_analysis_item_t *sai = (seq_analysis_item_t *) cur->data; + WSCPSeqData new_data; new_data.key = cur_key; new_data.value = sai; @@ -120,7 +120,6 @@ void SequenceDiagram::setData(seq_analysis_info_t *sainfo) cur_key++; } - sainfo_ = sainfo; for (unsigned int i = 0; i < sainfo_->num_nodes; i++) { val_ticks.append(i); @@ -193,7 +192,7 @@ void SequenceDiagram::draw(QCPPainter *painter) WSCPSeqDataMap::const_iterator it; for (it = data_->constBegin(); it != data_->constEnd(); ++it) { double cur_key = it.key(); - seq_analysis_item_t *sai = (seq_analysis_item_t *) it.value().value; + seq_analysis_item_t *sai = it.value().value; QPen fg_pen(mainPen()); if (sai->fd->num == selected_packet_) { diff --git a/ui/qt/sequence_diagram.h b/ui/qt/sequence_diagram.h index 952570e27e..facc33bf42 100644 --- a/ui/qt/sequence_diagram.h +++ b/ui/qt/sequence_diagram.h @@ -64,7 +64,7 @@ public: seq_analysis_item_t *itemForPosY(int ypos); // reimplemented virtual methods: - virtual void clearData() {} + virtual void clearData() { data_->clear(); } virtual double selectTest(const QPointF &pos, bool onlySelectable, QVariant *details=0) const; public slots: diff --git a/ui/qt/sequence_dialog.cpp b/ui/qt/sequence_dialog.cpp index 68eb6013f0..1d8f75fca6 100644 --- a/ui/qt/sequence_dialog.cpp +++ b/ui/qt/sequence_dialog.cpp @@ -26,6 +26,7 @@ #include "wsutil/nstime.h" +#include "sequence_diagram.h" #include "wireshark_application.h" #include <QDir> @@ -33,8 +34,6 @@ #include <QFontMetrics> #include <QPoint> -#include <QDebug> - // To do: // - Add UTF8 to text dump // - Save to XMI? http://www.umlgraph.org/ @@ -46,10 +45,11 @@ // - Create WSGraph subclasses with common behavior. // - Help button and text -SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType type) : +SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, seq_analysis_info_t *sainfo) : QDialog(parent), ui(new Ui::SequenceDialog), cap_file_(cf), + sainfo_(sainfo), num_items_(0), packet_num_(0), node_label_w_(20) @@ -57,6 +57,14 @@ SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType t ui->setupUi(this); QCustomPlot *sp = ui->sequencePlot; + if (!sainfo_) { + sainfo_ = sequence_analysis_info_new(); + sainfo_->type = SEQ_ANALYSIS_ANY; + sainfo_->all_packets = TRUE; + } else { + num_items_ = sequence_analysis_get_nodes(sainfo_); + } + seq_diagram_ = new SequenceDiagram(sp->yAxis, sp->xAxis2, sp->yAxis2); sp->addPlottable(seq_diagram_); sp->axisRect()->setRangeDragAxes(sp->xAxis2, sp->yAxis); @@ -90,8 +98,6 @@ SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType t ctx_menu_.addSeparator(); ctx_menu_.addAction(ui->actionGoToPacket); - memset (&seq_analysis_, 0, sizeof(seq_analysis_)); - ui->showComboBox->blockSignals(true); ui->showComboBox->setCurrentIndex(0); ui->showComboBox->blockSignals(false); @@ -104,23 +110,13 @@ SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType t fcb->addItem(ui->actionFlowTcp->text(), SEQ_ANALYSIS_TCP); ui->flowComboBox->blockSignals(true); - switch (type) { - case any: - seq_analysis_.type = SEQ_ANALYSIS_ANY; - ui->flowComboBox->setCurrentIndex(SEQ_ANALYSIS_ANY); - break; - case tcp: - seq_analysis_.type = SEQ_ANALYSIS_TCP; - ui->flowComboBox->setCurrentIndex(SEQ_ANALYSIS_TCP); - break; - case voip: - seq_analysis_.type = SEQ_ANALYSIS_VOIP; - ui->flowComboBox->hide(); - ui->flowLabel->hide(); - break; + ui->flowComboBox->setCurrentIndex(sainfo_->type); + + if (sainfo_->type == SEQ_ANALYSIS_VOIP) { + ui->controlFrame->hide(); + } else { + ui->flowComboBox->blockSignals(false); } - ui->flowComboBox->blockSignals(false); - seq_analysis_.all_packets = TRUE; QPushButton *save_bt = ui->buttonBox->button(QDialogButtonBox::Save); save_bt->setText(tr("Save As...")); @@ -146,6 +142,9 @@ SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType t SequenceDialog::~SequenceDialog() { + if (sainfo_->type != SEQ_ANALYSIS_VOIP) { + sequence_analysis_info_free(sainfo_); + } delete ui; } @@ -279,8 +278,12 @@ void SequenceDialog::mouseMoved(QMouseEvent *event) } if (hint.isEmpty()) { - hint += tr("%Ln node(s)", "", seq_analysis_.num_nodes) + QString(", ") - + tr("%Ln item(s)", "", num_items_); + if (!sainfo_) { + hint += tr("No data"); + } else { + hint += tr("%Ln node(s)", "", sainfo_->num_nodes) + QString(", ") + + tr("%Ln item(s)", "", num_items_); + } } hint.prepend("<small><i>"); @@ -329,8 +332,8 @@ void SequenceDialog::on_buttonBox_accepted() save_ok = ui->sequencePlot->saveBmp(file_name); } else if (extension.compare(jpeg_filter) == 0) { save_ok = ui->sequencePlot->saveJpg(file_name); - } else if (extension.compare(ascii_filter) == 0 && cap_file_) { - save_ok = sequence_analysis_dump_to_file(file_name.toUtf8().constData(), &seq_analysis_, cap_file_, 0); + } else if (extension.compare(ascii_filter) == 0 && cap_file_ && sainfo_) { + save_ok = sequence_analysis_dump_to_file(file_name.toUtf8().constData(), sainfo_, cap_file_, 0); } // else error dialog? if (save_ok) { @@ -342,23 +345,24 @@ void SequenceDialog::on_buttonBox_accepted() void SequenceDialog::fillDiagram() { + if (!sainfo_) return; + QCustomPlot *sp = ui->sequencePlot; - seq_analysis_info_t new_sa; - - new_sa = seq_analysis_; - new_sa.items = g_queue_new(); - new_sa.ht = NULL; - new_sa.num_nodes = 0; - sequence_analysis_list_get(cap_file_, &new_sa); - num_items_ = sequence_analysis_get_nodes(&new_sa); - seq_diagram_->setData(&new_sa); - sequence_analysis_list_free(&seq_analysis_); - seq_analysis_ = new_sa; + + if (sainfo_->type == SEQ_ANALYSIS_VOIP) { + seq_diagram_->setData(sainfo_); + } else { + seq_diagram_->clearData(); + sequence_analysis_list_free(sainfo_); + sequence_analysis_list_get(cap_file_, sainfo_); + num_items_ = sequence_analysis_get_nodes(sainfo_); + seq_diagram_->setData(sainfo_); + } QFontMetrics vfm = QFontMetrics(sp->xAxis2->labelFont()); node_label_w_ = 0; - for (guint i = 0; i < seq_analysis_.num_nodes; i++) { - int label_w = vfm.width(ep_address_to_display(&(seq_analysis_.nodes[i]))); + for (guint i = 0; i < sainfo_->num_nodes; i++) { + int label_w = vfm.width(ep_address_to_display(&(sainfo_->nodes[i]))); if (node_label_w_ < label_w) { node_label_w_ = label_w; } @@ -393,6 +397,8 @@ void SequenceDialog::panAxes(int x_pixels, int y_pixels) void SequenceDialog::resetAxes(bool keep_lower) { + if (!sainfo_) return; + QCustomPlot *sp = ui->sequencePlot; // Allow space for labels on the top and port numbers on the left. double top_pos = -1.0, left_pos = -0.5; @@ -408,7 +414,7 @@ void SequenceDialog::resetAxes(bool keep_lower) sp->yAxis->setRange(top_pos, range_ratio + top_pos); double rmin = sp->xAxis2->range().size() / 2; - ui->horizontalScrollBar->setRange((rmin - 0.5) * 100, (seq_analysis_.num_nodes - 0.5 - rmin) * 100); + ui->horizontalScrollBar->setRange((rmin - 0.5) * 100, (sainfo_->num_nodes - 0.5 - rmin) * 100); xAxisChanged(sp->xAxis2->range()); rmin = (sp->yAxis->range().size() / 2); @@ -432,27 +438,32 @@ void SequenceDialog::on_actionGoToPacket_triggered() void SequenceDialog::on_showComboBox_currentIndexChanged(int index) { + if (!sainfo_) return; + if (index == 0) { - seq_analysis_.all_packets = TRUE; + sainfo_->all_packets = TRUE; } else { - seq_analysis_.all_packets = FALSE; + sainfo_->all_packets = FALSE; } fillDiagram(); } void SequenceDialog::on_flowComboBox_currentIndexChanged(int index) { - if (index < 0) return; - seq_analysis_.type = static_cast<seq_analysis_type>(ui->flowComboBox->itemData(index).toInt()); + if (!sainfo_ || sainfo_->type == SEQ_ANALYSIS_VOIP || index < 0) return; + + sainfo_->type = static_cast<seq_analysis_type>(ui->flowComboBox->itemData(index).toInt()); fillDiagram(); } void SequenceDialog::on_addressComboBox_currentIndexChanged(int index) { + if (!sainfo_) return; + if (index == 0) { - seq_analysis_.any_addr = TRUE; + sainfo_->any_addr = TRUE; } else { - seq_analysis_.any_addr = FALSE; + sainfo_->any_addr = FALSE; } fillDiagram(); } diff --git a/ui/qt/sequence_dialog.h b/ui/qt/sequence_dialog.h index 5ede431b06..77728ffd10 100644 --- a/ui/qt/sequence_dialog.h +++ b/ui/qt/sequence_dialog.h @@ -30,7 +30,9 @@ #include "epan/packet.h" -#include "sequence_diagram.h" +#include "ui/tap-sequence-analysis.h" + +#include "qcustomplot.h" #include <QDialog> #include <QMenu> @@ -39,14 +41,14 @@ namespace Ui { class SequenceDialog; } +class SequenceDiagram; + class SequenceDialog : public QDialog { Q_OBJECT public: - enum SequenceType { any, tcp, voip }; - - explicit SequenceDialog(QWidget *parent = 0, capture_file *cf = NULL, SequenceType type = any); + explicit SequenceDialog(QWidget *parent = 0, capture_file *cf = NULL, seq_analysis_info_t *sainfo = NULL); ~SequenceDialog(); signals: @@ -90,7 +92,7 @@ private: Ui::SequenceDialog *ui; SequenceDiagram *seq_diagram_; capture_file *cap_file_; - seq_analysis_info_t seq_analysis_; + seq_analysis_info_t *sainfo_; int num_items_; guint32 packet_num_; double one_em_; diff --git a/ui/qt/sequence_dialog.ui b/ui/qt/sequence_dialog.ui index 26067d9960..93a44eb140 100644 --- a/ui/qt/sequence_dialog.ui +++ b/ui/qt/sequence_dialog.ui @@ -13,7 +13,7 @@ <property name="windowTitle"> <string>Flow</string> </property> - <layout class="QVBoxLayout" name="verticalLayout"> + <layout class="QVBoxLayout" name="verticalLayout_2" stretch="1,0,0,0"> <item> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> @@ -75,123 +75,137 @@ </widget> </item> <item> - <layout class="QHBoxLayout" name="controlHorizontalLayout" stretch="0,0,0,0,0,0,0,0,1"> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Show:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="showComboBox"> - <item> - <property name="text"> - <string>All packets</string> - </property> - </item> - <item> - <property name="text"> - <string>Displayed packets</string> - </property> - </item> - </widget> - </item> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>13</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="flowLabel"> - <property name="text"> - <string>Flow type:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="flowComboBox"/> - </item> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>13</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Addresses:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="addressComboBox"> - <item> - <property name="text"> - <string>Any</string> - </property> - </item> - <item> - <property name="text"> - <string>Network</string> - </property> - </item> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="resetButton"> - <property name="text"> - <string>Reset</string> - </property> - </widget> - </item> - </layout> + <widget class="QFrame" name="controlFrame"> + <property name="frameShape"> + <enum>QFrame::NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Show:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="showComboBox"> + <item> + <property name="text"> + <string>All packets</string> + </property> + </item> + <item> + <property name="text"> + <string>Displayed packets</string> + </property> + </item> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>13</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="flowLabel"> + <property name="text"> + <string>Flow type:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="flowComboBox"/> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>13</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Addresses:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="addressComboBox"> + <item> + <property name="text"> + <string>Any</string> + </property> + </item> + <item> + <property name="text"> + <string>Network</string> + </property> + </item> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="resetButton"> + <property name="text"> + <string>Reset</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </item> <item> <widget class="QDialogButtonBox" name="buttonBox"> @@ -345,6 +359,7 @@ <container>1</container> </customwidget> </customwidgets> + <resources/> <connections> <connection> <sender>buttonBox</sender> diff --git a/ui/qt/stock_icon.cpp b/ui/qt/stock_icon.cpp index 03c50e0325..86e953e3dd 100644 --- a/ui/qt/stock_icon.cpp +++ b/ui/qt/stock_icon.cpp @@ -75,15 +75,16 @@ StockIcon::StockIcon(const char *icon_name) : #endif return; } else { - QStringList types = QStringList() << "16x16" << "24x24"; + QStringList types = QStringList() << "12x12" << "16x16" << "24x24"; foreach (QString type, types) { - // Along with each name check for "<name>.on" to use for the on (checked) state. - // XXX Add checks for each combination of QIcon::Mode + QIcon::State QString icon_path = path_pfx_ + QString("%1/%2.png").arg(type).arg(icon_name); - QString icon_path_on = path_pfx_ + QString("%1/%2.on.png").arg(type).arg(icon_name); if (QFile::exists(icon_path)) { addFile(icon_path); } + + // Along with each name check for "<name>.on" to use for the on (checked) state. + // XXX Add checks for each combination of QIcon::Mode + QIcon::State + QString icon_path_on = path_pfx_ + QString("%1/%2.on.png").arg(type).arg(icon_name); if (QFile::exists(icon_path_on)) { addFile(icon_path_on, QSize(), QIcon::Normal, QIcon::On); } diff --git a/ui/qt/voip_calls_dialog.cpp b/ui/qt/voip_calls_dialog.cpp new file mode 100644 index 0000000000..aee0e08121 --- /dev/null +++ b/ui/qt/voip_calls_dialog.cpp @@ -0,0 +1,508 @@ +/* voip_calls_dialog.cpp + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "voip_calls_dialog.h" +#include "ui_voip_calls_dialog.h" + +#include "file.h" + +#include "epan/addr_resolv.h" +#include "epan/dissectors/packet-h225.h" + +#include "ui/utf8_entities.h" + +#include "sequence_dialog.h" +#include "stock_icon.h" +#include "wireshark_application.h" + +#include <QContextMenuEvent> +#include <QPushButton> + +// To do: +// - More context menu items +// - Don't select on right click +// - Player +// - Add a screenshot to the user's guide + +// Bugs: +// - Preparing a filter overwrites the existing filter. The GTK+ UI appends. +// We'll probably have to add an "append" parameter to MainWindow::filterPackets. + +// VoipCallsTreeWidgetItem +// QTreeWidgetItem subclass that allows sorting + +const int start_time_col_ = 0; +const int stop_time_col_ = 1; +const int initial_speaker_col_ = 2; +const int from_col_ = 3; +const int to_col_ = 4; +const int protocol_col_ = 5; +const int packets_col_ = 6; +const int state_col_ = 7; +const int comments_col_ = 8; + +Q_DECLARE_METATYPE(voip_calls_info_t*) + +class VoipCallsTreeWidgetItem : public QTreeWidgetItem +{ +public: + VoipCallsTreeWidgetItem(QTreeWidget *tree, voip_calls_info_t *call_info) : QTreeWidgetItem(tree) { + setData(0, Qt::UserRole, qVariantFromValue(call_info)); + drawData(); + } + + void drawData() { + voip_calls_info_t *call_info = data(0, Qt::UserRole).value<voip_calls_info_t*>(); + if (!call_info) { + return; + } + + // XXX Pull digit count from capture file precision + setText(start_time_col_, QString::number(nstime_to_sec(&(call_info->start_rel_ts)), 'f', 6)); + setText(stop_time_col_, QString::number(nstime_to_sec(&(call_info->stop_rel_ts)), 'f', 6)); + setText(initial_speaker_col_, ep_address_to_display(&(call_info->initial_speaker))); + setText(from_col_, call_info->from_identity); + setText(to_col_, call_info->to_identity); + setText(protocol_col_, ((call_info->protocol == VOIP_COMMON) && call_info->protocol_name) ? + call_info->protocol_name : voip_protocol_name[call_info->protocol]); + setText(packets_col_, QString::number(call_info->npackets)); + setText(state_col_, voip_call_state_name[call_info->call_state]); + + /* Add comments based on the protocol */ + QString call_comments; + switch (call_info->protocol) { + case VOIP_ISUP: + { + isup_calls_info_t *isup_info = (isup_calls_info_t *)call_info->prot_info; + call_comments = QString("%1-%2 %3 %4-%5") + .arg(isup_info->ni) + .arg(isup_info->opc) + .arg(UTF8_RIGHTWARDS_ARROW) + .arg(isup_info->ni) + .arg(isup_info->dpc); + } + break; + case VOIP_H323: + { + h323_calls_info_t *h323_info = (h323_calls_info_t *)call_info->prot_info; + gboolean flag = FALSE; + static const QString on_str = QObject::tr("On"); + static const QString off_str = QObject::tr("Off"); + if (call_info->call_state == VOIP_CALL_SETUP) { + flag = h323_info->is_faststart_Setup; + } else { + if ((h323_info->is_faststart_Setup) && (h323_info->is_faststart_Proc)) { + flag = TRUE; + } + } + call_comments = QObject::tr("Tunneling: %1 Fast Start: %2") + .arg(h323_info->is_h245Tunneling ? on_str : off_str) + .arg(flag ? on_str : off_str); + } + break; + case VOIP_COMMON: + default: + call_comments = call_info->call_comment; + break; + } + setText(comments_col_, call_comments); + } + + bool operator< (const QTreeWidgetItem &other) const + { + voip_calls_info_t *this_call_info = data(0, Qt::UserRole).value<voip_calls_info_t*>(); + voip_calls_info_t *other_call_info = other.data(0, Qt::UserRole).value<voip_calls_info_t*>(); + if (!this_call_info || !other_call_info) { + return false; + } + + switch (treeWidget()->sortColumn()) { + case start_time_col_: + return nstime_cmp(&(this_call_info->start_rel_ts), &(other_call_info->start_rel_ts)) < 0; + break; + case stop_time_col_: + return nstime_cmp(&(this_call_info->stop_rel_ts), &(other_call_info->stop_rel_ts)) < 0; + break; + case initial_speaker_col_: + return cmp_address(&(this_call_info->initial_speaker), &(other_call_info->initial_speaker)) < 0; + break; + case packets_col_: + return this_call_info->npackets < other_call_info->npackets; + break; + default: + break; + } + + // Fall back to string comparison + return QTreeWidgetItem::operator <(other); + } + +}; + +VoipCallsDialog::VoipCallsDialog(QWidget *parent, capture_file *cf, bool all_flows) : + QDialog(parent), + ui(new Ui::VoipCallsDialog), + cap_file_(cf) +{ + ui->setupUi(this); + ui->callTreeWidget->sortByColumn(start_time_col_, Qt::AscendingOrder); + + ctx_menu_.addActions(QList<QAction *>() << ui->actionSelect_All); + + prepare_button_ = ui->buttonBox->addButton(tr("Prepare Filter"), QDialogButtonBox::ApplyRole); + sequence_button_ = ui->buttonBox->addButton(tr("Flow Sequence"), QDialogButtonBox::ApplyRole); + player_button_ = ui->buttonBox->addButton(tr("Play Call"), QDialogButtonBox::ApplyRole); + player_button_->setIcon(StockIcon("media-playback-start")); + + // XXX Use recent settings instead + if (parent) { + resize(parent->width() * 4 / 5, parent->height() * 2 / 3); + } + + memset (&tapinfo_, 0, sizeof(tapinfo_)); + tapinfo_.tap_packet = tapPacket; + tapinfo_.tap_draw = tapDraw; + tapinfo_.tap_data = this; + tapinfo_.callsinfos = g_queue_new(); + tapinfo_.h225_cstype = H225_OTHER; + tapinfo_.fs_option = all_flows ? FLOW_ALL : FLOW_ONLY_INVITES; /* flow show option */ + tapinfo_.graph_analysis = sequence_analysis_info_new(); + tapinfo_.graph_analysis->type = SEQ_ANALYSIS_VOIP; + + voip_calls_init_all_taps(&tapinfo_); + + updateWidgets(); + + if (cap_file_) { + tapinfo_.session = cap_file_->epan; + cf_retap_packets(cap_file_); + } +} + +VoipCallsDialog::~VoipCallsDialog() +{ + delete ui; + + voip_calls_remove_all_tap_listeners(&tapinfo_); + sequence_analysis_info_free(tapinfo_.graph_analysis); +} + +void VoipCallsDialog::setCaptureFile(capture_file *cf) +{ + if (!cf) { // We only want to know when the file closes. + voip_calls_remove_all_tap_listeners(&tapinfo_); + cap_file_ = NULL; + tapinfo_.session = NULL; + } + emit captureFileChanged(cap_file_); + updateWidgets(); +} + +void VoipCallsDialog::contextMenuEvent(QContextMenuEvent *event) +{ + ctx_menu_.exec(event->globalPos()); +} + +void VoipCallsDialog::changeEvent(QEvent *event) +{ + if (0 != event) + { + switch (event->type()) + { + case QEvent::LanguageChange: + ui->retranslateUi(this); + break; + default: + break; + } + } + QDialog::changeEvent(event); +} + +//void VoipCallsDialog::tapReset(void *tapinfo_ptr) +//{ +// Q_UNUSED(tapinfo_ptr) +// voip_calls_tapinfo_t *tapinfo = (voip_calls_tapinfo_t *) tapinfo_ptr; +//} + +gboolean VoipCallsDialog::tapPacket(void *tapinfo_ptr, packet_info *pinfo, epan_dissect_t *, const void *data) +{ + Q_UNUSED(tapinfo_ptr) + Q_UNUSED(pinfo) + Q_UNUSED(data) +#ifdef QT_MULTIMEDIAWIDGETS_LIB +// voip_calls_tapinfo_t *tapinfo = (voip_calls_tapinfo_t *) tapinfo_ptr; + // add_rtp_packet for voip player. +// return TRUE; +#endif + return FALSE; +} + +void VoipCallsDialog::tapDraw(void *tapinfo_ptr) +{ + voip_calls_tapinfo_t *tapinfo = (voip_calls_tapinfo_t *) tapinfo_ptr; + + if (!tapinfo || !tapinfo->redraw) { + return; + } + + VoipCallsDialog *voip_calls_dialog = static_cast<VoipCallsDialog *>(tapinfo->tap_data); + if (voip_calls_dialog) { + voip_calls_dialog->updateCalls(); + } +} + +void VoipCallsDialog::updateCalls() +{ + GList *cur_call = g_queue_peek_nth_link(tapinfo_.callsinfos, ui->callTreeWidget->topLevelItemCount()); + ui->callTreeWidget->setSortingEnabled(false); + + // Add any missing items + while (cur_call && cur_call->data) { + voip_calls_info_t *call_info = (voip_calls_info_t*) cur_call->data; + new VoipCallsTreeWidgetItem(ui->callTreeWidget, call_info); + cur_call = g_list_next(cur_call); + } + + // Fill in the tree + QTreeWidgetItemIterator iter(ui->callTreeWidget); + while (*iter) { + VoipCallsTreeWidgetItem *vcti = static_cast<VoipCallsTreeWidgetItem*>(*iter); + vcti->drawData(); + ++iter; + } + + // Resize columns + for (int i = 0; i < ui->callTreeWidget->columnCount(); i++) { + ui->callTreeWidget->resizeColumnToContents(i); + } + + ui->callTreeWidget->setSortingEnabled(true); + + updateWidgets(); +} + +void VoipCallsDialog::updateWidgets() +{ + bool selected = ui->callTreeWidget->selectedItems().count() > 0 ? true : false; + bool have_ga_items = false; + + if (tapinfo_.graph_analysis && tapinfo_.graph_analysis->items) { + have_ga_items = true; + } + + foreach (QMenu *submenu, ctx_menu_.findChildren<QMenu*>()) { + submenu->setEnabled(selected); + } + prepare_button_->setEnabled(selected && have_ga_items); + sequence_button_->setEnabled(selected && have_ga_items); +#if defined(QT_MULTIMEDIAWIDGETS_LIB) && 0 // We don't have a playback dialog yet. + player_button_->setEnabled(selected && have_ga_items); +#else + player_button_->setEnabled(false); + player_button_->setText(tr("No Audio")); +#endif +} + +void VoipCallsDialog::prepareFilter() +{ + if (ui->callTreeWidget->selectedItems().count() < 1 || !tapinfo_.graph_analysis) { + return; + } + + QString filter_str; + QSet<guint16> selected_calls; + + /* Build a new filter based on frame numbers */ + const char *or_prepend = ""; + foreach (QTreeWidgetItem *ti, ui->callTreeWidget->selectedItems()) { + voip_calls_info_t *call_info = ti->data(0, Qt::UserRole).value<voip_calls_info_t*>(); + selected_calls << call_info->call_num; + } + + GList *cur_ga_item = g_queue_peek_nth_link(tapinfo_.graph_analysis->items, 0); + while (cur_ga_item && cur_ga_item->data) { + seq_analysis_item_t *ga_item = (seq_analysis_item_t*) cur_ga_item->data; + if (selected_calls.contains(ga_item->conv_num)) { + filter_str += QString("%1frame.number == %2").arg(or_prepend).arg(ga_item->fd->num); + or_prepend = " or "; + } + cur_ga_item = g_list_next(cur_ga_item); + } + +#if 0 + // XXX The GTK+ UI falls back to building a filter based on protocols if the filter + // length is too long. Leaving this here for the time being in case we need to do + // the same in the Qt UI. + const sip_calls_info_t *sipinfo; + const isup_calls_info_t *isupinfo; + const h323_calls_info_t *h323info; + const h245_address_t *h245_add = NULL; + const gcp_ctx_t* ctx; + + if (filter_length < max_filter_length) { + gtk_editable_insert_text(GTK_EDITABLE(main_display_filter_widget), filter_string_fwd->str, -1, &pos); + } else { + g_string_free(filter_string_fwd, TRUE); + filter_string_fwd = g_string_new(filter_prepend); + + g_string_append_printf(filter_string_fwd, "("); + is_first = TRUE; + /* Build a new filter based on protocol fields */ + lista = g_queue_peek_nth_link(voip_calls_get_info()->callsinfos, 0); + while (lista) { + listinfo = (voip_calls_info_t *)lista->data; + if (listinfo->selected) { + if (!is_first) + g_string_append_printf(filter_string_fwd, " or "); + switch (listinfo->protocol) { + case VOIP_SIP: + sipinfo = (sip_calls_info_t *)listinfo->prot_info; + g_string_append_printf(filter_string_fwd, + "(sip.Call-ID == \"%s\")", + sipinfo->call_identifier + ); + break; + case VOIP_ISUP: + isupinfo = (isup_calls_info_t *)listinfo->prot_info; + g_string_append_printf(filter_string_fwd, + "(isup.cic == %i and frame.number >= %i and frame.number <= %i and mtp3.network_indicator == %i and ((mtp3.dpc == %i) and (mtp3.opc == %i)) or ((mtp3.dpc == %i) and (mtp3.opc == %i)))", + isupinfo->cic, listinfo->start_fd->num, + listinfo->stop_fd->num, + isupinfo->ni, isupinfo->dpc, isupinfo->opc, + isupinfo->opc, isupinfo->dpc + ); + break; + case VOIP_H323: + h323info = (h323_calls_info_t *)listinfo->prot_info; + g_string_append_printf(filter_string_fwd, + "((h225.guid == %s || q931.call_ref == %x:%x || q931.call_ref == %x:%x)", + guid_to_ep_str(&h323info->guid[0]), + (guint8) (h323info->q931_crv & 0x00ff), + (guint8)((h323info->q931_crv & 0xff00)>>8), + (guint8) (h323info->q931_crv2 & 0x00ff), + (guint8)((h323info->q931_crv2 & 0xff00)>>8)); + listb = g_list_first(h323info->h245_list); + while (listb) { + h245_add = (h245_address_t *)listb->data; + g_string_append_printf(filter_string_fwd, + " || (ip.addr == %s && tcp.port == %d && h245)", + ip_to_str((guint8 *)(h245_add->h245_address.data)), h245_add->h245_port); + listb = g_list_next(listb); + } + g_string_append_printf(filter_string_fwd, ")"); + break; + case TEL_H248: + ctx = (gcp_ctx_t *)listinfo->prot_info; + g_string_append_printf(filter_string_fwd, + "(h248.ctx == 0x%x)", ctx->id); + break; + default: + /* placeholder to assure valid display filter expression */ + g_string_append_printf(filter_string_fwd, + "(frame)"); + break; + } + is_first = FALSE; + } + lista = g_list_next(lista); + } + + g_string_append_printf(filter_string_fwd, ")"); + gtk_editable_insert_text(GTK_EDITABLE(main_display_filter_widget), filter_string_fwd->str, -1, &pos); + } +#endif + + emit updateFilter(filter_str); +} + +void VoipCallsDialog::showSequence() +{ + if (!cap_file_) return; + + QSet<guint16> selected_calls; + foreach (QTreeWidgetItem *ti, ui->callTreeWidget->selectedItems()) { + voip_calls_info_t *call_info = ti->data(0, Qt::UserRole).value<voip_calls_info_t*>(); + selected_calls << call_info->call_num; + } + + sequence_analysis_list_sort(tapinfo_.graph_analysis); + GList *cur_ga_item = g_queue_peek_nth_link(tapinfo_.graph_analysis->items, 0); + while (cur_ga_item && cur_ga_item->data) { + seq_analysis_item_t *ga_item = (seq_analysis_item_t*) cur_ga_item->data; + ga_item->display = selected_calls.contains(ga_item->conv_num); + cur_ga_item = g_list_next(cur_ga_item); + } + + SequenceDialog *sequence_dialog = new SequenceDialog(this, cap_file_, tapinfo_.graph_analysis); + // XXX This goes away when we close the VoIP Calls dialog. + connect(sequence_dialog, SIGNAL(goToPacket(int)), + this, SIGNAL(goToPacket(int))); + connect(this, SIGNAL(captureFileChanged(capture_file*)), + sequence_dialog, SLOT(setCaptureFile(capture_file*))); + sequence_dialog->show(); +} + +void VoipCallsDialog::on_callTreeWidget_itemActivated(QTreeWidgetItem *item, int) +{ + voip_calls_info_t *call_info = item->data(0, Qt::UserRole).value<voip_calls_info_t*>(); + if (!call_info) { + return; + } + emit goToPacket(call_info->start_fd->num); +} + +void VoipCallsDialog::on_callTreeWidget_itemSelectionChanged() +{ + updateWidgets(); +} + +void VoipCallsDialog::on_actionSelect_All_triggered() +{ + ui->callTreeWidget->selectAll(); +} + +void VoipCallsDialog::on_buttonBox_clicked(QAbstractButton *button) +{ + if (button == prepare_button_) { + prepareFilter(); + } else if (button == sequence_button_) { + showSequence(); + } +} + +void VoipCallsDialog::on_buttonBox_helpRequested() +{ + wsApp->helpTopicAction(HELP_TELEPHONY_VOIP_CALLS_DIALOG); +} + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/voip_calls_dialog.h b/ui/qt/voip_calls_dialog.h new file mode 100644 index 0000000000..16391b683d --- /dev/null +++ b/ui/qt/voip_calls_dialog.h @@ -0,0 +1,107 @@ +/* voip_calls_dialog.h + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef VOIP_CALLS_DIALOG_H +#define VOIP_CALLS_DIALOG_H + +#include "config.h" + +#include <glib.h> + +#include "cfile.h" + +#include "ui/voip_calls.h" + +#include <QDialog> +#include <QMenu> + +class QAbstractButton; +class QTreeWidgetItem; + +namespace Ui { +class VoipCallsDialog; +} + +class QTreeWidgetItem; +class VoipCallsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit VoipCallsDialog(QWidget *parent = 0, capture_file *cf = NULL, bool all_flows = false); + ~VoipCallsDialog(); + +public slots: + void setCaptureFile(capture_file *cf); + +signals: + void updateFilter(QString &filter, bool force = false); + void captureFileChanged(capture_file *cf); + void goToPacket(int packet_num); + +protected: + void contextMenuEvent(QContextMenuEvent *event); + +protected slots: + void changeEvent(QEvent* event); + +private: + Ui::VoipCallsDialog *ui; + + capture_file *cap_file_; + voip_calls_tapinfo_t tapinfo_; + QPushButton *prepare_button_; + QPushButton *sequence_button_; + QPushButton *player_button_; + QMenu ctx_menu_; + + // Tap callbacks +// static void tapReset(void *tapinfo_ptr); + static gboolean tapPacket(void *tapinfo_ptr, packet_info *pinfo, epan_dissect_t *, const void *data); + static void tapDraw(void *tapinfo_ptr); + + void updateCalls(); + void updateWidgets(); + void prepareFilter(); + void showSequence(); + +private slots: + void on_callTreeWidget_itemActivated(QTreeWidgetItem *item, int); + void on_callTreeWidget_itemSelectionChanged(); + void on_actionSelect_All_triggered(); + void on_buttonBox_clicked(QAbstractButton *button); + void on_buttonBox_helpRequested(); +}; + +#endif // VOIP_CALLS_DIALOG_H + +/* + * Editor modelines + * + * Local Variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * ex: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */ diff --git a/ui/qt/voip_calls_dialog.ui b/ui/qt/voip_calls_dialog.ui new file mode 100644 index 0000000000..27ec107427 --- /dev/null +++ b/ui/qt/voip_calls_dialog.ui @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VoipCallsDialog</class> + <widget class="QDialog" name="VoipCallsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>750</width> + <height>430</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTreeWidget" name="callTreeWidget"> + <property name="selectionMode"> + <enum>QAbstractItemView::ExtendedSelection</enum> + </property> + <property name="textElideMode"> + <enum>Qt::ElideMiddle</enum> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="itemsExpandable"> + <bool>false</bool> + </property> + <column> + <property name="text"> + <string>Start Time</string> + </property> + </column> + <column> + <property name="text"> + <string>Stop Time</string> + </property> + </column> + <column> + <property name="text"> + <string>Initial Speaker</string> + </property> + </column> + <column> + <property name="text"> + <string>From</string> + </property> + </column> + <column> + <property name="text"> + <string>To</string> + </property> + </column> + <column> + <property name="text"> + <string>Protocol</string> + </property> + </column> + <column> + <property name="text"> + <string>Packets</string> + </property> + </column> + <column> + <property name="text"> + <string>State</string> + </property> + </column> + <column> + <property name="text"> + <string>Comments</string> + </property> + </column> + </widget> + </item> + <item> + <widget class="QLabel" name="hintLabel"> + <property name="text"> + <string><small></small></string> + </property> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + <action name="actionSelect_All"> + <property name="text"> + <string>Select &All</string> + </property> + <property name="toolTip"> + <string>Select all calls</string> + </property> + <property name="shortcut"> + <string>Ctrl+A</string> + </property> + </action> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>VoipCallsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>VoipCallsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> |