~singpolyma/biboumi

0859801230f999889d0f7356864888e8c5936cda — Florent Le Coz 9 years ago 3cfaab9
Handle KICK in irc channel, both ways
M src/bridge/bridge.cpp => src/bridge/bridge.cpp +12 -0
@@ 122,6 122,13 @@ void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick)
    irc->send_nick_command(new_nick);
}

void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason)
{
  IrcClient* irc = this->get_irc_client(iid.server);
  if (irc)
    irc->send_kick_command(iid.chan, target, reason);
}

void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc)
{
  std::string utf8_body = this->sanitize_for_xmpp(body);


@@ 180,3 187,8 @@ std::string Bridge::get_own_nick(const Iid& iid)
    return irc->get_own_nick();
  return "";
}

void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author)
{
  this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid);
}

M src/bridge/bridge.hpp => src/bridge/bridge.hpp +2 -0
@@ 39,6 39,7 @@ public:
  void send_private_message(const Iid& iid, const std::string& body);
  void leave_irc_channel(Iid&& iid, std::string&& status_message);
  void send_irc_nick_change(const Iid& iid, const std::string& new_nick);
  void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason);

  /***
   **


@@ 76,6 77,7 @@ public:
   * true) changed his nick to new_nick
   */
  void send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self);
  void kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author);

  /**
   * Misc

M src/irc/irc_client.cpp => src/irc/irc_client.cpp +20 -0
@@ 113,6 113,11 @@ void IrcClient::send_nick_command(const std::string& nick)
  this->send_message(IrcMessage("NICK", {nick}));
}

void IrcClient::send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason)
{
  this->send_message(IrcMessage("KICK", {chan_name, target, reason}));
}

void IrcClient::send_join_command(const std::string& chan_name)
{
  if (this->welcomed == false)


@@ 311,6 316,21 @@ void IrcClient::on_nick(const IrcMessage& message)
    }
}

void IrcClient::on_kick(const IrcMessage& message)
{
  const std::string target = message.arguments[1];
  const std::string reason = message.arguments[2];
  const std::string chan_name = message.arguments[0];
  IrcChannel* channel = this->get_channel(chan_name);
  if (channel->get_self()->nick == target)
    channel->joined = false;
  IrcUser author(message.prefix);
  Iid iid;
  iid.chan = chan_name;
  iid.server = this->hostname;
  this->bridge->kick_muc_user(std::move(iid), target, reason, author.nick);
}

void IrcClient::on_mode(const IrcMessage& message)
{
  const std::string target = message.arguments[0];

M src/irc/irc_client.hpp => src/irc/irc_client.hpp +6 -0
@@ 92,6 92,10 @@ public:
   */
  void send_mode_command(const std::string& chan_name, const std::vector<std::string>& arguments);
  /**
   * Send the KICK irc command
   */
  void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason);
  /**
   * Forward the server message received from IRC to the XMPP component
   */
  void forward_server_message(const IrcMessage& message);


