diff options
Diffstat (limited to 'src/monitor-gui.cc')
| -rw-r--r-- | src/monitor-gui.cc | 146 |
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_; |
