aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorGerald Combs <gerald@wireshark.org>2014-11-18 16:21:42 -0800
committerGerald Combs <gerald@wireshark.org>2014-12-09 21:25:33 +0000
commit4921e559906aee70c4665f1c739057e227787e01 (patch)
tree4465cb9e9de152bfb57f00852e437994e2d85cd9 /ui
parent3147087de323c0294b51006f97b641fc408f1b06 (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')
-rw-r--r--ui/gtk/voip_calls_dlg.c22
-rw-r--r--ui/help_url.c3
-rw-r--r--ui/help_url.h3
-rw-r--r--ui/qt/CMakeLists.txt3
-rw-r--r--ui/qt/Makefile.am2
-rw-r--r--ui/qt/Makefile.common8
-rw-r--r--ui/qt/Wireshark.pro13
-rw-r--r--ui/qt/follow_stream_dialog.cpp1
-rw-r--r--ui/qt/main_window.h3
-rw-r--r--ui/qt/main_window.ui18
-rw-r--r--ui/qt/main_window_slots.cpp23
-rw-r--r--ui/qt/sequence_diagram.cpp9
-rw-r--r--ui/qt/sequence_diagram.h2
-rw-r--r--ui/qt/sequence_dialog.cpp101
-rw-r--r--ui/qt/sequence_dialog.h12
-rw-r--r--ui/qt/sequence_dialog.ui251
-rw-r--r--ui/qt/stock_icon.cpp9
-rw-r--r--ui/qt/voip_calls_dialog.cpp508
-rw-r--r--ui/qt/voip_calls_dialog.h107
-rw-r--r--ui/qt/voip_calls_dialog.ui143
-rw-r--r--ui/tap-sequence-analysis.c33
-rw-r--r--ui/tap-sequence-analysis.h6
-rw-r--r--ui/voip_calls.h18
23 files changed, 1084 insertions, 214 deletions
diff --git a/ui/gtk/voip_calls_dlg.c b/ui/gtk/voip_calls_dlg.c
index 7042f25fa3..79b2fb3a41 100644
--- a/ui/gtk/voip_calls_dlg.c
+++ b/ui/gtk/voip_calls_dlg.c
@@ -41,7 +41,6 @@
#include <epan/epan.h>
#include <epan/packet.h>
#include "wsutil/filesystem.h"
-#include <epan/tap.h>
#include <epan/stat_tap_ui.h>
#include <epan/to_str.h>
#include <epan/address.h>
@@ -125,7 +124,8 @@ voip_calls_get_info(void)
{
/* the one and only global voip_calls_tapinfo_t structure */
static voip_calls_tapinfo_t the_tapinfo_struct =
- {voip_calls_dlg_reset, voip_calls_dlg_packet, voip_calls_dlg_draw,
+ {
+ voip_calls_dlg_reset, voip_calls_dlg_packet, voip_calls_dlg_draw, NULL,
0, NULL, {0}, 0, NULL, 0, 0, 0, NULL, NULL,
0, NULL, /* rtp */
0, 0, FALSE, /* rtp evt */
@@ -332,22 +332,6 @@ voip_calls_on_select_all(GtkButton *button _U_, gpointer user_data _U_)
gtk_tree_selection_select_all(selection);
}
-/* compare two list entries by packet no */
-static gint
-graph_analysis_sort_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
-{
- const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a;
- const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b;
-
- if(entry_a->fd->num < entry_b->fd->num)
- return -1;
-
- if(entry_a->fd->num > entry_b->fd->num)
- return 1;
-
- return 0;
-}
-
/****************************************************************************/
static void
on_graph_bt_clicked(GtkButton *button _U_, gpointer user_data _U_)
@@ -361,7 +345,7 @@ on_graph_bt_clicked(GtkButton *button _U_, gpointer user_data _U_)
if(!tapinfo->graph_analysis){
return;
}
- g_queue_sort(tapinfo->graph_analysis->items, graph_analysis_sort_compare, NULL);
+ sequence_analysis_list_sort(tapinfo->graph_analysis);
/* reset the "display" parameter in graph analysis */
listb = g_queue_peek_nth_link(tapinfo->graph_analysis->items, 0);
diff --git a/ui/help_url.c b/ui/help_url.c
index 1638036c18..a1fa295b20 100644
--- a/ui/help_url.c
+++ b/ui/help_url.c
@@ -333,6 +333,9 @@ topic_action_url(topic_action_e action)
case(HELP_FILTER_SAVE_DIALOG):
url = user_guide_url("ChWorkFilterSaveSection.html");
break;
+ case(HELP_TELEPHONY_VOIP_CALLS_DIALOG):
+ url = user_guide_url("ChTelVoipCalls.html");
+ break;
case(TOPIC_ACTION_NONE):
default:
diff --git a/ui/help_url.h b/ui/help_url.h
index ecaa0b4ee3..7662910a4d 100644
--- a/ui/help_url.h
+++ b/ui/help_url.h
@@ -109,7 +109,8 @@ typedef enum {
HELP_MERGE_WIN32_DIALOG,
HELP_SAVE_WIN32_DIALOG,
HELP_TIME_SHIFT_DIALOG,
- HELP_FILTER_SAVE_DIALOG
+ HELP_FILTER_SAVE_DIALOG,
+ HELP_TELEPHONY_VOIP_CALLS_DIALOG
} topic_action_e;
/** Given a filename return a filesystem URL. Relative paths are prefixed with
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>&amp;VoIP Calls</string>
+ </property>
+ <property name="toolTip">
+ <string>All VoIP Calls</string>
+ </property>
+ </action>
+ <action name="actionTelephonySipFlows">
+ <property name="text">
+ <string>SIP &amp;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>&lt;small&gt;&lt;/small&gt;</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 &amp;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>
diff --git a/ui/tap-sequence-analysis.c b/ui/tap-sequence-analysis.c
index abaf6f19b1..a30ee53eda 100644
--- a/ui/tap-sequence-analysis.c
+++ b/ui/tap-sequence-analysis.c
@@ -256,8 +256,6 @@ sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo)
case SEQ_ANALYSIS_VOIP:
default:
return;
- break;
-
}
cf_retap_packets(cf);
@@ -278,6 +276,31 @@ static void sequence_analysis_item_free(gpointer data)
g_free(data);
}
+
+/* compare two list entries by packet no */
+static gint
+sequence_analysis_sort_compare(gconstpointer a, gconstpointer b, gpointer user_data _U_)
+{
+ const seq_analysis_item_t *entry_a = (const seq_analysis_item_t *)a;
+ const seq_analysis_item_t *entry_b = (const seq_analysis_item_t *)b;
+
+ if(entry_a->fd->num < entry_b->fd->num)
+ return -1;
+
+ if(entry_a->fd->num > entry_b->fd->num)
+ return 1;
+
+ return 0;
+}
+
+
+void
+sequence_analysis_list_sort(seq_analysis_info_t *sainfo)
+{
+ if (!sainfo) return;
+ g_queue_sort(sainfo->items, sequence_analysis_sort_compare, NULL);
+}
+
void
sequence_analysis_list_free(seq_analysis_info_t *sainfo)
{
@@ -380,7 +403,7 @@ static void overwrite (GString *gstr, char *text_to_insert, guint32 p1, guint32
* and Return -2 if the array is full
*/
/****************************************************************************/
-static gint add_or_get_node(seq_analysis_info_t *sainfo, address *node) {
+static guint add_or_get_node(seq_analysis_info_t *sainfo, address *node) {
guint i;
if (node->type == AT_NONE) return NODE_OVERFLOW;
@@ -409,8 +432,8 @@ static void sequence_analysis_get_nodes_item_proc(gpointer data, gpointer user_d
struct sainfo_counter *sc = (struct sainfo_counter *)user_data;
if (gai->display) {
(sc->num_items)++;
- gai->src_node = (guint16)add_or_get_node(sc->sainfo, &(gai->src_addr));
- gai->dst_node = (guint16)add_or_get_node(sc->sainfo, &(gai->dst_addr));
+ gai->src_node = add_or_get_node(sc->sainfo, &(gai->src_addr));
+ gai->dst_node = add_or_get_node(sc->sainfo, &(gai->dst_addr));
}
}
diff --git a/ui/tap-sequence-analysis.h b/ui/tap-sequence-analysis.h
index b8262f7d5b..342f91984e 100644
--- a/ui/tap-sequence-analysis.h
+++ b/ui/tap-sequence-analysis.h
@@ -60,8 +60,8 @@ typedef struct _seq_analysis_item {
gchar *comment; /**< a comment that appears at the right of the graph */
guint16 conv_num; /**< the conversation number, each conversation will be colored */
gboolean display; /**< indicate if the packet is displayed or not in the graph */
- guint16 src_node; /**< this is used by graph_analysis.c to identify the node */
- guint16 dst_node; /**< a node is an IP address that will be displayed in columns */
+ guint src_node; /**< this is used by graph_analysis.c to identify the node */
+ guint dst_node; /**< a node is an IP address that will be displayed in columns */
guint16 line_style; /**< the arrow line width in pixels*/
} seq_analysis_item_t;
@@ -94,6 +94,8 @@ void sequence_analysis_info_free(seq_analysis_info_t * sainfo);
*/
void sequence_analysis_list_get(capture_file *cf, seq_analysis_info_t *sainfo);
+void sequence_analysis_list_sort(seq_analysis_info_t *sainfo);
+
/** Free the segment list
*
* @param sainfo Sequence analysis information.
diff --git a/ui/voip_calls.h b/ui/voip_calls.h
index ccaf2e984f..fc6cdb5904 100644
--- a/ui/voip_calls.h
+++ b/ui/voip_calls.h
@@ -34,11 +34,22 @@
#ifndef __VOIP_CALLS_H__
#define __VOIP_CALLS_H__
+/** @file
+ * "VoIP Calls" dialog box common routines.
+ * @ingroup main_ui_group
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
#include <glib.h>
#include <stdio.h>
#include "epan/address.h"
+#include "epan/packet.h"
#include "epan/guid-utils.h"
+#include "epan/tap.h"
#include "epan/tap-voip.h"
#include "ui/tap-sequence-analysis.h"
@@ -160,7 +171,7 @@ typedef struct _voip_calls_info {
nstime_t start_rel_ts;
frame_data *stop_fd;
nstime_t stop_rel_ts;
- gboolean selected;
+ gboolean selected; /* GTK+ only */
} voip_calls_info_t;
@@ -176,6 +187,7 @@ typedef struct _voip_calls_tapinfo {
tap_reset_cb tap_reset; /**< tap reset callback */
tap_packet_cb tap_packet; /**< tap per-packet callback */
tap_draw_cb tap_draw; /**< tap draw callback */
+ void *tap_data; /**< data for tap callbacks */
int ncalls; /**< number of call */
GQueue* callsinfos; /**< queue with all calls */
GHashTable* callsinfo_hashtable[1]; /**< array of hashes per voip protocol; currently only the one for SIP is used */
@@ -237,6 +249,10 @@ void voip_calls_remove_all_tap_listeners(voip_calls_tapinfo_t *tap_id_base);
*/
void voip_calls_reset_all_taps(voip_calls_tapinfo_t *tapinfo);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
#endif /* __VOIP_CALLS_H__ */
/*