1
0
Fork 0
mirror of https://gitlab.com/niansa/asbots.git synced 2025-03-06 20:48:25 +01:00

(Almost) fully implemented modes

This commit is contained in:
Nils 2021-06-19 14:27:15 +02:00
parent 36717eb59c
commit f689535382
2 changed files with 110 additions and 5 deletions

View file

@ -73,12 +73,17 @@ void Command::parse(std::string_view str) {
}
template<bool channelModes>
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<false>(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<true>(split[2], netInfo);
// Get members
for (auto& raw_uuid : strSplit(event.text, ' ')) {
// Erase leading sign
@ -359,7 +394,7 @@ async::result<void> Instance::process(const Event event) {
throw DesyncError();
}
// Update mode
res->get()->umode.parse(event.text, netInfo);
res->get()->umode.parse<false>(event.text, netInfo);
}
// Channel updates
else if (event.name == "SJOIN") {
@ -378,6 +413,62 @@ async::result<void> 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<UUID>(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<true>(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<UUID>(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<true>("+{} {}"_format(modes, event.text), netInfo);
}
}
//std::clog << event.dump() << std::flush;

View file

@ -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<std::tuple<char, std::string>> params;
template<bool channelModes>
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<void> wait_ready() {