~singpolyma/biboumi

c01befb054075ab414fd602859e5999a138aa5bf — Florent Le Coz 7 years ago 6a2240f
Implement room discovery using the LIST irc command

ref #2472
M src/bridge/bridge.cpp => src/bridge/bridge.cpp +38 -0
@@ 1,5 1,6 @@
#include <bridge/bridge.hpp>
#include <bridge/colors.hpp>
#include <bridge/list_element.hpp>
#include <xmpp/xmpp_component.hpp>
#include <xmpp/xmpp_stanza.hpp>
#include <irc/irc_message.hpp>


@@ 285,6 286,43 @@ void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick)
    irc->send_nick_command(new_nick);
}

void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq_id,
                                           const std::string& to_jid)
{
  IrcClient* irc = this->get_irc_client(iid.get_server());

  if (!irc)
    return;

  irc->send_list_command();
  irc_responder_callback_t cb = [this, iid, iq_id, to_jid](const std::string& irc_hostname,
                                                           const IrcMessage& message) -> bool
    {
      static std::vector<ListElement> list;

      if (irc_hostname != iid.get_server())
        return false;
      if (message.command == "263" || message.command == "RPL_TRYAGAIN")
        { // TODO send an error iq
          return true;
        }
      else if (message.command == "322" || message.command == "RPL_LIST")
        { // Add element to list
          if (message.arguments.size() == 4)
            list.emplace_back(message.arguments[1], message.arguments[2],
                              message.arguments[3]);
          return false;
        }
      else if (message.command == "323" || message.command == "RPL_LISTEND")
        { // Send the iq response with the content of the list
          this->xmpp->send_iq_room_list_result(iq_id, to_jid, std::to_string(iid), list);
          return true;
        }
      return false;
    };
  this->add_waiting_irc(std::move(cb));
}

void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason,
                           const std::string& iq_id, const std::string& to_jid)
{

M src/bridge/bridge.hpp => src/bridge/bridge.hpp +2 -0
@@ 72,6 72,8 @@ public:
  void send_irc_version_request(const std::string& irc_hostname, const std::string& target,
                                const std::string& iq_id, const std::string& to_jid,
                                const std::string& from_jid);
  void send_irc_channel_list_request(const Iid& iid, const std::string& iq_id,
                                     const std::string& to_jid);
  void forward_affiliation_role_change(const Iid& iid, const std::string& nick,
                                       const std::string& affiliation, const std::string& role);
  /**

A src/bridge/list_element.hpp => src/bridge/list_element.hpp +19 -0
@@ 0,0 1,19 @@
#ifndef LIST_ELEMENT_HPP_INCLUDED
#define LIST_ELEMENT_HPP_INCLUDED

#include <string>

struct ListElement
{
  ListElement(const std::string& channel, const std::string& nb_users,
                 const std::string& topic):
    channel(channel),
    nb_users(nb_users),
    topic(topic){}

  std::string channel;
  std::string nb_users;
  std::string topic;
};

#endif /* LIST_ELEMENT_HPP_INCLUDED */

M src/irc/irc_client.cpp => src/irc/irc_client.cpp +5 -0
@@ 196,6 196,11 @@ void IrcClient::send_kick_command(const std::string& chan_name, const std::strin
  this->send_message(IrcMessage("KICK", {chan_name, target, reason}));
}

void IrcClient::send_list_command()
{
  this->send_message(IrcMessage("LIST", {}));
}

void IrcClient::send_topic_command(const std::string& chan_name, const std::string& topic)
{
  this->send_message(IrcMessage("TOPIC", {chan_name, topic}));

M src/irc/irc_client.hpp => src/irc/irc_client.hpp +4 -0
@@ 104,6 104,10 @@ public:
   * Send the KICK irc command
   */
  void send_kick_command(const std::string& chan_name, const std::string& target, const std::string& reason);
  /**
   * Send the LIST irc command
   */
  void send_list_command();
  void send_topic_command(const std::string& chan_name, const std::string& topic);
  /**
   * Send the QUIT irc command

M src/xmpp/xmpp_component.cpp => src/xmpp/xmpp_component.cpp +32 -0
@@ 4,6 4,7 @@
#include <logger/logger.hpp>

#include <xmpp/xmpp_component.hpp>
#include <bridge/list_element.hpp>
#include <config/config.hpp>
#include <xmpp/jid.hpp>
#include <utils/sha1.hpp>


@@ 556,12 557,18 @@ void XmppComponent::handle_iq(const Stanza& stanza)
        }
      else if ((query = stanza.get_child("query", DISCO_ITEMS_NS)))
        {
          Iid iid(to.local);
          const std::string node = query->get_tag("node");
          if (node == ADHOC_NS)
            {
              this->send_adhoc_commands_list(id, from);
              stanza_error.disable();
            }
          else if (node.empty() && !iid.is_user && !iid.is_channel)
            { // Disco on an IRC server: get the list of channels
              bridge->send_irc_channel_list_request(iid, id, from);
              stanza_error.disable();
            }
        }
      else if ((query = stanza.get_child("ping", PING_NS)))
        {


@@ 1152,6 1159,31 @@ void XmppComponent::send_iq_result(const std::string& id, const std::string& to_
  this->send_stanza(iq);
}

void XmppComponent::send_iq_room_list_result(const std::string& id,
                                             const std::string to_jid,
                                             const std::string& from,
                                             const std::vector<ListElement>& rooms_list)
{
  Stanza iq("iq");
  iq["from"] = from + "@" + this->served_hostname;
  iq["to"] = to_jid;
  iq["id"] = id;
  iq["type"] = "result";
  XmlNode query("query");
  query["xmlns"] = DISCO_ITEMS_NS;
  for (const auto& room: rooms_list)
    {
      XmlNode item("item");
      item["jid"] = room.channel + "%" + from + "@" + this->served_hostname;
      item.close();
      query.add_child(std::move(item));
    }
  query.close();
  iq.add_child(std::move(query));
  iq.close();
  this->send_stanza(iq);
}

std::string XmppComponent::next_id()
{
  char uuid_str[37];

M src/xmpp/xmpp_component.hpp => src/xmpp/xmpp_component.hpp +8 -0
@@ 26,6 26,8 @@
#define ADHOC_NS         "http://jabber.org/protocol/commands"
#define PING_NS          "urn:xmpp:ping"

class ListElement;

/**
 * A callback called when the waited iq result is received (it is matched
 * against the iq id)


@@ 229,6 231,12 @@ public:
   */
  void send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from);
  /**
   * Send the channels list in one big stanza
   */
  void send_iq_room_list_result(const std::string& id, const std::string to_jid,
                                const std::string& from,
                                const std::vector<ListElement>& rooms_list);
  /**
   * Handle the various stanza types
   */
  void handle_handshake(const Stanza& stanza);