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>
This commit is contained in:
Gerald Combs 2014-11-18 16:21:42 -08:00
parent 3147087de3
commit 4921e55990
33 changed files with 1304 additions and 224 deletions

View File

@ -529,7 +529,12 @@ if(BUILD_wireshark)
set( QT5_DLL_PATH "${QT5_BASE_PATH}/bin" )
set( WS_ALL_LIBS ${WS_ALL_LIBS} ${QT5_DLL_PATH} )
endif()
set(PACKAGELIST ${PACKAGELIST} Qt5Widgets Qt5PrintSupport Qt5LinguistTools)
set(PACKAGELIST ${PACKAGELIST}
Qt5LinguistTools
Qt5MultimediaWidgets
Qt5PrintSupport
Qt5Widgets
)
if (APPLE)
set(PACKAGELIST ${PACKAGELIST} Qt5MacExtras)
endif()
@ -732,6 +737,11 @@ if (Qt5Widgets_FOUND)
endif()
set (QT_FOUND ON)
set (QT_LIBRARIES ${Qt5Widgets_LIBRARIES} ${Qt5PrintSupport_LIBRARIES})
if(Qt5MultimediaWidgets_FOUND)
set (QT_LIBRARIES ${QT_LIBRARIES} ${Qt5MultimediaWidgets_LIBRARIES})
# That's the name autofoo uses
set(QT_MULTIMEDIAWIDGETS_LIB 1)
endif()
if(Qt5MacExtras_FOUND)
set (QT_LIBRARIES ${QT_LIBRARIES} ${Qt5MacExtras_LIBRARIES})
# That's the name autofoo uses

View File

