~singpolyma/biboumi

acf769d83a40e971ccc1346225688841465b36ee — Florent Le Coz 9 years ago a075517
Use isupport informations to know the user modes when joining

Also remove the duplicate send_self_join methods, user only send_user_join
M src/bridge/bridge.cpp => src/bridge/bridge.cpp +11 -7
@@ 189,14 189,18 @@ void Bridge::send_xmpp_message(const std::string& from, const std::string& autho

void Bridge::send_user_join(const std::string& hostname,
                            const std::string& chan_name,
                            const IrcUser* user)
                            const IrcUser* user,
                            const bool self)
{
  this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host, this->user_jid);
}

void Bridge::send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick)
{
  this->xmpp->send_self_join(chan_name + "%" + hostname, nick, this->user_jid);
  std::string affiliation = "participant";
  std::string role = "none";
  if (user->modes.find('o') != user->modes.end())
    {
      affiliation = "admin";
      role = "moderator";
    }
  this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host,
                             affiliation, role, this->user_jid, self);
}

void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic)

M src/bridge/bridge.hpp => src/bridge/bridge.hpp +2 -5
@@ 66,11 66,8 @@ public:
   */
  void send_user_join(const std::string& hostname,
                      const std::string& chan_name,
                      const IrcUser* user);
  /**
   * Send the self presence of an user when the MUC is fully joined.
   */
  void send_self_join(const std::string& hostname, const std::string& chan_name, const std::string nick);
                      const IrcUser* user,
                      const bool self);
  /**
   * Send the topic of the MUC to the user
   */

M src/irc/irc_channel.cpp => src/irc/irc_channel.cpp +3 -2
@@ 12,9 12,10 @@ void IrcChannel::set_self(const std::string& name)
  this->self = std::make_unique<IrcUser>(name);
}

IrcUser* IrcChannel::add_user(const std::string& name)
IrcUser* IrcChannel::add_user(const std::string& name,
                              const std::map<char, char> prefix_to_mode)
{
  this->users.emplace_back(std::make_unique<IrcUser>(name));
  this->users.emplace_back(std::make_unique<IrcUser>(name, prefix_to_mode));
  return this->users.back().get();
}


M src/irc/irc_channel.hpp => src/irc/irc_channel.hpp +3 -1
@@ 5,6 5,7 @@
#include <memory>
#include <string>
#include <vector>
#include <map>

