Convert received modes into roles and affiliations
This commit is contained in:
@@ -24,7 +24,7 @@ IrcUser* IrcChannel::get_self() const
|
||||
return this->self.get();
|
||||
}
|
||||
|
||||
IrcUser* IrcChannel::find_user(const std::string& name)
|
||||
IrcUser* IrcChannel::find_user(const std::string& name) const
|
||||
{
|
||||
IrcUser user(name);
|
||||
for (const auto& u: this->users)
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
IrcUser* get_self() const;
|
||||
IrcUser* add_user(const std::string& name,
|
||||
const std::map<char, char> prefix_to_mode);
|
||||
IrcUser* find_user(const std::string& name);
|
||||
IrcUser* find_user(const std::string& name) const;
|
||||
void remove_user(const IrcUser* user);
|
||||
|
||||
private:
|
||||
|
||||
+74
-1
@@ -218,7 +218,10 @@ void IrcClient::on_isupport_message(const IrcMessage& message)
|
||||
j++;
|
||||
j++;
|
||||
while (j < token.size() && token[i] != ')')
|
||||
this->prefix_to_mode[token[j++]] = token[i++];
|
||||
{
|
||||
this->sorted_user_modes.push_back(token[i]);
|
||||
this->prefix_to_mode[token[j++]] = token[i++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -508,6 +511,76 @@ void IrcClient::on_channel_mode(const IrcMessage& message)
|
||||
this->bridge->send_message(iid, "", std::string("Mode ") + iid.chan +
|
||||
" [" + mode_arguments + "] by " + user.nick,
|
||||
true);
|
||||
const IrcChannel* channel = this->get_channel(iid.chan);
|
||||
if (!channel)
|
||||
return;
|
||||
|
||||
// parse the received modes, we need to handle things like "+m-oo coucou toutou"
|
||||
const std::string modes = message.arguments[1];
|
||||
// a list of modified IrcUsers. When we applied all modes, we check the
|
||||
// modes that now applies to each of them, and send a notification for
|
||||
// each one. This is to disallow sending two notifications or more when a
|
||||
// single MODE command changes two or more modes on the same participant
|
||||
std::set<const IrcUser*> modified_users;
|
||||
// If it is true, the modes are added, if it’s false they are
|
||||
// removed. When we encounter the '+' char, the value is changed to true,
|
||||
// and with '-' it is changed to false.
|
||||
bool add = true;
|
||||
bool use_arg;
|
||||
size_t arg_pos = 2;
|
||||
for (const char c: modes)
|
||||
{
|
||||
if (c == '+')
|
||||
add = true;
|
||||
else if (c == '-')
|
||||
add = false;
|
||||
else
|
||||
{ // lookup the mode symbol in the 4 chanmodes lists, depending on
|
||||
// the list where it is found, it takes an argument or not
|
||||
size_t type;
|
||||
for (type = 0; type < 4; ++type)
|
||||
if (this->chanmodes[type].find(c) != std::string::npos)
|
||||
break;
|
||||
if (type == 4) // if mode was not found
|
||||
{
|
||||
// That mode can also be of type B if it is present in the
|
||||
// prefix_to_mode map
|
||||
for (const std::pair<char, char>& pair: this->prefix_to_mode)
|
||||
if (pair.second == c)
|
||||
{
|
||||
type = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// modes of type A, B or C (but only with add == true)
|
||||
if (type == 0 || type == 1 ||
|
||||
(type == 2 && add == true))
|
||||
use_arg = true;
|
||||
else // modes of type C (but only with add == false), D, or unknown
|
||||
use_arg = false;
|
||||
if (use_arg == true && message.arguments.size() > arg_pos)
|
||||
{
|
||||
const std::string target = message.arguments[arg_pos++];
|
||||
IrcUser* user = channel->find_user(target);
|
||||
if (!user)
|
||||
{
|
||||
log_warning("Trying to set mode for non-existing user '" << target
|
||||
<< "' in channel" << iid.chan);
|
||||
return;
|
||||
}
|
||||
if (add)
|
||||
user->add_mode(c);
|
||||
else
|
||||
user->remove_mode(c);
|
||||
modified_users.insert(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const IrcUser* u: modified_users)
|
||||
{
|
||||
char most_significant_mode = u->get_most_significant_mode(this->sorted_user_modes);
|
||||
this->bridge->send_affiliation_role_change(iid, u->nick, most_significant_mode);
|
||||
}
|
||||
}
|
||||
|
||||
void IrcClient::on_user_mode(const IrcMessage& message)
|
||||
|
||||
@@ -229,9 +229,14 @@ private:
|
||||
/**
|
||||
* See http://www.irc.org/tech_docs/draft-brocklesby-irc-isupport-03.txt section 3.14
|
||||
* The example given would be transformed into
|
||||
* modes_to_prefix = {{'a', '&'}, {'b', '*'}}
|
||||
* modes_to_prefix = {{'&', 'a'}, {'*', 'b'}}
|
||||
*/
|
||||
std::map<char, char> prefix_to_mode;
|
||||
/**
|
||||
* Available user modes, sorted from most significant to least significant
|
||||
* (for example 'ahov' is a common order).
|
||||
*/
|
||||
std::vector<char> sorted_user_modes;
|
||||
|
||||
IrcClient(const IrcClient&) = delete;
|
||||
IrcClient(IrcClient&&) = delete;
|
||||
|
||||
@@ -25,3 +25,23 @@ IrcUser::IrcUser(const std::string& name):
|
||||
IrcUser(name, {})
|
||||
{
|
||||
}
|
||||
|
||||
void IrcUser::add_mode(const char mode)
|
||||
{
|
||||
this->modes.insert(mode);
|
||||
}
|
||||
|
||||
void IrcUser::remove_mode(const char mode)
|
||||
{
|
||||
this->modes.erase(mode);
|
||||
}
|
||||
|
||||
char IrcUser::get_most_significant_mode(const std::vector<char>& modes) const
|
||||
{
|
||||
for (const char mode: modes)
|
||||
{
|
||||
if (this->modes.find(mode) != this->modes.end())
|
||||
return mode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef IRC_USER_INCLUDED
|
||||
# define IRC_USER_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
@@ -14,6 +15,9 @@ public:
|
||||
explicit IrcUser(const std::string& name,
|
||||
const std::map<char, char>& prefix_to_mode);
|
||||
explicit IrcUser(const std::string& name);
|
||||
void add_mode(const char mode);
|
||||
void remove_mode(const char mode);
|
||||
char get_most_significant_mode(const std::vector<char>& sorted_user_modes) const;
|
||||
std::string nick;
|
||||
std::string host;
|
||||
std::set<char> modes;
|
||||
|
||||
Reference in New Issue
Block a user