#pragma once #include "irc_command.hpp" #include "ircmsg.hpp" #include "snote.hpp" #include "stream.hpp" #include #include #include #include #include template class Ref { struct Deleter { auto operator()(auto ptr) { Free(ptr); }}; std::unique_ptr obj; public: Ref() = default; Ref(T* t) : obj{t} { if (t) UpRef(t); } auto get() const -> T* { return obj.get(); } }; struct ConnectSettings { bool tls; std::string host; std::uint16_t port; Ref client_cert; Ref client_key; std::string verify; std::string sni; std::string socks_host; std::uint16_t socks_port; std::string socks_user; std::string socks_pass; }; class Connection : public std::enable_shared_from_this { private: Stream stream_; boost::asio::steady_timer watchdog_timer_; std::list write_strings_; bool write_posted_; // Set true when watchdog triggers. // Set false when message received. bool stalled_; // AUTHENTICATE support std::string authenticate_buffer_; auto write_buffers() -> void; auto dispatch_line(char *line) -> void; static constexpr std::chrono::seconds watchdog_duration = std::chrono::seconds{30}; auto watchdog() -> void; auto watchdog_activity() -> void; auto connect(ConnectSettings settings) -> boost::asio::awaitable; auto on_authenticate(std::string_view) -> void; /// Build and send well-formed IRC message from individual parameters auto write_irc(std::string) -> void; auto write_irc(std::string, std::string_view) -> void; template auto write_irc(std::string front, std::string_view next, Args... rest) -> void; public: boost::signals2::signal sig_connect; boost::signals2::signal sig_disconnect; boost::signals2::signal sig_ircmsg; boost::signals2::signal sig_snote; boost::signals2::signal sig_authenticate; Connection(boost::asio::io_context &io); /// Write bytes into the socket. auto write_line(std::string message) -> void; auto get_executor() -> boost::asio::any_io_executor { return stream_.get_executor(); } auto start(ConnectSettings) -> void; auto close() -> void; auto send_ping(std::string_view) -> void; auto send_pong(std::string_view) -> void; auto send_pass(std::string_view) -> void; auto send_user(std::string_view, std::string_view) -> void; auto send_nick(std::string_view) -> void; auto send_join(std::string_view) -> void; auto send_cap_ls() -> void; auto send_cap_end() -> void; auto send_cap_req(std::string_view) -> void; auto send_privmsg(std::string_view, std::string_view) -> void; auto send_notice(std::string_view, std::string_view) -> void; auto send_authenticate(std::string_view message) -> void; auto send_authenticate_encoded(std::string_view message) -> void; auto send_authenticate_abort() -> void; }; template auto Connection::write_irc(std::string front, std::string_view next, Args... rest) -> void { using namespace std::literals; if (next.empty() || next.front() == ':' || next.find_first_of("\r\n \0"sv) != next.npos) { throw std::runtime_error{"bad irc argument"}; } front += " "; front += next; write_irc(std::move(front), rest...); }