/**
 * Keep the state of a joined channel (the list of occupants with their


@@ 19,7 20,8 @@ public:
  std::string topic;
  void set_self(const std::string& name);
  IrcUser* get_self() const;
  IrcUser* add_user(const std::string& name);
  IrcUser* add_user(const std::string& name,
                    const std::map<char, char> prefix_to_mode);
  IrcUser* find_user(const std::string& name);
  void remove_user(const IrcUser* user);


M src/irc/irc_client.cpp => src/irc/irc_client.cpp +10 -5
@@ 235,11 235,16 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message)
  std::vector<std::string> nicks = utils::split(message.arguments[3], ' ');
  for (const std::string& nick: nicks)
    {
      const IrcUser* user = channel->add_user(nick);
      const IrcUser* user = channel->add_user(nick, this->prefix_to_mode);
      if (user->nick != channel->get_self()->nick)
        {
          log_debug("Adding user [" << nick << "] to chan " << chan_name);
          this->bridge->send_user_join(this->hostname, chan_name, user);
          this->bridge->send_user_join(this->hostname, chan_name, user, false);
        }
      else
        {
          // we now know the modes of self, so copy the modes into self
          channel->get_self()->modes = user->modes;
        }
    }
}


@@ 256,8 261,8 @@ void IrcClient::on_channel_join(const IrcMessage& message)
    }
  else
    {
      const IrcUser* user = channel->add_user(nick);
      this->bridge->send_user_join(this->hostname, chan_name, user);
      const IrcUser* user = channel->add_user(nick, this->prefix_to_mode);
      this->bridge->send_user_join(this->hostname, chan_name, user, false);
    }
}



@@ 319,7 324,7 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message)
{
  const std::string chan_name = utils::tolower(message.arguments[1]);
  IrcChannel* channel = this->get_channel(chan_name);
  this->bridge->send_self_join(this->hostname, chan_name, channel->get_self()->nick);
  this->bridge->send_user_join(this->hostname, chan_name, channel->get_self(), true);
  this->bridge->send_topic(this->hostname, chan_name, channel->topic);
}


M src/irc/irc_user.cpp => src/irc/irc_user.cpp +15 -15
@@ 2,26 2,26 @@

#include <iostream>

IrcUser::IrcUser(const std::string& name)
IrcUser::IrcUser(const std::string& name,
                 const std::map<char, char>& prefix_to_mode)
{
  if (name.empty())
    return ;
  const std::string::size_type sep = name.find("!");
  const std::map<char, char>::const_iterator prefix = prefix_to_mode.find(name[0]);
  const size_t name_begin = prefix == prefix_to_mode.end()? 0: 1;
  if (sep == std::string::npos)
    {
      if (name[0] == '~' || name[0] == '&'
          || name[0] == '@' || name[0] == '%'
          || name[0] == '+')
        this->nick = name.substr(1);
      else
        this->nick = name;
    }
    this->nick = name.substr(name_begin);
  else
    {
      if (name[0] == '~' || name[0] == '&'
          || name[0] == '@' || name[0] == '%'
          || name[0] == '+')
        this->nick = name.substr(1, sep);
      else
        this->nick = name.substr(0, sep);
      this->nick = name.substr(name_begin, sep);
      this->host = name.substr(sep+1);
    }
  if (prefix != prefix_to_mode.end())
    this->modes.insert(prefix->second);
}

IrcUser::IrcUser(const std::string& name):
  IrcUser(name, {})
{
}

M src/irc/irc_user.hpp => src/irc/irc_user.hpp +5 -1
@@ 2,6 2,8 @@
# define IRC_USER_INCLUDED

#include <string>
#include <map>
#include <set>

/**
 * Keeps various information about one IRC channel user


@@ 9,10 11,12 @@
class IrcUser
{
public:
  explicit IrcUser(const std::string& name,
                   const std::map<char, char>& prefix_to_mode);
  explicit IrcUser(const std::string& name);

  std::string nick;
  std::string host;
  std::set<char> modes;

private:
  IrcUser(const IrcUser&) = delete;

M src/xmpp/xmpp_component.cpp => src/xmpp/xmpp_component.cpp +14 -34
@@ 294,7 294,10 @@ void XmppComponent::send_message(const std::string& from, Xmpp::body&& body, con
void XmppComponent::send_user_join(const std::string& from,
                                   const std::string& nick,
                                   const std::string& realjid,
                                   const std::string& to)
                                   const std::string& affiliation,
                                   const std::string& role,
                                   const std::string& to,
                                   const bool self)
{
  XmlNode node("presence");
  node["to"] = to;


@@ 305,8 308,8 @@ void XmppComponent::send_user_join(const std::string& from,

  // TODO: put real values here
  XmlNode item("item");
  item["affiliation"] = "member";
  item["role"] = "participant";
  item["affiliation"] = affiliation;
  item["role"] = role;
  if (!realjid.empty())
    {
      const std::string preped_jid = jidprep(realjid);


@@ 315,35 318,15 @@ void XmppComponent::send_user_join(const std::string& from,
    }
  item.close();
  x.add_child(std::move(item));
  x.close();
  node.add_child(std::move(x));
  node.close();
  this->send_stanza(node);
}

void XmppComponent::send_self_join(const std::string& from, const std::string& nick, const std::string& to)
{
  XmlNode node("presence");
  node["to"] = to;
  node["from"] = from + "@" + this->served_hostname + "/" + nick;

  XmlNode x("x");
  x["xmlns"] = MUC_USER_NS;

  // TODO: put real values here
  XmlNode item("item");
  item["affiliation"] = "member";
  item["role"] = "participant";
  item.close();
  x.add_child(std::move(item));

  XmlNode status("status");
  status["code"] = "110";
  status.close();
  x.add_child(std::move(status));

  if (self)
    {
      XmlNode status("status");
      status["code"] = "110";
      status.close();
      x.add_child(std::move(status));
    }
  x.close();

  node.add_child(std::move(x));
  node.close();
  this->send_stanza(node);


@@ 438,10 421,7 @@ void XmppComponent::send_nick_change(const std::string& muc_name, const std::str
  presence.close();
  this->send_stanza(presence);

  if (self)
    this->send_self_join(muc_name, new_nick, jid_to);
  else
    this->send_user_join(muc_name, new_nick, "", jid_to);
  this->send_user_join(muc_name, new_nick, "", "participant", "none", jid_to, self);
}

void XmppComponent::kick_user(const std::string& muc_name,

M src/xmpp/xmpp_component.hpp => src/xmpp/xmpp_component.hpp +4 -5
@@ 78,11 78,10 @@ public:
  void send_user_join(const std::string& from,
                      const std::string& nick,
                      const std::string& realjid,
                      const std::string& to);
  /**
   * Send the self join to the user
   */
  void send_self_join(const std::string& from, const std::string& nick, const std::string& to);
                      const std::string& affiliation,
                      const std::string& role,
                      const std::string& to,
                      const bool self);
  /**
   * Send the MUC topic to the user
   */