aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/follow.c26
-rw-r--r--epan/follow.h33
-rw-r--r--ui/gtk/follow_ssl.c2
-rw-r--r--ui/gtk/follow_tcp.c2
-rw-r--r--ui/gtk/follow_udp.c2
-rw-r--r--ui/qt/follow_stream_dialog.cpp501
-rw-r--r--ui/qt/follow_stream_dialog.h85
-rw-r--r--ui/qt/follow_stream_dialog.ui31
-rw-r--r--ui/qt/main_window.cpp1
-rw-r--r--ui/qt/main_window.h3
-rw-r--r--ui/qt/main_window_slots.cpp53
-rw-r--r--ui/qt/sequence_dialog.cpp13
-rw-r--r--wsutil/tempfile.h4
13 files changed, 428 insertions, 328 deletions
diff --git a/epan/follow.c b/epan/follow.c
index 4e26a5bad7..ed930c12b4 100644
--- a/epan/follow.c
+++ b/epan/follow.c
@@ -58,7 +58,7 @@ FILE* data_out_file = NULL;
gboolean empty_tcp_stream;
gboolean incomplete_tcp_stream;
-static guint32 tcp_stream_to_follow;
+static guint32 tcp_stream_to_follow = 0;
static guint8 ip_address[2][MAX_IPADDR_LEN];
static guint port[2];
static guint bytes_written[2];
@@ -80,12 +80,12 @@ follow_stats(follow_stats_t* stats)
}
}
-/* this will build libpcap filter text that will only
+/* This will build a display filter text that will only
pass the packets related to the stream. There is a
chance that two streams could intersect, but not a
very good one */
-char*
-build_follow_filter( packet_info *pi ) {
+gchar*
+build_follow_conv_filter( packet_info *pi ) {
char* buf;
int len;
conversation_t *conv=NULL;
@@ -148,6 +148,15 @@ static gboolean find_tcp_addr;
static address tcp_addr[2];
static gboolean find_tcp_index;
+gchar*
+build_follow_index_filter(void) {
+ gchar *buf;
+
+ find_tcp_addr = TRUE;
+ buf = g_strdup_printf("tcp.stream eq %d", tcp_stream_to_follow);
+ return buf;
+}
+
/* select a tcp stream to follow via it's address/port pairs */
gboolean
follow_tcp_addr(const address *addr0, guint port0,
@@ -192,6 +201,10 @@ follow_tcp_index(guint32 indx)
return FALSE;
}
+ if (indx > get_tcp_stream_count()) {
+ return FALSE;
+ }
+
find_tcp_addr = TRUE;
tcp_stream_to_follow = indx;
memset(ip_address, 0, sizeof ip_address);
@@ -200,6 +213,11 @@ follow_tcp_index(guint32 indx)
return TRUE;
}
+guint32
+get_follow_tcp_index(void) {
+ return tcp_stream_to_follow;
+}
+
/* here we are going to try and reconstruct the data portion of a TCP
session. We will try and handle duplicates, TCP fragments, and out
of order packets in a smart way. */
diff --git a/epan/follow.h b/epan/follow.h
index cd92221aa5..b1e02dbcad 100644
--- a/epan/follow.h
+++ b/epan/follow.h
@@ -46,12 +46,43 @@ typedef struct _tcp_stream_chunk {
guint32 dlen;
} tcp_stream_chunk;
+/** Build a follow filter based on the current packet's conversation.
+ *
+ * @param packet_info[in] The current packet.
+ * @return A filter that specifies the conversation. Must be g_free()d
+ * the caller.
+ */
+WS_DLL_PUBLIC
+gchar* build_follow_conv_filter( packet_info * );
+
+/** Build a follow filter based on the current TCP stream index.
+ * follow_tcp_index() must be called prior to calling this.
+ *
+ * @return A filter that specifies the current stream. Must be g_free()d
+ * the caller.
+ */
WS_DLL_PUBLIC
-char* build_follow_filter( packet_info * );
+gchar* build_follow_index_filter(void);
+
WS_DLL_PUBLIC
gboolean follow_tcp_addr( const address *, guint, const address *, guint );
+
+/** Select a TCP stream to follow via its index.
+ *
+ * @param addr[in] The stream index to follow.
+ * @return TRUE on success, FALSE on failure.
+ */
WS_DLL_PUBLIC
gboolean follow_tcp_index( guint32 );
+
+/** Get the current TCP index being followed.
+ *
+ * @return The current TCP index. The behavior is undefined
+ * if no TCP stream is being followed.
+ */
+WS_DLL_PUBLIC
+guint32 get_follow_tcp_index(void);
+
void reassemble_tcp( guint32, guint32, guint32, guint32, const char*, guint32,
int, address *, address *, guint, guint );
WS_DLL_PUBLIC
diff --git a/ui/gtk/follow_ssl.c b/ui/gtk/follow_ssl.c
index 8ef803bc70..7e826e9211 100644
--- a/ui/gtk/follow_ssl.c
+++ b/ui/gtk/follow_ssl.c
@@ -167,7 +167,7 @@ follow_ssl_stream_cb(GtkWidget * w _U_, gpointer data _U_)
/* Create a new filter that matches all packets in the SSL stream,
and set the display filter entry accordingly */
reset_tcp_reassembly();
- follow_filter = build_follow_filter(&cfile.edt->pi);
+ follow_filter = build_follow_conv_filter(&cfile.edt->pi);
if (!follow_filter)
{
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
diff --git a/ui/gtk/follow_tcp.c b/ui/gtk/follow_tcp.c
index 14651d68d9..9325309994 100644
--- a/ui/gtk/follow_tcp.c
+++ b/ui/gtk/follow_tcp.c
@@ -121,7 +121,7 @@ follow_tcp_stream_cb(GtkWidget * w _U_, gpointer data _U_)
/* Create a new filter that matches all packets in the TCP stream,
and set the display filter entry accordingly */
reset_tcp_reassembly();
- follow_filter = build_follow_filter(&cfile.edt->pi);
+ follow_filter = build_follow_conv_filter(&cfile.edt->pi);
if (!follow_filter) {
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
"Error creating filter for this stream.\n"
diff --git a/ui/gtk/follow_udp.c b/ui/gtk/follow_udp.c
index 93a5106b7e..3980d3c9c2 100644
--- a/ui/gtk/follow_udp.c
+++ b/ui/gtk/follow_udp.c
@@ -109,7 +109,7 @@ follow_udp_stream_cb(GtkWidget *w _U_, gpointer data _U_)
/* Create a new filter that matches all packets in the UDP stream,
and set the display filter entry accordingly */
- follow_filter = build_follow_filter(&cfile.edt->pi);
+ follow_filter = build_follow_conv_filter(&cfile.edt->pi);
if (!follow_filter)
{
simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
diff --git a/ui/qt/follow_stream_dialog.cpp b/ui/qt/follow_stream_dialog.cpp
index 4407c0b266..a06dd63b70 100644
--- a/ui/qt/follow_stream_dialog.cpp
+++ b/ui/qt/follow_stream_dialog.cpp
@@ -29,25 +29,27 @@
#include "epan/follow.h"
#include "epan/dissectors/packet-ipv6.h"
+#include "epan/dissectors/packet-tcp.h"
#include "epan/prefs.h"
#include "epan/charsets.h"
#include "epan/epan_dissect.h"
#include "epan/ipproto.h"
#include "epan/tap.h"
-#include "file.h"
#include "ui/alert_box.h"
#include "ui/simple_dialog.h"
#include "ui/utf8_entities.h"
+
#include "wsutil/tempfile.h"
#include "wsutil/file_util.h"
+#include "wsutil/str_util.h"
+
#include "ws_symbol_export.h"
#include "color_utils.h"
#include "qt_ui_utils.h"
#include "wireshark_application.h"
-#include "globals.h"
#include "file.h"
#include "version_info.h"
@@ -65,30 +67,40 @@
#include <QTextEdit>
#include <QTextStream>
-FollowStreamDialog::FollowStreamDialog(QWidget *parent) :
+FollowStreamDialog::FollowStreamDialog(QWidget *parent, follow_type_t type, capture_file *cf) :
QDialog(parent),
- ui(new Ui::FollowStreamDialog)
+ ui(new Ui::FollowStreamDialog),
+ cap_file_(cf),
+ follow_type_(type),
+ save_as_(false)
{
- follow_info = NULL;
ui->setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ memset(&follow_info_, 0, sizeof(follow_info_));
+
ui->teStreamContent->installEventFilter(this);
- connect(ui->buttonBox, SIGNAL(helpRequested()), this, SLOT(HelpButton()));
+ connect(ui->buttonBox, SIGNAL(helpRequested()), this, SLOT(helpButton()));
- bFilterOut = ui->buttonBox->addButton(tr("Hide this stream"), QDialogButtonBox::ActionRole);
- connect(bFilterOut, SIGNAL(clicked()), this, SLOT(FilterOut()));
+ b_filter_out_ = ui->buttonBox->addButton(tr("Hide this stream"), QDialogButtonBox::ActionRole);
+ connect(b_filter_out_, SIGNAL(clicked()), this, SLOT(filterOut()));
- bPrint = ui->buttonBox->addButton(tr("Print"), QDialogButtonBox::ActionRole);
- connect(bPrint, SIGNAL(clicked()), this, SLOT(Print()));
+ b_print_ = ui->buttonBox->addButton(tr("Print"), QDialogButtonBox::ActionRole);
+ connect(b_print_, SIGNAL(clicked()), this, SLOT(printStream()));
- bSave = ui->buttonBox->addButton(tr("Save as..."), QDialogButtonBox::ActionRole);
- connect(bSave, SIGNAL(clicked()), this, SLOT(SaveAs()));
+ b_save_ = ui->buttonBox->addButton(tr("Save as..."), QDialogButtonBox::ActionRole);
+ connect(b_save_, SIGNAL(clicked()), this, SLOT(saveAs()));
- save_as = false;
}
-void FollowStreamDialog::Print()
+FollowStreamDialog::~FollowStreamDialog()
+{
+ delete ui;
+ resetStream(); // Frees payload
+}
+
+void FollowStreamDialog::printStream()
{
#ifndef QT_NO_PRINTER
QPrinter printer(QPrinter::HighResolution);
@@ -98,7 +110,7 @@ void FollowStreamDialog::Print()
#endif
}
-void FollowStreamDialog::FindText(bool go_back)
+void FollowStreamDialog::findText(bool go_back)
{
if (ui->leFind->text().isEmpty()) return;
@@ -108,60 +120,56 @@ void FollowStreamDialog::FindText(bool go_back)
ui->teStreamContent->setFocus();
} else if (go_back) {
ui->teStreamContent->moveCursor(QTextCursor::Start);
- FindText(false);
+ findText(false);
}
}
-void FollowStreamDialog::SaveAs()
+void FollowStreamDialog::saveAs()
{
QString file_name = QFileDialog::getSaveFileName(this, "Wireshark: Save stream content as");
- file.setFileName(file_name);
- file.open( QIODevice::WriteOnly );
- QTextStream out(&file);
+ file_.setFileName(file_name);
+ file_.open( QIODevice::WriteOnly );
+ QTextStream out(&file_);
- save_as = true;
+ save_as_ = true;
follow_read_stream();
- if (follow_info->show_type != SHOW_RAW)
+ if (follow_info_.show_type != SHOW_RAW)
{
out << ui->teStreamContent->toPlainText();
}
- save_as = false;
+ save_as_ = false;
- file.close();
+ file_.close();
}
-void FollowStreamDialog::HelpButton()
+void FollowStreamDialog::helpButton()
{
wsApp->helpTopicAction(HELP_FOLLOW_STREAM_DIALOG);
}
-void FollowStreamDialog::FilterOut()
+void FollowStreamDialog::filterOut()
{
- QString filter = QString(follow_info->filter_out_filter);
- emit updateFilter(filter, TRUE);
+ emit updateFilter(filter_out_filter_, TRUE);
this->close();
}
void FollowStreamDialog::on_cbDirections_currentIndexChanged(int index)
{
- if (!follow_info)
- return;
-
switch(index)
{
case 0 :
- follow_info->show_stream = BOTH_HOSTS;
+ follow_info_.show_stream = BOTH_HOSTS;
break;
case 1 :
- follow_info->show_stream = FROM_SERVER;
+ follow_info_.show_stream = FROM_SERVER;
break;
case 2 :
- follow_info->show_stream = FROM_CLIENT;
+ follow_info_.show_stream = FROM_CLIENT;
break;
default:
return;
@@ -175,23 +183,23 @@ void FollowStreamDialog::on_cbCharset_currentIndexChanged(int index)
switch (index)
{
case 0:
- follow_info->show_type = SHOW_ASCII;
+ follow_info_.show_type = SHOW_ASCII;
break;
case 1:
- follow_info->show_type = SHOW_EBCDIC;
+ follow_info_.show_type = SHOW_EBCDIC;
break;
case 2:
- follow_info->show_type = SHOW_CARRAY;
+ follow_info_.show_type = SHOW_CARRAY;
break;
case 3:
- follow_info->show_type = SHOW_HEXDUMP;
+ follow_info_.show_type = SHOW_HEXDUMP;
break;
case 4:
- follow_info->show_type = SHOW_RAW;
+ follow_info_.show_type = SHOW_RAW;
break;
default:
@@ -203,17 +211,46 @@ void FollowStreamDialog::on_cbCharset_currentIndexChanged(int index)
void FollowStreamDialog::on_bFind_clicked()
{
- FindText();
+ findText();
}
void FollowStreamDialog::on_leFind_returnPressed()
{
- FindText();
+ findText();
+}
+
+void FollowStreamDialog::on_streamNumberSpinBox_valueChanged(int stream_num)
+{
+ if (stream_num >= 0) {
+ follow_tcp_index(stream_num);
+ follow(QString(), true);
+ }
}
+// Not sure why we have to do this manually.
void FollowStreamDialog::on_buttonBox_rejected()
{
- hide();
+ reject();
+}
+
+void FollowStreamDialog::removeStreamControls()
+{
+ ui->horizontalLayout->removeItem(ui->streamNumberSpacer);
+ ui->streamNumberLabel->setVisible(false);
+ ui->streamNumberSpinBox->setVisible(false);
+}
+
+void FollowStreamDialog::resetStream()
+{
+ GList *cur;
+
+ filter_out_filter_.clear();
+ if (!data_out_filename_.isEmpty()) ws_unlink(data_out_filename_.toUtf8().constData());
+ for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) {
+ g_free(cur->data);
+ }
+ g_list_free(follow_info_.payload);
+ follow_info_.payload = NULL;
}
frs_return_t
@@ -221,7 +258,7 @@ FollowStreamDialog::follow_read_stream()
{
ui->teStreamContent->clear();
- switch(follow_info->follow_type) {
+ switch(follow_type_) {
case FOLLOW_TCP :
return follow_read_tcp_stream();
@@ -243,7 +280,7 @@ static int
udp_queue_packet_data(void *tapdata, packet_info *pinfo,
epan_dissect_t *edt, const void *data)
{
- Q_UNUSED(edt)
+ Q_UNUSED(edt);
follow_record_t *follow_record;
follow_info_t *follow_info = (follow_info_t *)tapdata;
@@ -277,7 +314,7 @@ udp_queue_packet_data(void *tapdata, packet_info *pinfo,
static int
ssl_queue_packet_data(void *tapdata, packet_info *pinfo, epan_dissect_t *edt, const void *ssl)
{
- Q_UNUSED(edt)
+ Q_UNUSED(edt);
follow_info_t * follow_info = (follow_info_t*) tapdata;
SslDecryptedRecord * rec = NULL;
@@ -363,18 +400,18 @@ FollowStreamDialog::follow_read_ssl_stream()
GList * cur;
frs_return_t frs_return;
- for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
+ for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) {
SslDecryptedRecord * rec = (SslDecryptedRecord*) cur->data;
gboolean include_rec = FALSE;
if (rec->is_from_server) {
global_pos = &global_server_pos;
- include_rec = (follow_info->show_stream == BOTH_HOSTS) ||
- (follow_info->show_stream == FROM_SERVER);
+ include_rec = (follow_info_.show_stream == BOTH_HOSTS) ||
+ (follow_info_.show_stream == FROM_SERVER);
} else {
global_pos = &global_client_pos;
- include_rec = (follow_info->show_stream == BOTH_HOSTS) ||
- (follow_info->show_stream == FROM_CLIENT);
+ include_rec = (follow_info_.show_stream == BOTH_HOSTS) ||
+ (follow_info_.show_stream == FROM_CLIENT);
}
if (include_rec) {
@@ -398,13 +435,13 @@ FollowStreamDialog::follow_stream()
{
follow_stats_t stats;
- follow_info->show_type = SHOW_RAW;
- follow_info->show_stream = BOTH_HOSTS;
+ follow_info_.show_type = SHOW_RAW;
+ follow_info_.show_stream = BOTH_HOSTS;
/* Stream to show */
follow_stats(&stats);
- follow_info->is_ipv6 = stats.is_ipv6;
+ follow_info_.is_ipv6 = stats.is_ipv6;
follow_read_stream();
ui->teStreamContent->moveCursor(QTextCursor::Start);
@@ -419,11 +456,11 @@ void FollowStreamDialog::add_text(char *buffer, size_t nchars, gboolean is_from_
QString buf;
gchar *str;
- if (save_as == true)
+ if (save_as_ == true)
{
//FILE *fh = (FILE *)arg;
size_t nwritten;
- int FileDescriptor = file.handle();
+ int FileDescriptor = file_.handle();
FILE* fh = fdopen(dup(FileDescriptor), "wb");
nwritten = fwrite(buffer, 1, nchars, fh);
fclose(fh);
@@ -469,6 +506,14 @@ void FollowStreamDialog::add_text(char *buffer, size_t nchars, gboolean is_from_
}
}
+void FollowStreamDialog::setCaptureFile(capture_file *cf)
+{
+ if (!cf) { // We only want to know when the file closes.
+ cap_file_ = NULL;
+ ui->streamNumberSpinBox->setEnabled(false);
+ }
+}
+
// The following keyboard shortcuts should work (although
// they may not work consistently depending on focus):
// / (slash), Ctrl-F - Focus and highlight the search box
@@ -476,14 +521,14 @@ void FollowStreamDialog::add_text(char *buffer, size_t nchars, gboolean is_from_
// Should we make it so that typing any text starts searching?
bool FollowStreamDialog::eventFilter(QObject *obj, QEvent *event)
{
- Q_UNUSED(obj)
+ Q_UNUSED(obj);
if (ui->teStreamContent->hasFocus() && event->type() == QEvent::KeyPress) {
ui->leFind->setFocus();
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->matches(QKeySequence::Find)) {
return true;
} else if (keyEvent->matches(QKeySequence::FindNext)) {
- FindText();
+ findText();
return true;
}
}
@@ -495,7 +540,7 @@ void FollowStreamDialog::keyPressEvent(QKeyEvent *event)
{
if (ui->leFind->hasFocus()) {
if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
- FindText();
+ findText();
return;
}
} else {
@@ -507,20 +552,13 @@ void FollowStreamDialog::keyPressEvent(QKeyEvent *event)
}
if (event->key() == Qt::Key_F3 || (event->key() == Qt::Key_N && event->modifiers() & Qt::ControlModifier)) {
- FindText();
+ findText();
return;
}
QDialog::keyPressEvent(event);
}
-void FollowStreamDialog::closeEvent(QCloseEvent *event)
-{
- Q_UNUSED(event)
- hide();
-}
-
-
frs_return_t
FollowStreamDialog::follow_show(char *buffer, size_t nchars, gboolean is_from_server,
guint32 *global_pos, guint32 *server_packet_count,
@@ -530,7 +568,7 @@ FollowStreamDialog::follow_show(char *buffer, size_t nchars, gboolean is_from_se
guint32 current_pos;
static const gchar hexchars[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
- switch (follow_info->show_type) {
+ switch (follow_info_.show_type) {
case SHOW_EBCDIC:
/* If our native arch is ASCII, call: */
@@ -562,7 +600,7 @@ FollowStreamDialog::follow_show(char *buffer, size_t nchars, gboolean is_from_se
/* is_from_server indentation : put 4 spaces at the
* beginning of the string */
/* XXX - We might want to prepend each line with "C" or "S" instead. */
- if (is_from_server && follow_info->show_stream == BOTH_HOSTS) {
+ if (is_from_server && follow_info_.show_stream == BOTH_HOSTS) {
memset(cur, ' ', 4);
cur += 4;
}
@@ -646,48 +684,53 @@ FollowStreamDialog::follow_show(char *buffer, size_t nchars, gboolean is_from_se
return FRS_OK;
}
-
-
-bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
+bool FollowStreamDialog::follow(QString previous_filter, bool use_tcp_index)
{
int tmp_fd;
- gchar *follow_filter;
- const gchar *previous_filter = previous_filter_.toStdString().c_str();
- int filter_out_filter_len, previous_filter_len;
+ QString follow_filter;
const char *hostname0 = NULL, *hostname1 = NULL;
char *port0 = NULL, *port1 = NULL;
- gchar *server_to_client_string = NULL;
- gchar *client_to_server_string = NULL;
- gchar *both_directions_string = NULL;
+ QString server_to_client_string;
+ QString client_to_server_string;
+ QString both_directions_string;
follow_stats_t stats;
tcp_stream_chunk sc;
size_t nchars;
- gchar *data_out_filename;
GString * msg;
- if (cfile.edt == NULL)
+ resetStream();
+
+ if (cap_file_ == NULL)
+ {
+ QMessageBox::warning(this, tr("No capture file."), tr("Please make sure you have a capture file opened."));
+ return false;
+ }
+
+ if (cap_file_->edt == NULL)
{
QMessageBox::warning(this, tr("Error following stream."), tr("Capture file invalid."));
return false;
}
- switch (type)
+ switch (follow_type_)
{
case FOLLOW_TCP:
- if (cfile.edt->pi.ipproto != IP_PROTO_TCP) {
+ if (cap_file_->edt->pi.ipproto != IP_PROTO_TCP) {
QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a TCP packet selected."));
return false;
}
break;
case FOLLOW_UDP:
- if (cfile.edt->pi.ipproto != IP_PROTO_UDP) {
+ removeStreamControls();
+ if (cap_file_->edt->pi.ipproto != IP_PROTO_UDP) {
QMessageBox::warning(this, tr("Error following stream."), tr("Please make sure you have a UDP packet selected."));
return false;
}
break;
case FOLLOW_SSL:
/* we got ssl so we can follow */
- if (!epan_dissect_packet_contains_field(cfile.edt, "ssl")) {
+ removeStreamControls();
+ if (!epan_dissect_packet_contains_field(cap_file_->edt, "ssl")) {
QMessageBox::critical(this, tr("Error following stream"),
tr("Please make sure you have an SSL packet selected."));
return false;
@@ -695,26 +738,26 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
break;
}
- follow_info = g_new0(follow_info_t, 1);
- follow_info->follow_type = type;
-
- if (type == FOLLOW_TCP || type == FOLLOW_SSL)
+ if (follow_type_ == FOLLOW_TCP || follow_type_ == FOLLOW_SSL)
{
/* Create a new filter that matches all packets in the TCP stream,
and set the display filter entry accordingly */
reset_tcp_reassembly();
}
- follow_filter = build_follow_filter(&cfile.edt->pi);
- if (!follow_filter) {
+ if (use_tcp_index) {
+ follow_filter = gchar_free_to_qstring(build_follow_index_filter());
+ } else {
+ follow_filter = gchar_free_to_qstring(build_follow_conv_filter(&cap_file_->edt->pi));
+ }
+ if (follow_filter.isEmpty()) {
QMessageBox::warning(this,
tr("Error creating filter for this stream."),
tr("A transport or network layer header is needed."));
- g_free(follow_info);
return false;
}
- if (type == FOLLOW_TCP || type == FOLLOW_SSL)
+ if (follow_type_ == FOLLOW_TCP || follow_type_ == FOLLOW_SSL)
{
/* Create a temporary file into which to dump the reassembled data
from the TCP stream, and set "data_out_file" to refer to it, so
@@ -724,16 +767,15 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
append stuff to the text widget for the TCP stream window,
if we can arrange that said window not pop up until we're
done. */
+ gchar *data_out_filename;
tmp_fd = create_tempfile(&data_out_filename, "follow");
- follow_info->data_out_filename = g_strdup(data_out_filename);
+ data_out_filename_ = data_out_filename;
if (tmp_fd == -1) {
QMessageBox::warning(this, "Error",
"Could not create temporary file %1: %2",
- follow_info->data_out_filename, g_strerror(errno));
- g_free(follow_info->data_out_filename);
- g_free(follow_info);
- g_free(follow_filter);
+ data_out_filename_, g_strerror(errno));
+ data_out_filename_.clear();
return false;
}
@@ -741,101 +783,88 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
if (data_out_file == NULL) {
QMessageBox::warning(this, "Error",
"Could not create temporary file %1: %2",
- follow_info->data_out_filename, g_strerror(errno));
+ data_out_filename_, g_strerror(errno));
//ws_close(tmp_fd);
- ws_unlink(follow_info->data_out_filename);
- g_free(follow_info->data_out_filename);
- g_free(follow_info);
- g_free(follow_filter);
+ ws_unlink(data_out_filename_.toUtf8().constData());
+ data_out_filename_.clear();
return false;
}
}
- /* allocate our new filter. API claims g_malloc terminates program on failure */
- /* my calc for max alloc needed is really +10 but when did a few extra bytes hurt ? */
- previous_filter_len = previous_filter?(int)strlen(previous_filter):0;
- filter_out_filter_len = (int)(strlen(follow_filter) + strlen(previous_filter) + 16);
- follow_info->filter_out_filter = (gchar *)g_malloc(filter_out_filter_len);
+ /* Allocate our new filter. */
/* append the negation */
- if(previous_filter_len) {
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "%s and !(%s)", previous_filter, follow_filter);
+ if(!previous_filter.isEmpty()) {
+ filter_out_filter_ = QString("%1 and !(%2)")
+ .arg(previous_filter).arg(follow_filter);
}
else
{
- g_snprintf(follow_info->filter_out_filter, filter_out_filter_len,
- "!(%s)", follow_filter);
+ filter_out_filter_ = QString("!(%1)").arg(follow_filter);
}
- switch (type)
+ switch (follow_type_)
{
case FOLLOW_TCP:
+ ui->streamNumberSpinBox->blockSignals(true);
+ ui->streamNumberSpinBox->setMaximum(get_tcp_stream_count() - 1);
+ ui->streamNumberSpinBox->setValue(get_follow_tcp_index());
+ ui->streamNumberSpinBox->blockSignals(false);
break;
case FOLLOW_UDP:
/* data will be passed via tap callback*/
- msg = register_tap_listener("udp_follow", follow_info, follow_filter,
+ msg = register_tap_listener("udp_follow", &follow_info_,
+ follow_filter.toUtf8().constData(),
0, NULL, udp_queue_packet_data, NULL);
if (msg) {
QMessageBox::critical(this, "Error",
"Can't register udp_follow tap: %1",
msg->str);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
- g_free(follow_filter);
return false;
}
break;
case FOLLOW_SSL:
/* we got ssl so we can follow */
- msg = register_tap_listener("ssl", follow_info, follow_filter, 0,
+ msg = register_tap_listener("ssl", &follow_info_,
+ follow_filter.toUtf8().constData(), 0,
NULL, ssl_queue_packet_data, NULL);
if (msg)
{
QMessageBox::critical(this, "Error",
"Can't register ssl tap: %1", msg->str);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
- g_free(follow_filter);
return false;
}
break;
}
-
-
/* Run the display filter so it goes in effect - even if it's the
same as the previous display filter. */
- QString filter = QString(follow_filter);
- emit updateFilter(filter, TRUE);
+ emit updateFilter(follow_filter, TRUE);
- switch (type)
+ switch (follow_type_)
{
case FOLLOW_TCP:
break;
case FOLLOW_UDP:
- remove_tap_listener(follow_info);
+ remove_tap_listener(&follow_info_);
break;
case FOLLOW_SSL:
- remove_tap_listener(follow_info);
+ remove_tap_listener(&follow_info_);
break;
}
-
- if (type == FOLLOW_TCP)
+ if (follow_type_ == FOLLOW_TCP)
{
/* Check whether we got any data written to the file. */
if (empty_tcp_stream) {
QMessageBox::warning(this, "Error",
"The packets in the capture file for that stream have no data.");
//ws_close(tmp_fd);
- ws_unlink(follow_info->data_out_filename);
- g_free(follow_info->data_out_filename);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
+ ws_unlink(data_out_filename_.toUtf8().constData());
+ data_out_filename_.clear();
return false;
}
@@ -845,24 +874,23 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
if (ferror(data_out_file)) {
QMessageBox::warning(this, "Error",
QString(tr("Could not read from temporary file %1: %2"))
- .arg(follow_info->data_out_filename)
+ .arg(data_out_filename_)
.arg(g_strerror(errno)));
} else {
QMessageBox::warning(this, "Error",
QString(tr("Short read from temporary file %1: expected %2, got %3"))
- .arg(follow_info->data_out_filename)
+ .arg(data_out_filename_)
.arg((unsigned long)sizeof(sc))
.arg((unsigned long)nchars));
}
//ws_close(tmp_fd);
- ws_unlink(follow_info->data_out_filename);
- g_free(follow_info->data_out_filename);
- g_free(follow_info->filter_out_filter);
- g_free(follow_info);
+ ws_unlink(data_out_filename_.toUtf8().constData());
+ data_out_filename_.clear();
return false;
}
fclose(data_out_file);
+ data_out_file = NULL;
}
/* Stream to show */
@@ -872,7 +900,7 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
struct e_in6_addr ipaddr;
memcpy(&ipaddr, stats.ip_address[0], 16);
hostname0 = get_hostname6(&ipaddr);
- memcpy(&ipaddr, (type == FOLLOW_TCP) ? stats.ip_address[1] : stats.ip_address[0], 16);
+ memcpy(&ipaddr, (follow_type_ == FOLLOW_TCP) ? stats.ip_address[1] : stats.ip_address[0], 16);
hostname1 = get_hostname6(&ipaddr);
} else {
guint32 ipaddr;
@@ -882,7 +910,7 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
hostname1 = get_hostname(ipaddr);
}
- switch (type)
+ switch (follow_type_)
{
case FOLLOW_TCP:
port0 = get_tcp_port(stats.port[0]);
@@ -898,99 +926,129 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
break;
}
- follow_info->is_ipv6 = stats.is_ipv6;
+ follow_info_.is_ipv6 = stats.is_ipv6;
- if (type == FOLLOW_TCP)
+ if (follow_type_ == FOLLOW_TCP)
{
/* Host 0 --> Host 1 */
if(sc.src_port == stats.port[0]) {
server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- stats.bytes_written[0]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname0).arg(port0)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname1).arg(port1)
+ .arg(gchar_free_to_qstring(format_size(
+ stats.bytes_written[0],
+ format_size_unit_bytes|format_size_prefix_si)));
} else {
server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0,port0,
- stats.bytes_written[0]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname1).arg(port1)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname0).arg(port0)
+ .arg(gchar_free_to_qstring(format_size(
+ stats.bytes_written[0],
+ format_size_unit_bytes|format_size_prefix_si)));
}
/* Host 1 --> Host 0 */
if(sc.src_port == stats.port[1]) {
client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- stats.bytes_written[1]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname0).arg(port0)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname1).arg(port1)
+ .arg(gchar_free_to_qstring(format_size(
+ stats.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
} else {
client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- stats.bytes_written[1]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname1).arg(port1)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname0).arg(port0)
+ .arg(gchar_free_to_qstring(format_size(
+ stats.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
}
}
else
{
- if(follow_info->client_port == stats.port[0]) {
+ if(follow_info_.client_port == stats.port[0]) {
server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[0]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname0).arg(port0)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname1).arg(port1)
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[0],
+ format_size_unit_bytes|format_size_prefix_si)));
client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[1]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname0).arg(port0)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname1).arg(port1)
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
} else {
server_to_client_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname1, port1,
- hostname0, port0,
- follow_info->bytes_written[0]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname1).arg(port1)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname0).arg(port0)
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[0],
+ format_size_unit_bytes|format_size_prefix_si)));
client_to_server_string =
- g_strdup_printf("%s:%s " UTF8_RIGHTWARDS_ARROW " %s:%s (%u bytes)",
- hostname0, port0,
- hostname1, port1,
- follow_info->bytes_written[1]);
+ QString("%1:%2 %3 %4:%5 (%6)")
+ .arg(hostname1).arg(port1)
+ .arg(UTF8_RIGHTWARDS_ARROW)
+ .arg(hostname0).arg(port0)
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
}
}
/* Both Stream Directions */
- switch (type)
+ switch (follow_type_)
{
case FOLLOW_TCP:
- both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", stats.bytes_written[0] + stats.bytes_written[1]);
+ both_directions_string = QString("Entire conversation (%1)")
+ .arg(gchar_free_to_qstring(format_size(
+ stats.bytes_written[0] + stats.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
this->setWindowTitle(QString("Follow TCP Stream (%1)").arg(follow_filter));
break;
case FOLLOW_UDP:
- both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
+ both_directions_string = QString("Entire conversation (%1)")
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
this->setWindowTitle(QString("Follow UDP Stream (%1)").arg(follow_filter));
break;
case FOLLOW_SSL:
- both_directions_string = g_strdup_printf("Entire conversation (%u bytes)", follow_info->bytes_written[0] + follow_info->bytes_written[1]);
+ both_directions_string = QString("Entire conversation (%1)")
+ .arg(gchar_free_to_qstring(format_size(
+ follow_info_.bytes_written[0] + follow_info_.bytes_written[1],
+ format_size_unit_bytes|format_size_prefix_si)));
this->setWindowTitle(QString("Follow SSL Stream (%1)").arg(follow_filter));
break;
}
ui->cbDirections->clear();
- this->ui->cbDirections->addItem(QString(both_directions_string));
- this->ui->cbDirections->addItem(QString(client_to_server_string));
- this->ui->cbDirections->addItem(QString(server_to_client_string));
+ this->ui->cbDirections->addItem(both_directions_string);
+ this->ui->cbDirections->addItem(client_to_server_string);
+ this->ui->cbDirections->addItem(server_to_client_string);
follow_stream();
- /* Free the filter string, as we're done with it. */
- g_free(follow_filter);
-
data_out_file = NULL;
return true;
@@ -1019,7 +1077,7 @@ bool FollowStreamDialog::Follow(QString previous_filter_, follow_type_t type)
frs_return_t
FollowStreamDialog::follow_read_tcp_stream()
{
- FILE *data_out_file;
+ FILE *data_out_fp;
tcp_stream_chunk sc;
size_t bcount;
size_t bytes_read;
@@ -1043,25 +1101,25 @@ FollowStreamDialog::follow_read_tcp_stream()
#endif
- iplen = (follow_info->is_ipv6) ? 16 : 4;
+ iplen = (follow_info_.is_ipv6) ? 16 : 4;
- data_out_file = ws_fopen(follow_info->data_out_filename, "rb");
- if (data_out_file == NULL) {
+ data_out_fp = ws_fopen(data_out_filename_.toUtf8().constData(), "rb");
+ if (data_out_fp == NULL) {
QMessageBox::critical(this, "Error",
- "Could not open temporary file %1: %2", follow_info->data_out_filename,
+ "Could not open temporary file %1: %2", data_out_filename_,
g_strerror(errno));
return FRS_OPEN_ERROR;
}
- while ((nchars=fread(&sc, 1, sizeof(sc), data_out_file))) {
+ while ((nchars=fread(&sc, 1, sizeof(sc), data_out_fp))) {
if (nchars != sizeof(sc)) {
QMessageBox::critical(this, "Error",
QString(tr("Short read from temporary file %1: expected %2, got %3"))
- .arg(follow_info->data_out_filename)
+ .arg(data_out_filename_)
.arg(sizeof(sc))
.arg(nchars));
- fclose(data_out_file);
- data_out_file = NULL;
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return FRS_READ_ERROR;
}
if (client_port == 0) {
@@ -1073,14 +1131,14 @@ FollowStreamDialog::follow_read_tcp_stream()
client_port == sc.src_port) {
is_server = FALSE;
global_pos = &global_client_pos;
- if (follow_info->show_stream == FROM_SERVER) {
+ if (follow_info_.show_stream == FROM_SERVER) {
skip = TRUE;
}
}
else {
is_server = TRUE;
global_pos = &global_server_pos;
- if (follow_info->show_stream == FROM_CLIENT) {
+ if (follow_info_.show_stream == FROM_CLIENT) {
skip = TRUE;
}
}
@@ -1088,7 +1146,7 @@ FollowStreamDialog::follow_read_tcp_stream()
bytes_read = 0;
while (bytes_read < sc.dlen) {
bcount = ((sc.dlen-bytes_read) < FLT_BUF_SIZE) ? (sc.dlen-bytes_read) : FLT_BUF_SIZE;
- nchars = fread(buffer, 1, bcount, data_out_file);
+ nchars = fread(buffer, 1, bcount, data_out_fp);
if (nchars == 0)
break;
/* XXX - if we don't get "bcount" bytes, is that an error? */
@@ -1107,8 +1165,8 @@ FollowStreamDialog::follow_read_tcp_stream()
header_len, is_server, global_pos,
&server_packet_count, &client_packet_count);
if (frs_return == FRS_PRINT_ERROR) {
- fclose(data_out_file);
- data_out_file = NULL;
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return frs_return;
}
@@ -1122,8 +1180,8 @@ FollowStreamDialog::follow_read_tcp_stream()
strm.opaque = Z_NULL;
ret = inflateInit2(&strm, MAX_WBITS+16);
if (ret != Z_OK) {
- fclose(data_out_file);
- data_out_file = NULL;
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return FRS_READ_ERROR;
}
@@ -1143,8 +1201,8 @@ FollowStreamDialog::follow_read_tcp_stream()
ret = inflate(&strm, Z_NO_FLUSH);
if (ret < 0 || ret == Z_NEED_DICT) {
inflateEnd(&strm);
- fclose(data_out_file);
- data_out_file = NULL;
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return FRS_READ_ERROR;
} else if (ret == Z_STREAM_END) {
inflateEnd(&strm);
@@ -1157,8 +1215,8 @@ FollowStreamDialog::follow_read_tcp_stream()
&client_packet_count);
if(frs_return == FRS_PRINT_ERROR) {
inflateEnd(&strm);
- fclose(data_out_file);
- data_out_file = NULL;
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return frs_return;
}
} while (strm.avail_out == 0);
@@ -1172,8 +1230,8 @@ FollowStreamDialog::follow_read_tcp_stream()
&server_packet_count,
&client_packet_count);
if(frs_return == FRS_PRINT_ERROR) {
- fclose(data_out_file);
- data_out_file = NULL;
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return frs_return;
}
@@ -1181,17 +1239,16 @@ FollowStreamDialog::follow_read_tcp_stream()
}
}
- if (ferror(data_out_file)) {
- simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
- "Error reading temporary file %s: %s", follow_info->data_out_filename,
- g_strerror(errno));
- fclose(data_out_file);
- data_out_file = NULL;
+ if (ferror(data_out_fp)) {
+ QMessageBox::critical(this, tr("Error reading temporary file"),
+ QString("%1: %2").arg(data_out_filename_).arg(g_strerror(errno)));
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return FRS_READ_ERROR;
}
- fclose(data_out_file);
- data_out_file = NULL;
+ fclose(data_out_fp);
+ data_out_fp = NULL;
return FRS_OK;
}
@@ -1229,17 +1286,17 @@ FollowStreamDialog::follow_read_udp_stream()
char *buffer;
- for (cur = follow_info->payload; cur; cur = g_list_next(cur)) {
+ for (cur = follow_info_.payload; cur; cur = g_list_next(cur)) {
follow_record = (follow_record_t *)cur->data;
skip = FALSE;
if (!follow_record->is_server) {
global_pos = &global_client_pos;
- if(follow_info->show_stream == FROM_SERVER) {
+ if(follow_info_.show_stream == FROM_SERVER) {
skip = TRUE;
}
} else {
global_pos = &global_server_pos;
- if (follow_info->show_stream == FROM_CLIENT) {
+ if (follow_info_.show_stream == FROM_CLIENT) {
skip = TRUE;
}
}
@@ -1264,12 +1321,6 @@ FollowStreamDialog::follow_read_udp_stream()
return FRS_OK;
}
-
-FollowStreamDialog::~FollowStreamDialog()
-{
- delete ui;
-}
-
/*
* Editor modelines
*
diff --git a/ui/qt/follow_stream_dialog.h b/ui/qt/follow_stream_dialog.h
index 5f8ec74714..ffa3817cb8 100644
--- a/ui/qt/follow_stream_dialog.h
+++ b/ui/qt/follow_stream_dialog.h
@@ -34,6 +34,8 @@
#include <unistd.h>
#endif
+#include "file.h"
+
#include "ui/follow.h"
#include <QDialog>
@@ -44,13 +46,11 @@ extern "C" {
WS_DLL_PUBLIC FILE *data_out_file;
}
+// Shouldn't these be member variables?
typedef struct {
- follow_type_t follow_type;
show_stream_t show_stream;
show_type_t show_type;
- char *data_out_filename;
gboolean is_ipv6;
- char *filter_out_filter;
GList *payload;
guint bytes_written[2]; /* Index with FROM_CLIENT or FROM_SERVER for readability. */
guint client_port;
@@ -66,69 +66,70 @@ class FollowStreamDialog : public QDialog
Q_OBJECT
public:
- explicit FollowStreamDialog(QWidget *parent = 0);
+ explicit FollowStreamDialog(QWidget *parent = 0, follow_type_t type = FOLLOW_TCP, capture_file *cf = NULL);
~FollowStreamDialog();
- bool Follow(QString previous_filter_, follow_type_t type);
-
- frs_return_t
- follow_show(char *buffer, size_t nchars, gboolean is_from_server,
- guint32 *global_pos, guint32 *server_packet_count,
- guint32 *client_packet_count);
-
- frs_return_t
- follow_read_stream();
-
- frs_return_t
- follow_read_tcp_stream();
-
- frs_return_t
- follow_read_udp_stream();
-
- frs_return_t
- follow_read_ssl_stream();
-
- void
- follow_stream();
+ bool follow(QString previous_filter = QString(), bool use_tcp_index = false);
- void add_text(char *buffer, size_t nchars, gboolean is_from_server);
+public slots:
+ void setCaptureFile(capture_file *cf);
protected:
bool eventFilter(QObject *obj, QEvent *event);
void keyPressEvent(QKeyEvent *event);
- void closeEvent (QCloseEvent *event);
private slots:
void on_cbCharset_currentIndexChanged(int index);
void on_cbDirections_currentIndexChanged(int index);
void on_bFind_clicked();
void on_leFind_returnPressed();
- void on_buttonBox_rejected();
- void HelpButton();
- void FilterOut();
- void FindText(bool go_back = true);
- void SaveAs();
- void Print();
+ void helpButton();
+ void filterOut();
+ void findText(bool go_back = true);
+ void saveAs();
+ void printStream();
+
+ void on_streamNumberSpinBox_valueChanged(int stream_num);
+
+ void on_buttonBox_rejected();
signals:
void updateFilter(QString &filter, bool force);
private:
- Ui::FollowStreamDialog *ui;
+ void removeStreamControls();
+ void resetStream(void);
+ frs_return_t
+ follow_show(char *buffer, size_t nchars, gboolean is_from_server,
+ guint32 *global_pos, guint32 *server_packet_count,
+ guint32 *client_packet_count);
- QPushButton *bFilterOut;
- QPushButton *bFind;
- QPushButton *bPrint;
- QPushButton *bSave;
+ frs_return_t follow_read_stream();
+ frs_return_t follow_read_tcp_stream();
+ frs_return_t follow_read_udp_stream();
+ frs_return_t follow_read_ssl_stream();
- follow_info_t *follow_info;
+ void follow_stream();
- bool save_as;
- QFile file;
-};
+ void add_text(char *buffer, size_t nchars, gboolean is_from_server);
+ Ui::FollowStreamDialog *ui;
+ capture_file *cap_file_;
+ QPushButton *b_filter_out_;
+ QPushButton *b_find_;
+ QPushButton *b_print_;
+ QPushButton *b_save_;
+
+ follow_type_t follow_type_;
+ follow_info_t follow_info_;
+ QString data_out_filename_;
+ QString filter_out_filter_;
+
+ bool save_as_;
+ QFile file_;
+};
#endif // FOLLOW_STREAM_DIALOG_H
diff --git a/ui/qt/follow_stream_dialog.ui b/ui/qt/follow_stream_dialog.ui
index 43c7042c2f..4dd0cd850b 100644
--- a/ui/qt/follow_stream_dialog.ui
+++ b/ui/qt/follow_stream_dialog.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>667</width>
- <height>639</height>
+ <width>750</width>
+ <height>620</height>
</rect>
</property>
<property name="sizePolicy">
@@ -31,7 +31,7 @@
</widget>
</item>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout">
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0,0,1,0,0">
<item>
<widget class="QComboBox" name="cbDirections"/>
</item>
@@ -87,6 +87,29 @@
</item>
</widget>
</item>
+ <item>
+ <spacer name="streamNumberSpacer">
+ <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="QLabel" name="streamNumberLabel">
+ <property name="text">
+ <string>Stream</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="streamNumberSpinBox"/>
+ </item>
</layout>
</item>
<item>
@@ -113,7 +136,7 @@
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Help</set>
+ <set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
</property>
</widget>
</item>
diff --git a/ui/qt/main_window.cpp b/ui/qt/main_window.cpp
index 27d854a5ec..0dcbbea564 100644
--- a/ui/qt/main_window.cpp
+++ b/ui/qt/main_window.cpp
@@ -119,7 +119,6 @@ MainWindow::MainWindow(QWidget *parent) :
updateRecentFiles();
connect(&summary_dialog_, SIGNAL(captureCommentChanged()), this, SLOT(updateForUnsavedChanges()));
- connect(&follow_stream_dialog_, SIGNAL(updateFilter(QString&, bool)), this, SLOT(filterPackets(QString&, bool)));
const DisplayFilterEdit *df_edit = dynamic_cast<DisplayFilterEdit *>(df_combo_box_->lineEdit());
connect(df_edit, SIGNAL(pushFilterSyntaxStatus(QString&)), main_ui_->statusBar, SLOT(pushFilterStatus(QString&)));
diff --git a/ui/qt/main_window.h b/ui/qt/main_window.h
index a5ea5269a4..ff42c0a6a9 100644
--- a/ui/qt/main_window.h
+++ b/ui/qt/main_window.h
@@ -113,7 +113,6 @@ private:
SummaryDialog summary_dialog_;
ByteViewTab *byte_view_tab_;
QWidget empty_pane_;
- FollowStreamDialog follow_stream_dialog_;
bool capture_stopping_;
bool capture_filter_valid_;
@@ -277,6 +276,8 @@ private slots:
void on_actionAnalyzePAFOrSelected_triggered();
void on_actionAnalyzePAFAndNotSelected_triggered();
void on_actionAnalyzePAFOrNotSelected_triggered();
+
+ void openFollowStreamDialog(follow_type_t type);
void on_actionAnalyzeFollowTCPStream_triggered();
void on_actionAnalyzeFollowUDPStream_triggered();
void on_actionAnalyzeFollowSSLStream_triggered();
diff --git a/ui/qt/main_window_slots.cpp b/ui/qt/main_window_slots.cpp
index dd69526b23..2dffc01e8e 100644
--- a/ui/qt/main_window_slots.cpp
+++ b/ui/qt/main_window_slots.cpp
@@ -1702,58 +1702,27 @@ void MainWindow::on_actionAnalyzePAFOrNotSelected_triggered()
matchSelectedFilter(MatchSelectedOrNot, false, false);
}
-void MainWindow::on_actionAnalyzeFollowTCPStream_triggered()
-{
- // XXX Keeping a window or dialog in memory is common in the GTK+
- // code but not in the Qt code. Should we just create a new
- // dialog and exec() it instead?
- follow_stream_dialog_.Follow(getFilter(), FOLLOW_TCP);
+void MainWindow::openFollowStreamDialog(follow_type_t type) {
+ FollowStreamDialog *fsd = new FollowStreamDialog(this, type, cap_file_);
+ connect(fsd, SIGNAL(updateFilter(QString&, bool)), this, SLOT(filterPackets(QString&, bool)));
- if (follow_stream_dialog_.isMinimized() == true)
- {
- follow_stream_dialog_.showNormal();
- }
- else
- {
- follow_stream_dialog_.show();
- }
+ fsd->follow(getFilter());
+ fsd->show();
+}
- follow_stream_dialog_.raise();
- follow_stream_dialog_.activateWindow();
+void MainWindow::on_actionAnalyzeFollowTCPStream_triggered()
+{
+ openFollowStreamDialog(FOLLOW_TCP);
}
void MainWindow::on_actionAnalyzeFollowUDPStream_triggered()
{
- follow_stream_dialog_.Follow(getFilter(), FOLLOW_UDP);
-
- if (follow_stream_dialog_.isMinimized() == true)
- {
- follow_stream_dialog_.showNormal();
- }
- else
- {
- follow_stream_dialog_.show();
- }
-
- follow_stream_dialog_.raise();
- follow_stream_dialog_.activateWindow();
+ openFollowStreamDialog(FOLLOW_UDP);
}
void MainWindow::on_actionAnalyzeFollowSSLStream_triggered()
{
- follow_stream_dialog_.Follow(getFilter(), FOLLOW_SSL);
-
- if (follow_stream_dialog_.isMinimized() == true)
- {
- follow_stream_dialog_.showNormal();
- }
- else
- {
- follow_stream_dialog_.show();
- }
-
- follow_stream_dialog_.raise();
- follow_stream_dialog_.activateWindow();
+ openFollowStreamDialog(FOLLOW_SSL);
}
// Next / previous / first / last slots in packet_list
diff --git a/ui/qt/sequence_dialog.cpp b/ui/qt/sequence_dialog.cpp
index 759b12dcf9..e861b62837 100644
--- a/ui/qt/sequence_dialog.cpp
+++ b/ui/qt/sequence_dialog.cpp
@@ -46,6 +46,7 @@
// - Incorporate packet comments?
// - Change line_style to seq_type (i.e. draw ACKs dashed)
// - Create WSGraph subclasses with common behavior.
+// - Help button and text
SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType type) :
QDialog(parent),
@@ -93,13 +94,18 @@ SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType t
memset (&seq_analysis_, 0, sizeof(seq_analysis_));
+ ui->showComboBox->blockSignals(true);
ui->showComboBox->setCurrentIndex(0);
+ ui->showComboBox->blockSignals(false);
+ ui->addressComboBox->blockSignals(true);
ui->addressComboBox->setCurrentIndex(0);
+ ui->addressComboBox->blockSignals(false);
QComboBox *fcb = ui->flowComboBox;
fcb->addItem(ui->actionFlowAny->text(), SEQ_ANALYSIS_ANY);
fcb->addItem(ui->actionFlowTcp->text(), SEQ_ANALYSIS_TCP);
+ ui->flowComboBox->blockSignals(true);
switch (type) {
case any:
seq_analysis_.type = SEQ_ANALYSIS_ANY;
@@ -115,6 +121,7 @@ SequenceDialog::SequenceDialog(QWidget *parent, capture_file *cf, SequenceType t
ui->flowLabel->hide();
break;
}
+ ui->flowComboBox->blockSignals(false);
seq_analysis_.all_packets = TRUE;
QPushButton *save_bt = ui->buttonBox->button(QDialogButtonBox::Save);
@@ -425,14 +432,14 @@ void SequenceDialog::on_showComboBox_currentIndexChanged(int index)
} else {
seq_analysis_.all_packets = FALSE;
}
- if (isVisible()) fillDiagram();
+ 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 (isVisible()) fillDiagram();
+ fillDiagram();
}
void SequenceDialog::on_addressComboBox_currentIndexChanged(int index)
@@ -442,7 +449,7 @@ void SequenceDialog::on_addressComboBox_currentIndexChanged(int index)
} else {
seq_analysis_.any_addr = FALSE;
}
- if (isVisible()) fillDiagram();
+ fillDiagram();
}
void SequenceDialog::on_actionReset_triggered()
diff --git a/wsutil/tempfile.h b/wsutil/tempfile.h
index 65746704dd..4f9492ed87 100644
--- a/wsutil/tempfile.h
+++ b/wsutil/tempfile.h
@@ -40,9 +40,9 @@ extern "C" {
* Create a tempfile with the given prefix (e.g. "wireshark"). The path
* is created using g_get_tmp_dir and mkstemp.
*
- * @param namebuf If not NULL, receives the full path of the temp file.
+ * @param namebuf[in,out] If not NULL, receives the full path of the temp file.
* Must NOT be freed.
- * @param pfx A prefix for the temporary file.
+ * @param pfx[in] A prefix for the temporary file.
* @return The file descriptor of the new tempfile, from mkstemp().
*/
WS_DLL_PUBLIC int create_tempfile(char **namebuf, const char *pfx);