~singpolyma/biboumi

43cc60e4a9e2859fdf67c89e58ee18cf7571f186 — Florent Le Coz 9 years ago e8e592d
Handle nickname conflicts by sending the correct XMPP error presence
M src/bridge/bridge.cpp => src/bridge/bridge.cpp +5 -0
@@ 216,3 216,8 @@ void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::stri
{
  this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid);
}

void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname)
{
  this->xmpp->send_nickname_conflict_error(iid.chan + "%" + iid.server, nickname, this->user_jid);
}

M src/bridge/bridge.hpp => src/bridge/bridge.hpp +1 -0
@@ 89,6 89,7 @@ public:
   */
  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);
  void send_nickname_conflict_error(const Iid& iid, const std::string& nickname);

  /**
   * Misc

M src/irc/irc_client.cpp => src/irc/irc_client.cpp +13 -0
@@ 303,6 303,19 @@ void IrcClient::on_erroneous_nickname(const IrcMessage& message)
  this->send_gateway_message(error_msg + ": " + message.arguments[1], message.prefix);
}

void IrcClient::on_nickname_conflict(const IrcMessage& message)
{
  const std::string nickname = message.arguments[1];
  this->on_generic_error(message);
  for (auto it = this->channels.begin(); it != this->channels.end(); ++it)
  {
    Iid iid;
    iid.chan = it->first;
    iid.server = this->hostname;
    this->bridge->send_nickname_conflict_error(iid, nickname);
  }
}

void IrcClient::on_generic_error(const IrcMessage& message)
{
  const std::string error_msg = message.arguments.size() >= 3 ?

M src/irc/irc_client.hpp => src/irc/irc_client.hpp +6 -0
@@ 149,6 149,11 @@ public:
   */
  void on_erroneous_nickname(const IrcMessage& message);
  /**
   * When the IRC servers denies our nickname because of a conflict.  Send a
   * presence conflict from all channels, because the name is server-wide.
   */
  void on_nickname_conflict(const IrcMessage& message);
  /**
   * Handles most errors from the server by just forwarding the message to the user.
   */
  void on_generic_error(const IrcMessage& message);


@@ 237,6 242,7 @@ static const std::unordered_map<std::string, irc_callback_t> irc_callbacks = {
  {"TOPIC", &IrcClient::on_topic_received},
  {"366", &IrcClient::on_channel_completely_joined},
  {"432", &IrcClient::on_erroneous_nickname},
  {"433", &IrcClient::on_nickname_conflict},
  {"461", &IrcClient::on_generic_error},
  {"001", &IrcClient::on_welcome_message},
  {"PART", &IrcClient::on_part},

M src/xmpp/xmpp_component.cpp => src/xmpp/xmpp_component.cpp +27 -2
@@ 20,6 20,7 @@
#define DISCO_ITEMS_NS   DISCO_NS"#items"
#define DISCO_INFO_NS    DISCO_NS"#info"
#define XHTMLIM_NS       "http://jabber.org/protocol/xhtml-im"
#define STANZA_NS        "urn:ietf:params:xml:ns:xmpp-stanzas"

XmppComponent::XmppComponent(const std::string& hostname, const std::string& secret):
  served_hostname(hostname),


@@ 195,8 196,7 @@ void XmppComponent::handle_presence(const Stanza& stanza)
          const std::string own_nick = bridge->get_own_nick(iid);
          if (!own_nick.empty() && own_nick != to.resource)
            bridge->send_irc_nick_change(iid, to.resource);
          else
            bridge->join_irc_channel(iid, to.resource);
          bridge->join_irc_channel(iid, to.resource);
        }
      else if (type == "unavailable")
        {


@@ 479,3 479,28 @@ void XmppComponent::kick_user(const std::string& muc_name,
  presence.close();
  this->send_stanza(presence);
}

void XmppComponent::send_nickname_conflict_error(const std::string& muc_name,
                                                 const std::string& nickname,
                                                 const std::string& jid_to)
{
  Stanza presence("presence");
  presence["from"] = muc_name + "@" + this->served_hostname + "/" + nickname;
  presence["to"] = jid_to;
  XmlNode x("x");
  x["xmlns"] = MUC_NS;
  x.close();
  presence.add_child(std::move(x));
  XmlNode error("error");
  error["by"] = muc_name + "@" + this->served_hostname;
  error["type"] = "cancel";
  error["code"] = "409";
  XmlNode conflict("conflict");
  conflict["xmlns"] = STANZA_NS;
  conflict.close();
  error.add_child(std::move(conflict));
  error.close();
  presence.add_child(std::move(error));
  presence.close();
  this->send_stanza(presence);
}

M src/xmpp/xmpp_component.hpp => src/xmpp/xmpp_component.hpp +6 -0
@@ 108,6 108,12 @@ public:
                     const std::string& author,
                     const std::string& jid_to);
  /**
   * Send a presence type=error with a conflict element
   */
  void send_nickname_conflict_error(const std::string& muc_name,
                                    const std::string& nickname,
                                    const std::string& jid_to);
  /**
   * Handle the various stanza types
   */
  void handle_handshake(const Stanza& stanza);