summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@yahoo.com>2017-08-06 22:27:09 +0200
committerJoel Klinghed <the_jk@yahoo.com>2017-08-06 22:28:12 +0200
commitea8148077fa28964e3b582cd6e0bb9cfea850b66 (patch)
tree1c8679be716830d6f1835aaa50d7f18b55528c1e
parent178bb3a1ceab88f29aa7d0ceb453e76de172fd27 (diff)
Add support for protocols in monitor-gui
-rw-r--r--src/Makefile.am14
-rw-r--r--src/gui_gtk.cc177
-rw-r--r--src/gui_main.hh1
-rw-r--r--src/gui_progress.hh38
-rw-r--r--src/gui_qt.cc160
-rw-r--r--src/monitor-gui.cc146
6 files changed, 495 insertions, 41 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3ace3ea..1579db3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -74,7 +74,7 @@ libmonitor_gui_a_SOURCES = monitor-gui.cc gui_config.cc gui_config.hh \
gui_about.hh gui_file.hh gui_main.hh \
gui_window.hh gui_formapply.hh gui_menu.hh \
gui_statusbar.hh gui_form.hh gui_listmodel.hh \
- gui_message.hh gui_textwnd.hh
+ gui_message.hh gui_textwnd.hh gui_progress.hh
libmonitor_gui_a_CXXFLAGS = $(AM_CXXFLAGS) -DVERSION='"@VERSION@"' \
@THREAD_CFLAGS@ @PCAP_CFLAGS@
@@ -90,9 +90,9 @@ protocol_LDADD = libprotocol.a libhexdump.a libattrstr.a libtp.a @THREAD_LIBS@ \
@ZLIB_LIBS@ @BZIP2_LIBS@
tp_monitor_gtk_SOURCES = gui_gtk.cc
-tp_monitor_gtk_LDADD = libmonitor_gui.a libattrstr.a libproxy.a libmonitor.a \
- libhexdump.a libtp.a @GTK_LIBS@ @THREAD_LIBS@ \
- @PCAP_LIBS@
+tp_monitor_gtk_LDADD = libmonitor_gui.a libprotocol.a libattrstr.a libproxy.a \
+ libmonitor.a libhexdump.a libtp.a @GTK_LIBS@ \
+ @THREAD_LIBS@ @PCAP_LIBS@ @ZLIB_LIBS@ @BZIP2_LIBS@
if HAVE_SSL
tp_monitor_gtk_LDADD += libmitm.a @SSL_LIBS@
endif
@@ -100,9 +100,9 @@ tp_monitor_gtk_CXXFLAGS = $(AM_CXXFLAGS) -DVERSION='"@VERSION@"' \
@GTK_CFLAGS@ @THREAD_CFLAGS@ -Wno-unused-function
tp_monitor_qt_SOURCES = gui_qt.cc
-tp_monitor_qt_LDADD = libmonitor_gui.a libattrstr.a libmonitor.a libproxy.a \
- libhexdump.a libtp.a @QT_LIBS@ @THREAD_LIBS@ \
- @PCAP_LIBS@
+tp_monitor_qt_LDADD = libmonitor_gui.a libprotocol.a libattrstr.a libmonitor.a \
+ libhexdump.a libproxy.a libtp.a @QT_LIBS@ @THREAD_LIBS@ \
+ @PCAP_LIBS@ @ZLIB_LIBS@ @BZIP2_LIBS@
if HAVE_SSL
tp_monitor_qt_LDADD += libmitm.a @SSL_LIBS@
endif
diff --git a/src/gui_gtk.cc b/src/gui_gtk.cc
index 20a6147..c02bdf6 100644
--- a/src/gui_gtk.cc
+++ b/src/gui_gtk.cc
@@ -17,6 +17,7 @@
#include "gui_main.hh"
#include "gui_menu.hh"
#include "gui_message.hh"
+#include "gui_progress.hh"
#include "gui_statusbar.hh"
#include "gui_textwnd.hh"
#include "looper.hh"
@@ -635,6 +636,16 @@ public:
return package_.get();
}
+ void set_content(std::string const& name, AttributedText* text) override;
+
+ AttributedText* content() const {
+ return content_;
+ }
+
+ std::string const& content_name() const {
+ return content_name_;
+ }
+
ListModel* gtklistmodel() const {
return listmodel_.get();
}
@@ -789,6 +800,8 @@ private:
shared_gobject<MainApp> app_;
shared_gobject<ListModel> listmodel_;
std::unique_ptr<AttributedText> package_;
+ AttributedText* content_;
+ std::string content_name_;
std::unique_ptr<GtkConfig> config_;
Observers<GuiMain::Listener*> observers_;
GuiMenu* menu_;
@@ -1777,6 +1790,109 @@ protected:
gulong changed_handler_;
};
+class GtkGuiProgress : public virtual GuiProgress, public GtkGuiWindow {
+public:
+ GtkGuiProgress(std::string const& title, std::string const& text,
+ float min, float max)
+ : title_(title), text_(text), min_(min), max_(max), value_(min),
+ dialog_(nullptr), progress_(nullptr) {
+ }
+
+ ~GtkGuiProgress() override {
+ if (dialog_) gtk_widget_destroy(dialog_);
+ }
+
+ void set_title(std::string const& title) override {
+ title_ = title;
+ GtkGuiWindow::set_title(title);
+ }
+ std::string const& title() const override {
+ return title_;
+ }
+
+ void* impl() const override {
+ return dialog_;
+ }
+
+ void add_listener(GuiProgress::Listener* listener) override {
+ observers_.insert(listener);
+ }
+
+ void remove_listener(GuiProgress::Listener* listener) override {
+ observers_.erase(listener);
+ }
+
+ void set_progress(float value) override {
+ value_ = value;
+ if (progress_) {
+ sync_value();
+ }
+ }
+
+ void show(GuiWindow* parent) override {
+ if (dialog_) {
+ gtk_window_present(GTK_WINDOW(dialog_));
+ assert(false);
+ return;
+ }
+
+ dialog_ = gtk_dialog_new();
+ g_signal_connect(G_OBJECT(dialog_), "delete-event",
+ G_CALLBACK(delete_event), this);
+ gtk_window_set_title(GTK_WINDOW(dialog_), title_.c_str());
+ gtk_window_set_modal(GTK_WINDOW(dialog_), true);
+ auto wnd = reinterpret_cast<GtkWindow*>(parent->impl());
+ gtk_window_set_transient_for(GTK_WINDOW(dialog_), wnd);
+ auto label = gtk_label_new(text_.c_str());
+ progress_ = gtk_progress_bar_new();
+ sync_value();
+ auto content = gtk_dialog_get_content_area(GTK_DIALOG(dialog_));
+ gtk_box_pack_start(GTK_BOX(content), label, true, true, 5);
+ gtk_box_pack_end(GTK_BOX(content), progress_, true, true, 5);
+ gtk_widget_show_all(dialog_);
+ }
+
+private:
+ void sync_value() {
+ assert(progress_);
+ gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_),
+ (value_ - min_) / (max_ - min_));
+ }
+
+ bool notify_about_to_close() {
+ auto it = observers_.notify();
+ while (it.has_next()) {
+ if (!it.next()->about_to_close(this)) return false;
+ }
+ return true;
+ }
+
+ static gboolean delete_event(GtkWidget* widget, GdkEvent*,
+ gpointer user_data) {
+ auto me = reinterpret_cast<GtkGuiProgress*>(user_data);
+ assert(me->dialog_ == widget);
+ me->dialog_ = nullptr;
+ auto progress = me->progress_;
+ me->progress_ = nullptr;
+ if (me->notify_about_to_close()) {
+ gtk_widget_destroy(widget);
+ return false;
+ }
+ me->dialog_ = widget;
+ me->progress_ = progress;
+ return true;
+ }
+
+ std::string title_;
+ std::string text_;
+ float min_;
+ float max_;
+ float value_;
+ Observers<GuiProgress::Listener*> observers_;
+ GtkWidget* dialog_;
+ GtkWidget* progress_;
+};
+
struct _MainApp
{
GtkApplication parent_;
@@ -1789,6 +1905,8 @@ struct _MainAppWindow
GtkWidget* paned_;
GtkWidget* top_;
GtkWidget* bottom_;
+ GtkWidget* bottom_content_;
+ GtkWidget* bottom_package_;
};
G_DEFINE_TYPE(MainApp, main_app, GTK_TYPE_APPLICATION);
@@ -1836,17 +1954,32 @@ MainAppWindow* main_app_window_new(MainApp *app) {
gtk_container_add(GTK_CONTAINER(top_scroll), ret->top_);
gtk_paned_add1(GTK_PANED(ret->paned_), top_scroll);
}
- ret->bottom_ = gtk_text_view_new();
- gtk_text_view_set_editable(GTK_TEXT_VIEW(ret->bottom_), false);
- gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ret->bottom_), false);
- gtk_text_view_set_monospace(GTK_TEXT_VIEW(ret->bottom_), true);
+ ret->bottom_package_ = gtk_text_view_new();
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(ret->bottom_package_), false);
+ gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ret->bottom_package_), false);
+ gtk_text_view_set_monospace(GTK_TEXT_VIEW(ret->bottom_package_), true);
if (app->main_->package()) {
- gtk_text_view_set_buffer(GTK_TEXT_VIEW(ret->bottom_),
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(ret->bottom_package_),
static_cast<GtkAttributedText*>(app->main_->package())->buffer());
}
- auto bottom_scroll = gtk_scrolled_window_new(nullptr, nullptr);
- gtk_container_add(GTK_CONTAINER(bottom_scroll), ret->bottom_);
- gtk_paned_add2(GTK_PANED(ret->paned_), bottom_scroll);
+ ret->bottom_content_ = gtk_text_view_new();
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(ret->bottom_content_), false);
+ gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ret->bottom_content_), false);
+ gtk_text_view_set_monospace(GTK_TEXT_VIEW(ret->bottom_content_), true);
+ if (app->main_->content()) {
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(ret->bottom_content_),
+ static_cast<GtkAttributedText*>(app->main_->content())->buffer());
+ }
+ ret->bottom_ = gtk_notebook_new();
+ auto scroll = gtk_scrolled_window_new(nullptr, nullptr);
+ gtk_container_add(GTK_CONTAINER(scroll), ret->bottom_package_);
+ auto label = gtk_label_new("Package");
+ gtk_notebook_append_page(GTK_NOTEBOOK(ret->bottom_), scroll, label);
+ scroll = gtk_scrolled_window_new(nullptr, nullptr);
+ gtk_container_add(GTK_CONTAINER(scroll), ret->bottom_content_);
+ label = gtk_label_new(app->main_->content_name().c_str());
+ gtk_notebook_append_page(GTK_NOTEBOOK(ret->bottom_), scroll, label);
+ gtk_paned_add2(GTK_PANED(ret->paned_), ret->bottom_);
gtk_box_pack_start(GTK_BOX(box), ret->paned_, true, true, 0);
auto statusbar = static_cast<GtkGuiStatusBar*>(app->main_->statusbar());
if (statusbar) {
@@ -1989,11 +2122,30 @@ void GtkGuiMain::set_package(std::unique_ptr<AttributedText>&& text) {
} else {
buf = gtk_text_buffer_new(NULL);
}
- gtk_text_view_set_buffer(GTK_TEXT_VIEW(wnd->bottom_), buf);
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(wnd->bottom_package_), buf);
if (!package_) g_object_unref(buf);
}
}
+void GtkGuiMain::set_content(std::string const& name, AttributedText* text) {
+ content_name_ = name;
+ content_ = text;
+ auto wnd = reinterpret_cast<MainAppWindow*>(window());
+ if (wnd) {
+ GtkTextBuffer* buf;
+ if (content_) {
+ buf = static_cast<GtkAttributedText*>(content_)->buffer();
+ } else {
+ buf = gtk_text_buffer_new(NULL);
+ }
+ gtk_notebook_set_tab_label_text(GTK_NOTEBOOK(wnd->bottom_),
+ gtk_widget_get_parent(wnd->bottom_content_),
+ content_name_.c_str());
+ gtk_text_view_set_buffer(GTK_TEXT_VIEW(wnd->bottom_content_), buf);
+ if (!content_) g_object_unref(buf);
+ }
+}
+
void GtkGuiMain::set_split(double split) {
split_ = std::max(0.0, std::min(split, 1.0));
auto wnd = reinterpret_cast<MainAppWindow*>(window());
@@ -2449,3 +2601,10 @@ GuiTextWindow* GuiTextWindow::create(std::string const& title,
AttributedText const* text) {
return new GtkGuiTextWindow(title, width, height, text);
}
+
+// static
+GuiProgress* GuiProgress::create(std::string const& title,
+ std::string const& text,
+ float min, float max) {
+ return new GtkGuiProgress(title, text, min, max);
+}
diff --git a/src/gui_main.hh b/src/gui_main.hh
index 1070c0d..ab8499d 100644
--- a/src/gui_main.hh
+++ b/src/gui_main.hh
@@ -51,6 +51,7 @@ public:
virtual void select_row(size_t row) = 0;
virtual void set_package(std::unique_ptr<AttributedText>&& data) = 0;
+ virtual void set_content(std::string const& name, AttributedText* data) = 0;
virtual bool run(int argc, char** argv) = 0;
diff --git a/src/gui_progress.hh b/src/gui_progress.hh
new file mode 100644
index 0000000..2c92693
--- /dev/null
+++ b/src/gui_progress.hh
@@ -0,0 +1,38 @@
+// -*- mode: c++; c-basic-offset: 2; -*-
+
+#ifndef GUI_PROGRESS_HH
+#define GUI_PROGRESS_HH
+
+#include <string>
+#include <vector>
+
+#include "gui_window.hh"
+
+class GuiProgress : public GuiWindow {
+public:
+ class Listener : public GuiWindow::Listener {
+ public:
+ virtual ~Listener() {}
+
+ virtual bool about_to_close(GuiProgress* progress) = 0;
+
+ protected:
+ Listener() {}
+ };
+
+ static GuiProgress* create(std::string const& title,
+ std::string const& text,
+ float min, float max);
+
+ virtual void add_listener(Listener* listener) = 0;
+ virtual void remove_listener(Listener* listener) = 0;
+
+ virtual void show(GuiWindow* parent) = 0;
+
+ virtual void set_progress(float progress) = 0;
+
+protected:
+ GuiProgress() {}
+};
+
+#endif // GUI_PROGRESS_HH
diff --git a/src/gui_qt.cc b/src/gui_qt.cc
index fe9d1c4..1d81bd6 100644
--- a/src/gui_qt.cc
+++ b/src/gui_qt.cc
@@ -48,6 +48,7 @@
#include "gui_main.hh"
#include "gui_menu.hh"
#include "gui_message.hh"
+#include "gui_progress.hh"
#include "gui_statusbar.hh"
#include "gui_textwnd.hh"
#include "looper.hh"
@@ -522,8 +523,27 @@ public:
} else {
package_.clear();
}
- if (bottom_) {
- bottom_->setHtml(QString::fromStdString(package_));
+ if (bottom_package_) {
+ bottom_package_->setHtml(QString::fromStdString(package_));
+ }
+ }
+
+ void set_content(std::string const& name, AttributedText* text) override {
+ if (text) {
+ content_ = "<span style=\"font-family: monospace;\">"
+ + static_cast<HtmlAttributedText*>(text)->html() + "</span>";
+ content_name_ = name;
+ } else {
+ content_.clear();
+ content_name_.clear();
+ }
+ if (bottom_content_) {
+ bottom_content_->setHtml(QString::fromStdString(content_));
+ bottom_->setTabText(1, QString::fromStdString(content_name_));
+ bottom_->setTabEnabled(1, !content_.empty());
+ if (text && content_last_active_) {
+ bottom_->setCurrentIndex(1);
+ }
}
}
@@ -658,6 +678,8 @@ private:
QtGuiStatusBar* statusbar_;
std::unique_ptr<QGuiListModel> listmodel_;
std::string package_;
+ std::string content_;
+ std::string content_name_;
Observers<GuiMain::Listener*> observers_;
std::unique_ptr<QMainWindow> main_;
std::unique_ptr<SizeHintLayout> layout_;
@@ -665,9 +687,12 @@ private:
std::unique_ptr<QtGuiConfig> config_;
QSplitter* splitter_;
QWidget* top_;
- QTextEdit* bottom_;
+ QTextEdit* bottom_package_;
+ QTextEdit* bottom_content_;
+ QTabWidget* bottom_;
bool started_;
std::vector<RunWhenStartedCallback> run_when_started_;
+ bool content_last_active_;
};
class QtChildGuiMenu : public QtCommonMenu {
@@ -1408,8 +1433,7 @@ private:
}
assert(!progress_);
progress_ = new QProgressBar();
- progress_->setMinimum(0);
- progress_->setMaximum(0);
+ progress_->setRange(0, 0);
layout->addWidget(progress_, row++, 0, 1, columns);
progress_->hide();
return row;
@@ -1677,6 +1701,106 @@ private:
QTextEdit* view_;
};
+
+class QtGuiProgress : public virtual GuiProgress, public QtGuiWindow,
+ public virtual OptionalCloseDialog::Delegate {
+private:
+ static const int UNIT = 100000;
+public:
+ QtGuiProgress(std::string const& title, std::string const& text,
+ float min, float max)
+ : title_(title), text_(text), min_(min), max_(max), value_(min),
+ progress_(nullptr) {
+ }
+
+ ~QtGuiProgress() override {
+ }
+
+ void add_listener(GuiProgress::Listener* listener) override {
+ observers_.insert(listener);
+ }
+
+ void remove_listener(GuiProgress::Listener* listener) override {
+ observers_.erase(listener);
+ }
+
+ void set_title(std::string const& title) override {
+ title_ = title;
+ QtGuiWindow::set_title(title);
+ }
+ std::string const& title() const override {
+ return title_;
+ }
+
+ void set_progress(float value) override {
+ value_ = value;
+ if (progress_) progress_->setValue(value_ * UNIT);
+ }
+
+ QWidget* widget() const override {
+ return dialog_.get();
+ }
+
+ void* impl() const override {
+ return QtGuiWindow::impl();
+ }
+
+ bool showWidget() override {
+ show(QApplication::activeWindow());
+ return true;
+ }
+
+ void show(GuiWindow* parent) override {
+ auto wnd = static_cast<QtGuiWindow*>(parent->impl());
+ show(wnd->widget());
+ }
+
+ bool about_to_close() override {
+ return notify_about_to_close();
+ }
+
+private:
+ void show(QWidget* parent) {
+ if (dialog_) {
+ assert(false);
+ dialog_->raise();
+ dialog_->activateWindow();
+ return;
+ }
+
+ progress_ = new QProgressBar();
+ progress_->setRange(min_ * UNIT, max_ * UNIT);
+ progress_->setValue(value_ * UNIT);
+
+ dialog_.reset(new OptionalCloseDialog(parent, this));
+ dialog_->setWindowTitle(QString::fromStdString(title_));
+ auto layout = new QVBoxLayout();
+ auto text = new QLabel(QString::fromStdString(text_));
+ layout->addWidget(text);
+ layout->addWidget(progress_);
+ dialog_->setLayout(layout);
+ dialog_->setModal(true);
+ dialog_->show();
+ }
+
+ bool notify_about_to_close() {
+ auto it = observers_.notify();
+ while (it.has_next()) {
+ if (!it.next()->about_to_close(this)) return false;
+ }
+ return true;
+ }
+
+ std::string title_;
+ std::string text_;
+ float min_;
+ float max_;
+ float value_;
+ Observers<GuiProgress::Listener*> observers_;
+ std::unique_ptr<QDialog> dialog_;
+ QProgressBar* progress_;
+};
+
bool QtGuiMain::run(int argc, char** argv) {
QApplication app(argc, argv);
app.setApplicationName(QString::fromStdString(title_));
@@ -1722,9 +1846,22 @@ bool QtGuiMain::run(int argc, char** argv) {
top_ = new QWidget();
}
splitter_->addWidget(top_);
- bottom_ = new QTextEdit();
- bottom_->setReadOnly(true);
- bottom_->setHtml(QString::fromStdString(package_));
+ bottom_package_ = new QTextEdit();
+ bottom_package_->setReadOnly(true);
+ bottom_package_->setHtml(QString::fromStdString(package_));
+ bottom_content_ = new QTextEdit();
+ bottom_content_->setReadOnly(true);
+ bottom_content_->setHtml(QString::fromStdString(content_));
+ bottom_ = new QTabWidget();
+ bottom_->addTab(bottom_package_, "Package");
+ bottom_->addTab(bottom_content_, QString::fromStdString(content_name_));
+ bottom_->setTabEnabled(1, !content_.empty());
+ content_last_active_ = false;
+ QObject::connect(bottom_, &QTabWidget::tabBarClicked,
+ [=](int index) {
+ if (index < 0) return;
+ content_last_active_ = index == 1;
+ });
splitter_->addWidget(bottom_);
main_->setCentralWidget(center_.get());
if (menu_) {
@@ -1978,3 +2115,10 @@ GuiTextWindow* GuiTextWindow::create(std::string const& title,
AttributedText const* text) {
return new QtGuiTextWindow(title, width, height, text);
}
+
+// static
+GuiProgress* GuiProgress::create(std::string const& title,
+ std::string const& text,
+ float min, float max) {
+ return new QtGuiProgress(title, text, min, max);
+}
diff --git a/src/monitor-gui.cc b/src/monitor-gui.cc
index 66c5e43..3301ada 100644
--- a/src/monitor-gui.cc
+++ b/src/monitor-gui.cc
@@ -5,6 +5,7 @@
#include <fcntl.h>
#include <fstream>
#include <memory>
+#include <sstream>
#include <stdarg.h>
#include <string.h>
#include <sys/socket.h>
@@ -30,6 +31,7 @@
#include "gui_menu.hh"
#include "gui_message.hh"
#include "gui_main.hh"
+#include "gui_progress.hh"
#include "gui_statusbar.hh"
#include "gui_textwnd.hh"
#include "io.hh"
@@ -37,12 +39,15 @@
#include "looper.hh"
#include "monitor.hh"
#include "observers.hh"
+#include "protocols.hh"
#include "proxy.hh"
#include "resolver.hh"
#include "ssl.hh"
namespace {
+size_t const MAX_DATA_SIZE = 65536;
+
std::string const APP_TITLE = "TransparentProxy";
std::string const ACTION_SETUP = "setup";
@@ -50,6 +55,7 @@ std::string const ACTION_CONNECT = "connect";
std::string const ACTION_DISCONNECT = "disconnect";
std::string const ACTION_EXIT = "exit";
std::string const ACTION_ABOUT = "about";
+std::string const ACTION_COPY_CONTENT = "copy_content";
std::string const ACTION_COPY_RAW = "copy_raw";
std::string const ACTION_COPY_TEXT = "copy_text";
std::string const ACTION_CLEAR = "clear";
@@ -62,6 +68,7 @@ std::string const ACTION_OPEN = "open";
std::string const ACTION_SAVE = "save";
std::string const ACTION_SAVE_AS = "save_as";
std::string const ACTION_JUMP = "jump";
+std::string const ACTION_EXPORT_CONTENT = "export_content";
std::string const ACTION_EXPORT_RAW = "export_raw";
std::string const ACTION_EXPORT_TEXT = "export_text";
@@ -389,7 +396,7 @@ private:
};
class MonitorGui : GuiMenu::Listener, GuiMain::Listener, Monitor::Delegate,
- GuiTextWindow::Listener {
+ GuiTextWindow::Listener, Protocols::Listener {
private:
class ConnectFormListener : public GuiFormApply::Listener {
public:
@@ -667,6 +674,13 @@ private:
};
#endif // HAVE_SSL
+ class DoNotCloseListener : public GuiProgress::Listener {
+ public:
+ bool about_to_close(GuiProgress*) override {
+ return false;
+ }
+ };
+
public:
MonitorGui()
: packages_(new PackageList()),
@@ -674,6 +688,7 @@ public:
menu_(GuiMenu::create()),
statusbar_(GuiStatusBar::create()),
looper_(main_->create_looper()),
+ protocols_(Protocols::create(4, MAX_DATA_SIZE, 10, looper_.get(), this)),
has_selection_(false),
has_related_(false),
selection_(0),
@@ -743,11 +758,15 @@ public:
GuiMenu::Shortcut(GuiMenu::CTRL, 'C'));
edit->add_item(ACTION_COPY_RAW, "Copy binary",
GuiMenu::Shortcut(GuiMenu::CTRL | GuiMenu::SHIFT, 'C'));
+ edit->add_item(ACTION_COPY_CONTENT, "Copy content",
+ GuiMenu::Shortcut(GuiMenu::CTRL | GuiMenu::ALT, 'C'));
edit->add_separator();
edit->add_item(ACTION_EXPORT_TEXT, "Export...",
GuiMenu::Shortcut(GuiMenu::CTRL, 'E'));
edit->add_item(ACTION_EXPORT_RAW, "Export binary...",
GuiMenu::Shortcut(GuiMenu::CTRL | GuiMenu::SHIFT, 'E'));
+ edit->add_item(ACTION_EXPORT_CONTENT, "Export content...",
+ GuiMenu::Shortcut(GuiMenu::CTRL | GuiMenu::ALT, 'E'));
edit->add_separator();
edit->add_item(ACTION_JUMP, "Jump to related",
GuiMenu::Shortcut(GuiMenu::CTRL, ' '));
@@ -770,11 +789,7 @@ public:
statusbar_->set_status("Not connected");
menu_->enable_item(ACTION_DISCONNECT, false);
- menu_->enable_item(ACTION_COPY_RAW, false);
- menu_->enable_item(ACTION_COPY_TEXT, false);
- menu_->enable_item(ACTION_EXPORT_RAW, false);
- menu_->enable_item(ACTION_EXPORT_TEXT, false);
- menu_->enable_item(ACTION_JUMP, false);
+ lost_selection(main_.get());
menu_->add_listener(this);
main_->add_listener(this);
@@ -894,6 +909,13 @@ public:
}
auto& pkg = packages_->package(selection_);
main_->add_to_clipboard(pkg.data, "application/octet-stream");
+ } else if (id == ACTION_COPY_CONTENT) {
+ if (!has_selection_ || !selection_content_) {
+ assert(false);
+ return;
+ }
+ setup_export_content_msg();
+ protocols_->content(selection_, &export_content_sstream_);
} else if (id == ACTION_EXPORT_TEXT) {
if (!has_selection_) {
assert(false);
@@ -907,6 +929,17 @@ public:
}
auto& pkg = packages_->package(selection_);
export_text(pkg.data, raw_filter_);
+ } else if (id == ACTION_EXPORT_CONTENT) {
+ if (!has_selection_ || !selection_content_) {
+ assert(false);
+ return;
+ }
+ auto file = main_->file_dialog("Export", "", GuiFile::FILE_SAVE,
+ raw_filter_);
+ if (file.empty()) return;
+ export_content_fstream_.open(file);
+ setup_export_content_msg();
+ protocols_->content(selection_, &export_content_fstream_);
} else if (id == ACTION_JUMP) {
if (!has_selection_) {
assert(false);
@@ -919,7 +952,7 @@ public:
}
main_->select_row(pkg.related);
} else if (id == ACTION_CLEAR) {
- packages_->clear();
+ clear();
set_modified(true);
} else if (id == ACTION_PROXY_LOG) {
if (!proxy_logwnd_) {
@@ -976,32 +1009,46 @@ public:
void selected_row(GuiMain* main, size_t index) override {
assert(main_.get() == main);
- if (has_selection_ && selection_ == index) return;
+ if (selection_content_) {
+ main_->set_content("", nullptr);
+ protocols_->free(selection_, std::move(selection_content_));
+ }
has_selection_ = true;
selection_ = index;
auto& pkg = packages_->package(index);
std::unique_ptr<AttributedText> text(AttributedText::create());
- HexDump::write(text.get(), HexDump::ADDRESS | HexDump::CHARS, pkg.data);
+ HexDump::write(text.get(), HexDump::ADDRESS | HexDump::CHARS,
+ pkg.data, 0, MAX_DATA_SIZE);
main_->set_package(std::move(text));
has_related_ = pkg.related != PackageList::NONE;
+ menu_->enable_item(ACTION_COPY_CONTENT, false);
menu_->enable_item(ACTION_COPY_RAW, true);
menu_->enable_item(ACTION_COPY_TEXT, true);
+ menu_->enable_item(ACTION_EXPORT_CONTENT, false);
menu_->enable_item(ACTION_EXPORT_RAW, true);
menu_->enable_item(ACTION_EXPORT_TEXT, true);
menu_->enable_item(ACTION_JUMP, has_related_);
+
+ protocols_->text(selection_);
}
void lost_selection(GuiMain* main) override {
assert(main_.get() == main);
+ if (selection_content_) {
+ main_->set_content("", nullptr);
+ protocols_->free(selection_, std::move(selection_content_));
+ }
has_selection_ = false;
has_related_ = false;
main_->set_package(nullptr);
+ menu_->enable_item(ACTION_COPY_CONTENT, false);
menu_->enable_item(ACTION_COPY_RAW, false);
menu_->enable_item(ACTION_COPY_TEXT, false);
+ menu_->enable_item(ACTION_EXPORT_CONTENT, false);
menu_->enable_item(ACTION_EXPORT_RAW, false);
menu_->enable_item(ACTION_EXPORT_TEXT, false);
menu_->enable_item(ACTION_JUMP, false);
@@ -1010,11 +1057,7 @@ public:
void open(GuiMain*, std::string const& file) override {
if (abort_if_modified()) return;
file_ = file;
- if (!load(file_, packages_.get())) {
- file_.clear();
- }
- modified_ = false;
- update_title();
+ finish_load();
}
// GuiTextWindow::Listener
@@ -1080,6 +1123,7 @@ public:
void package(Monitor* monitor, ::Package const& package) override {
assert(monitor == monitor_.get());
packages_->package(package);
+ protocols_->add(packages_->rows(), nullptr, 0);
set_modified(true);
if (has_selection_ && !has_related_) {
auto const& pkg = packages_->package(selection_);
@@ -1091,12 +1135,54 @@ public:
char const* data, size_t size, bool last) override {
assert(monitor == monitor_.get());
auto index = packages_->package_data(id, data, size, last);
+ auto const& pkg = packages_->package(index);
+ protocols_->update(index, pkg.data.data(), pkg.data.size());
if (has_selection_ && index == selection_) {
- selected_row(nullptr, index);
+ selected_row(main_.get(), index);
}
set_modified(true);
}
+ // Protocols::Listener
+ void text(Protocols* protocols, size_t id, std::string const& protocol,
+ std::unique_ptr<AttributedText>&& text) override {
+ assert(protocols == protocols_.get());
+ if (id >= packages_->rows()) {
+ assert(false);
+ protocols_->free(id, std::move(text));
+ protocols_->remove(id);
+ return;
+ }
+ if (!has_selection_ || selection_ != id) {
+ protocols_->free(id, std::move(text));
+ return;
+ }
+ selection_content_.swap(text);
+ main_->set_content(protocol, selection_content_.get());
+ menu_->enable_item(ACTION_COPY_CONTENT, true);
+ menu_->enable_item(ACTION_EXPORT_CONTENT, true);
+ }
+
+ void content(Protocols* protocols, size_t id, std::string const&,
+ std::ostream* out) override {
+ assert(protocols == protocols_.get());
+ if (id >= packages_->rows()) {
+ assert(false);
+ protocols_->remove(id);
+ return;
+ }
+ if (out == &export_content_sstream_) {
+ main_->add_to_clipboard(export_content_sstream_.str(),
+ "application/octet-stream");
+ export_content_sstream_.clear();
+ } else if (out == &export_content_fstream_) {
+ export_content_fstream_.close();
+ } else {
+ assert(false);
+ }
+ export_content_dialog_.reset();
+ }
+
private:
void setup_monitor() {
if (!resolver_) {
@@ -1146,11 +1232,16 @@ private:
}
}
+ void clear() {
+ protocols_->clear();
+ packages_->clear();
+ }
+
void new_file() {
if (abort_if_modified()) return;
file_.clear();
modified_ = false;
- packages_->clear();
+ clear();
update_title();
}
@@ -1159,11 +1250,19 @@ private:
file_ = main_->file_dialog("Open File", "", GuiFile::FILE_OPEN,
file_filter_);
if (file_.empty()) return;
- packages_->clear();
+ clear();
+
+ finish_load();
+ }
+ void finish_load() {
if (!load(file_, packages_.get())) {
file_.clear();
}
+ for (size_t i = 0; i < packages_->rows(); ++i) {
+ auto const& pkg = packages_->package(i);
+ protocols_->add(i, pkg.data.data(), pkg.data.size());
+ }
modified_ = false;
update_title();
}
@@ -1567,6 +1666,14 @@ private:
return true;
}
+ void setup_export_content_msg() {
+ export_content_dialog_.reset(GuiProgress::create("Exporting...",
+ "Please wait...",
+ .0f, .0f));
+ export_content_dialog_->add_listener(new DoNotCloseListener());
+ export_content_dialog_->show(main_.get());
+ }
+
std::unique_ptr<PackageList> packages_;
std::unique_ptr<GuiMain> main_;
std::unique_ptr<GuiMenu> menu_;
@@ -1580,11 +1687,16 @@ private:
std::unique_ptr<StringLogger> proxy_logger_;
std::unique_ptr<Proxy> proxy_;
std::unique_ptr<GuiTextWindow> proxy_logwnd_;
+ std::unique_ptr<Protocols> protocols_;
std::vector<GuiFile::Filter> pem_filter_;
std::vector<GuiFile::Filter> crt_filter_;
bool has_selection_;
bool has_related_;
size_t selection_;
+ std::unique_ptr<AttributedText> selection_content_;
+ std::unique_ptr<GuiProgress> export_content_dialog_;
+ std::stringstream export_content_sstream_;
+ std::ofstream export_content_fstream_;
std::vector<GuiFile::Filter> file_filter_;
std::string file_;
bool modified_;