@ -2121,6 +2121,13 @@ AC_DEFUN([AC_WIRESHARK_QT_CHECK],
#
AC_WIRESHARK_QT_MODULE_CHECK(PrintSupport, $1)
#
# Qt 5.0 added multimedia widgets in the Qt
# MultimediaWidgets module.
#
AC_WIRESHARK_QT_MODULE_CHECK(MultimediaWidgets, $1,
AC_DEFINE(QT_MULTIMEDIAWIDGETS_LIB, 1, [Define if we have QtMultimediaWidgets]))
#
# While we're at it, look for QtMacExtras. (Presumably
# if we're not building for OS X, it won't be present.)

View File

@ -368,6 +368,9 @@
/* Define if we are using version of of the Portaudio library API */
#cmakedefine PORTAUDIO_API_1 1
/* Define if we have QtMultimediaWidgets */
#cmakedefine QT_MULTIMEDIAWIDGETS_LIB 1
/* Define if we have QtMacExtras */
#cmakedefine QT_MACEXTRAS_LIB 1

View File

@ -34,6 +34,7 @@ reassembled packets.
description to be shown in the status bar.
** An Italian translation has been added.
** The Summary dialog has been updated and renamed to Capture File Properties.
** The VoIP Calls and SIP Flows dialogs have been added.
The following features are new (or have been significantly updated)
since version 1.12.0:

View File

@ -1720,7 +1720,7 @@ endif()
ABICHECK(libwireshark)
file(GLOB COLUMN_INFO_HEADER column-info.h)
file(GLOB EPAN_HEADERS *.h)
file(GLOB CRYPT_HEADERS crypt/*.h)
file(GLOB COMPRESS_HEADERS compress/*.h)
file(GLOB DFILTER_HEADERS dfilter/*.h ../tools/lemon/cppmagic.h)

View File

@ -9,6 +9,8 @@
<file>copy-8.png</file>
</qresource>
<qresource prefix="/icons">
<file>toolbar/12x12/media-playback-start.png</file>
<file>toolbar/12x12/media-playback-start@2x.png</file>
<file>toolbar/16x16/edit-find.png</file>
<file>toolbar/16x16/edit-find@2x.png</file>
<file>toolbar/16x16/go-first.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="12"
height="12"
id="svg2"
version="1.1"
inkscape:version="0.48.2 r9819"
sodipodi:docname="media-playback-start.svg">
<defs
id="defs4">
<linearGradient
id="linearGradient4324">
<stop
style="stop-color:#ffffff;stop-opacity:0.15686275;"
offset="0"
id="stop4326" />
<stop
style="stop-color:#fffffd;stop-opacity:0;"
offset="1"
id="stop4328" />
</linearGradient>
<linearGradient
id="linearGradient4316">
<stop
style="stop-color:#000000;stop-opacity:0.15686275;"
offset="0"
id="stop4318" />
<stop
style="stop-color:#000000;stop-opacity:0;"
offset="1"
id="stop4320" />
</linearGradient>
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective10" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4316"
id="linearGradient4322"
x1="3"
y1="3.9245384"
x2="0"
y2="1.0377871"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4324"
id="linearGradient4330"
x1="-1"
y1="-0.8867138"
x2="2"
y2="2.0000374"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="44.416667"
inkscape:cx="6"
inkscape:cy="6"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:window-width="1261"
inkscape:window-height="702"
inkscape:window-x="1701"
inkscape:window-y="76"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2983"
empspacing="2"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1040.3622)">
<path
inkscape:transform-center-y="-3.9e-05"
inkscape:transform-center-x="-1.25"
transform="matrix(1,0,0,1.0392305,3,1044.2837)"
d="m 7,2 -7.5,4.330127 0,-8.660254 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="true"
sodipodi:arg2="1.0471976"
sodipodi:arg1="0"
sodipodi:r2="2.5"
sodipodi:r1="5"
sodipodi:cy="2"
sodipodi:cx="2"
sodipodi:sides="3"
id="path3802"
style="fill:#888a85;fill-opacity:1;stroke:#555753;stroke-width:0.98094367999999998;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="star" />
<path
sodipodi:type="star"
style="fill:#888a85;fill-opacity:1;stroke:#555753;stroke-width:0.98094367999999998;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path4312"
sodipodi:sides="3"
sodipodi:cx="2"
sodipodi:cy="2"
sodipodi:r1="5"
sodipodi:r2="2.5"
sodipodi:arg1="0"
sodipodi:arg2="1.0471976"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 7,2 -7.5,4.330127 0,-8.660254 z"
transform="matrix(1,0,0,1.0392305,3,1044.2837)"
inkscape:transform-center-x="-1.25"
inkscape:transform-center-y="-3.9e-05" />
<path
sodipodi:type="star"
style="fill:url(#linearGradient4330);fill-opacity:1;stroke:#555753;stroke-width:0.98094367999999998;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path3760"
sodipodi:sides="3"
sodipodi:cx="2"
sodipodi:cy="2"
sodipodi:r1="5"
sodipodi:r2="2.5"
sodipodi:arg1="0"
sodipodi:arg2="1.0471976"
inkscape:flatsided="true"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 7,2 -7.5,4.330127 0,-8.660254 z"
transform="matrix(1,0,0,1.0392305,3,1044.2837)"
inkscape:transform-center-x="-1.25"
inkscape:transform-center-y="-3.9e-05" />
<path
inkscape:transform-center-y="-3.9e-05"
inkscape:transform-center-x="-1.25"
transform="matrix(1,0,0,1.0392305,3,1044.2837)"
d="m 7,2 -7.5,4.330127 0,-8.660254 z"
inkscape:randomized="0"
inkscape:rounded="0"
inkscape:flatsided="true"
sodipodi:arg2="1.0471976"
sodipodi:arg1="0"
sodipodi:r2="2.5"
sodipodi:r1="5"
sodipodi:cy="2"
sodipodi:cx="2"
sodipodi:sides="3"
id="path4314"
style="fill:url(#linearGradient4322);fill-opacity:1;stroke:#555753;stroke-width:0.98094367999999998;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
sodipodi:type="star" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

View File

@ -43,10 +43,6 @@ set_source_svgs() {
if [ ! -f ${TWO_X_SVG} ] ; then
TWO_X_SVG=$ONE_X_SVG
fi
if [ ! -f ${ONE_X_SVG} ] ; then
>&2 echo "Can't find ${ONE_X_SVG}"
exit 1
fi
}
ICONS="
@ -56,6 +52,7 @@ ICONS="
go-last
go-next
go-previous
media-playback-start
x-capture-file-close
x-capture-file-save
x-capture-file-reload
@ -75,7 +72,7 @@ ICONS="
QRC_FILES=""
# XXX Add support for 16 pixel icons.
for SIZE in 16 24 ; do
for SIZE in 12 16 24 ; do
SIZE_DIR=${SIZE}x${SIZE}
TWO_X_SIZE=`expr $SIZE \* 2`
@ -87,6 +84,11 @@ for SIZE in 16 24 ; do
for ICON in $ICONS ; do
set_source_svgs $ICON
if [ ! -f ${ONE_X_SVG} ] ; then
>&2 echo "Skipping ${ONE_X_SVG}"
continue
fi
ONE_X_PNG=${ICON}.png
TWO_X_PNG=${ICON}@2x.png
@ -100,15 +102,15 @@ for SIZE in 16 24 ; do
--file=$TWO_X_SVG --export-png=$TWO_X_PNG || exit 1
fi
QRC_FILES="${QRC_FILES} ${ONE_X_PNG} ${TWO_X_PNG}"
QRC_FILES="${QRC_FILES} ${SIZE_DIR}/${ONE_X_PNG} ${SIZE_DIR}/${TWO_X_PNG}"
done
cd ..
done
for QRC_FILE in $QRC_FILES ; do
echo " <file>toolbar/${SIZE_DIR}/${QRC_FILE}</file>"
echo " <file>toolbar/${QRC_FILE}</file>"
done
#

View File

@ -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);

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 = \

View File

@ -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

View File

@ -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);

View File

@ -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);
};

View File

@ -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>

View File

@ -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() {

View File

@ -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_) {

View File

@ -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:

View File

@ -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()
{
QCustomPlot *sp = ui->sequencePlot;
seq_analysis_info_t new_sa;
if (!sainfo_) return;
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;
QCustomPlot *sp = ui->sequencePlot;
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();
}

View File

@ -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_;

View File

@ -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>

View File

@ -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);
}

508
ui/qt/voip_calls_dialog.cpp Normal file
View File

@ -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:
*/

107
ui/qt/voip_calls_dialog.h Normal file
View File

@ -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:
*/

143
ui/qt/voip_calls_dialog.ui Normal file
View File

@ -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>

View File

@ -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));
}
}

View File

@ -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.

View File

@ -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__ */
/*