diff --git a/src/common/utils.cpp b/src/common/utils.cpp index 59cf6323..4ace2fc1 100644 --- a/src/common/utils.cpp +++ b/src/common/utils.cpp @@ -93,6 +93,37 @@ bool pid_running(pid_t pid) { } } +std::string xml_escape(std::string string) { + // Implementation idea stolen from https://stackoverflow.com/a/5665377 + std::string escaped; + escaped.reserve( + static_cast(static_cast(string.size()) * 1.1)); + for (const char& character : string) { + switch (character) { + case '&': + escaped.append("&"); + break; + case '\"': + escaped.append("""); + break; + case '\'': + escaped.append("'"); + break; + case '<': + escaped.append("<"); + break; + case '>': + escaped.append(">"); + break; + default: + escaped.push_back(character); + break; + } + } + + return escaped; +} + ScopedFlushToZero::ScopedFlushToZero() noexcept { old_ftz_mode = _MM_GET_FLUSH_ZERO_MODE(); _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); diff --git a/src/common/utils.h b/src/common/utils.h index e28d18e5..3fda783c 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -133,6 +133,11 @@ bool is_watchdog_timer_disabled(); */ bool pid_running(pid_t pid); +/** + * Escape XML entities within a string. Used inside of desktop notifications. + */ +std::string xml_escape(std::string string); + /** * A RAII wrapper that will temporarily enable the FTZ flag so that denormals * are automatically flushed to zero, returning to whatever the flag was diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp index ad58348d..a70c4d21 100644 --- a/src/plugin/utils.cpp +++ b/src/plugin/utils.cpp @@ -407,37 +407,14 @@ bool send_notification(const std::string& title, const std::string body) { // I think there's a zero chance that we're going to call this function with // anything that even somewhat resembles HTML, but we should still do a // basic XML escape anyways. - // Implementation idea stolen from https://stackoverflow.com/a/5665377 - std::string escaped_body{}; - escaped_body.reserve( - static_cast(static_cast(body.size()) * 1.1)); - for (const char& character : body) { - switch (character) { - case '&': - escaped_body.append("&"); - break; - case '\"': - escaped_body.append("""); - break; - case '\'': - escaped_body.append("'"); - break; - case '<': - escaped_body.append("<"); - break; - case '>': - escaped_body.append(">"); - break; - default: - escaped_body.push_back(character); - break; - } - } + std::ostringstream formatted_body; + formatted_body << xml_escape(body); try { return bp::system(notify_send_path, "--urgency=normal", "--expire-time=30000", "--app-name=yabridge", title, - escaped_body, bp::posix::use_vfork) == EXIT_SUCCESS; + formatted_body.str(), + bp::posix::use_vfork) == EXIT_SUCCESS; } catch (const boost::process::process_error&) { // We will have printed the message to the terminal anyways, so if the // user doesn't have libnotify installed we'll just fail silently