From f689535382332cf1ad82231afc9ebe2eb0d36859 Mon Sep 17 00:00:00 2001 From: Nils Date: Sat, 19 Jun 2021 14:27:15 +0200 Subject: [PATCH] (Almost) fully implemented modes --- instance.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--- instance.hpp | 16 ++++++++- 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/instance.cpp b/instance.cpp index 82d4ab9..dc53dc9 100644 --- a/instance.cpp +++ b/instance.cpp @@ -73,12 +73,17 @@ void Command::parse(std::string_view str) { } +template void ModeSet::parse(std::string_view in, NetworkInfo &netInfo) { enum { ADDING, REMOVING } op; - for (const auto character : in) { + // Split up + auto split = strSplit(in, ' '); + auto paramIt = split.begin() + 1; + // Iterate through mode characters + for (const char character : split[0]) { if (character == '+') { op = ADDING; } else if (character == '-') { @@ -87,11 +92,41 @@ void ModeSet::parse(std::string_view in, NetworkInfo &netInfo) { if (op == ADDING) { if (str.find(character) == str.npos) { str.push_back(character); + if constexpr(channelModes) { + if (netInfo.channelModes.takesParamOnSet(character)) { + if (paramIt == split.end()) { + throw DesyncError(); + } + params.push_back({character, std::string(*(paramIt++))}); + } + } + } else { + throw DesyncError(); } } else if (op == REMOVING) { auto res = str.find(character); if (res != str.npos) { str.erase(res); + if constexpr(channelModes) { + if (netInfo.channelModes.takesParamOnUnset(character)) { + if (paramIt == split.end()) { + throw DesyncError(); + } + for (auto it = params.begin(); ; it++) { + if (it == params.end()) { + throw DesyncError(); + } + auto &[c, d] = *it; + if (c == character && (d == *paramIt || *paramIt == "*")) { + params.erase(it); + break; + } + } + paramIt++; + } + } + } else { + throw DesyncError(); } } } @@ -109,7 +144,7 @@ void User::parse_euid(const Event& event, NetworkInfo& netInfo) { // Move values nick = std::move(split[0]); hops = std::stoull(std::string(split[1])); - umode.parse(split[3], netInfo); + umode.parse(split[3], netInfo); ident = std::move(split[4]); host = std::move(split[5]); realhost = std::move(split[6]); @@ -132,7 +167,7 @@ void Channel::parse_sjoin(const Event& event, Cache& cache, NetworkInfo& netInfo } // Move values name = std::move(split[1]); - mode.parse(split[2], netInfo); + mode.parse(split[2], netInfo); // Get members for (auto& raw_uuid : strSplit(event.text, ' ')) { // Erase leading sign @@ -359,7 +394,7 @@ async::result Instance::process(const Event event) { throw DesyncError(); } // Update mode - res->get()->umode.parse(event.text, netInfo); + res->get()->umode.parse(event.text, netInfo); } // Channel updates else if (event.name == "SJOIN") { @@ -378,6 +413,62 @@ async::result Instance::process(const Event event) { } // Set topic res->get()->topic = event.text; + } else if (event.name == "JOIN") { + // User joined existing channel + // Split args + auto split = strSplit(event.args, ' ', 2); + if (split.size() != 3) { + throw ParseError("In join event parser: join even did not receive enough arguments (expected 3)"); + } + // Get channel from cache + auto c_res = cache.find_channel_by_name(split[1]); + if (c_res == cache.channels.end()) { + throw DesyncError(); + } + // Get user from cache + auto u_res = cache.find_user_by_uid(std::get(event.sender.id)); + if (u_res == cache.users.end()) { + throw DesyncError(); + } + // Assign user to channel and vice versa + c_res->get()->members.push_back(*u_res); + u_res->get()->channels.push_back(*c_res); + // Update channel modes + c_res->get()->mode.parse(split[2], netInfo); + } else if (event.name == "PART" || event.name == "KICK") { + // User left channel + // Get channel from cache + auto c_res = cache.find_channel_by_name(strSplit(event.args, ' ', 1)[0]); + if (c_res == cache.channels.end()) { + throw DesyncError(); + } + // Get user from cache + auto u_res = cache.find_user_by_uid(std::get(event.sender.id)); + if (u_res == cache.users.end()) { + throw DesyncError(); + } + // Remove channel from both user and channel + c_res->get()->removeMember(*u_res); + u_res->get()->removeChannel(*c_res); + } else if (event.name == "TMODE" || event.name == "BMASK") { + // Channel modes changed + // Split args + std::string_view modes, channelName; + { + auto split = strSplit(event.args, ' ', 2); + if (split.size() != 3) { + throw DesyncError(); + } + channelName = split[1]; + modes = split[2]; + } + // Get channel from cache + auto c_res = cache.find_channel_by_name(channelName); + if (c_res == cache.channels.end()) { + throw DesyncError(); + } + // Apply changes + c_res->get()->mode.parse("+{} {}"_format(modes, event.text), netInfo); } } //std::clog << event.dump() << std::flush; diff --git a/instance.hpp b/instance.hpp index a90287c..a4e3921 100644 --- a/instance.hpp +++ b/instance.hpp @@ -52,14 +52,16 @@ struct Command { std::string name, args, text; std::string dump() const { - return fmt::format("{} {}{}\n", name, args, (text.empty()?"":":"+text)); + return fmt::format("{} {}{}\n", name, args, (text.empty()?"":" :"+text)); } void parse(std::string_view str); }; struct ModeSet { std::string str; + std::vector> params; + template void parse(std::string_view str, NetworkInfo& netInfo); }; @@ -118,6 +120,18 @@ struct NetworkInfo { paramOnSetAndUnsetModes, // Properties like k paramOnSetOnlyModes, // Properties like f paramLessModes; // Properties like z + + bool takesNoParam(char mode) { + return paramLessModes.find(mode) != paramLessModes.npos; + } + bool takesParamOnUnset(char mode) { + return listModes.find(mode) != std::string::npos || + paramOnSetAndUnsetModes.find(mode) != std::string::npos; + } + bool takesParamOnSet(char mode) { + return paramOnSetOnlyModes.find(mode) != std::string::npos || + takesParamOnUnset(mode); + } } channelModes; async::result wait_ready() {