summaryrefslogtreecommitdiff
path: root/src/monitor-gui.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/monitor-gui.cc')
-rw-r--r--src/monitor-gui.cc146
1 files changed, 129 insertions, 17 deletions
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_;