@@ 124,6 128,7 @@ public:
  void on_welcome_message(const IrcMessage& message);
  void on_part(const IrcMessage& message);
  void on_nick(const IrcMessage& message);
  void on_kick(const IrcMessage& message);
  void on_mode(const IrcMessage& message);
  /**
   * A mode towards our own user is received (note, that is different from a


@@ 194,6 199,7 @@ static const std::unordered_map<std::string, irc_callback_t> irc_callbacks = {
  {"NICK", &IrcClient::on_nick},
  {"MODE", &IrcClient::on_mode},
  {"PING", &IrcClient::send_pong_command},
  {"KICK", &IrcClient::on_kick},
};

#endif // IRC_CLIENT_INCLUDED

M src/xmpp/xmpp_component.cpp => src/xmpp/xmpp_component.cpp +79 -0
@@ 14,6 14,7 @@
#define COMPONENT_NS     "jabber:component:accept"
#define MUC_NS           "http://jabber.org/protocol/muc"
#define MUC_USER_NS      MUC_NS"#user"
#define MUC_ADMIN_NS     MUC_NS"#admin"
#define DISCO_NS         "http://jabber.org/protocol/disco"
#define DISCO_ITEMS_NS   DISCO_NS"#items"
#define DISCO_INFO_NS    DISCO_NS"#info"


@@ 36,6 37,8 @@ XmppComponent::XmppComponent(const std::string& hostname, const std::string& sec
                                std::bind(&XmppComponent::handle_presence, this,std::placeholders::_1));
  this->stanza_handlers.emplace(COMPONENT_NS":message",
                                std::bind(&XmppComponent::handle_message, this,std::placeholders::_1));
  this->stanza_handlers.emplace(COMPONENT_NS":iq",
                                std::bind(&XmppComponent::handle_iq, this,std::placeholders::_1));
}

XmppComponent::~XmppComponent()


@@ 201,6 204,46 @@ void XmppComponent::handle_message(const Stanza& stanza)
    }
}

void XmppComponent::handle_iq(const Stanza& stanza)
{
  Bridge* bridge = this->get_user_bridge(stanza["from"]);
  Jid to(stanza["to"]);
  std::string type;
  try {
    type = stanza["type"];
  }
  catch (const AttributeNotFound&)
    { return; }
  if (type == "set")
    {
      XmlNode* query;
      if ((query = stanza.get_child(MUC_ADMIN_NS":query")))
        {
          XmlNode* child;
          if ((child = query->get_child(MUC_ADMIN_NS":item")))
            {
              std::string nick;
              std::string role;
              try {
                nick = (*child)["nick"];
                role = (*child)["role"];
              }
              catch (const AttributeNotFound&)
                { return; }
              if (!nick.empty() && role == "none")
                {
                  std::string reason;
                  XmlNode* reason_el = child->get_child(MUC_ADMIN_NS":reason");
                  if (reason_el)
                    reason = reason_el->get_inner();
                  Iid iid(to.local);
                  bridge->send_irc_kick(iid, nick, reason);
                }
            }
        }
    }
}

Bridge* XmppComponent::get_user_bridge(const std::string& user_jid)
{
  try


@@ 360,3 403,39 @@ void XmppComponent::send_nick_change(const std::string& muc_name, const std::str
  else
    this->send_user_join(muc_name, new_nick, jid_to);
}

void XmppComponent::kick_user(const std::string& muc_name,
                                  const std::string& target,
                                  const std::string& txt,
                                  const std::string& author,
                                  const std::string& jid_to)
{
  Stanza presence("presence");
  presence["from"] = muc_name + "@" + this->served_hostname + "/" + target;
  presence["to"] = jid_to;
  presence["type"] = "unavailable";
  XmlNode x("x");
  x["xmlns"] = MUC_USER_NS;
  XmlNode item("item");
  item["affiliation"] = "none";
  item["role"] = "none";
  XmlNode actor("actor");
  actor["nick"] = author;
  actor["jid"] = author; // backward compatibility with old clients
  actor.close();
  item.add_child(std::move(actor));
  XmlNode reason("reason");
  reason.set_inner(txt);
  reason.close();
  item.add_child(std::move(reason));
  item.close();
  x.add_child(std::move(item));
  XmlNode status("status");
  status["code"] = "307";
  status.close();
  x.add_child(std::move(status));
  x.close();
  presence.add_child(std::move(x));
  presence.close();
  this->send_stanza(presence);
}

M src/xmpp/xmpp_component.hpp => src/xmpp/xmpp_component.hpp +9 -0
@@ 84,11 84,20 @@ public:
   */
  void send_nick_change(const std::string& muc_name, const std::string& old_nick, const std::string& new_nick, const std::string& jid_to, const bool self);
  /**
   * An user is kicked from a room
   */
  void kick_user(const std::string& muc_name,
                     const std::string& target,
                     const std::string& reason,
                     const std::string& author,
                     const std::string& jid_to);
  /**
   * Handle the various stanza types
   */
  void handle_handshake(const Stanza& stanza);
  void handle_presence(const Stanza& stanza);
  void handle_message(const Stanza& stanza);
  void handle_iq(const Stanza& stanza);

private:
  /**