Implement the Bridge class to translate between the two protocols

Add all useful classes as well: Jid, Iid, IrcChannel, IrcUser etc to
properly keep the informations about what we receive from the IRC server.

Only handle the MUC join stanza, and send the list of users in the IRC
channel to the XMPP user, and the IRC channel’s topic, for now.
This commit is contained in:
Florent Le Coz
2013-11-06 21:01:18 +01:00
parent dea7f60fa1
commit bf7b05ef72
17 changed files with 694 additions and 14 deletions
+19
View File
@@ -0,0 +1,19 @@
#include <xmpp/jid.hpp>
Jid::Jid(const std::string& jid)
{
std::string::size_type at = jid.find("@");
if (at != std::string::npos)
{
this->local = jid.substr(0, at);
at++;
}
else
at = 0;
std::string::size_type slash = jid.find("/", at);
if (slash != std::string::npos)
{
this->resource = jid.substr(slash + 1);
}
this->domain = jid.substr(at, slash - at);
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef JID_INCLUDED
# define JID_INCLUDED
#include <string>
/**
* Parse a JID into its different subart
*/
class Jid
{
public:
explicit Jid(const std::string& jid);
std::string domain;
std::string local;
std::string resource;
private:
Jid(const Jid&) = delete;
Jid(Jid&&) = delete;
Jid& operator=(const Jid&) = delete;
Jid& operator=(Jid&&) = delete;
};
#endif // JID_INCLUDED
+18
View File
@@ -0,0 +1,18 @@
#ifndef Stanza
# define Stanza
class Stanza
{
public:
explicit Stanza();
~Stanza();
private:
Stanza(const Stanza&) = delete;
Stanza(Stanza&&) = delete;
Stanza& operator=(const Stanza&) = delete;
Stanza& operator=(Stanza&&) = delete;
};
#endif // Stanza
+107 -3
View File
@@ -1,4 +1,7 @@
#include <utils/make_unique.hpp>
#include <xmpp/xmpp_component.hpp>
#include <xmpp/jid.hpp>
#include <iostream>
@@ -20,6 +23,8 @@ XmppComponent::XmppComponent(const std::string& hostname, const std::string& sec
std::placeholders::_1));
this->stanza_handlers.emplace("handshake",
std::bind(&XmppComponent::handle_handshake, this,std::placeholders::_1));
this->stanza_handlers.emplace("presence",
std::bind(&XmppComponent::handle_presence, this,std::placeholders::_1));
}
XmppComponent::~XmppComponent()
@@ -46,7 +51,6 @@ void XmppComponent::on_connected()
node["xmlns:stream"] = "http://etherx.jabber.org/streams";
node["to"] = "irc.abricot";
this->send_stanza(node);
}
void XmppComponent::on_connection_close()
@@ -99,16 +103,17 @@ void XmppComponent::on_stanza(const Stanza& stanza)
{
std::cout << "=========== STANZA ============" << std::endl;
std::cout << stanza.to_string() << std::endl;
std::function<void(const Stanza&)> handler;
try
{
const auto& handler = this->stanza_handlers.at(stanza.get_name());
handler(stanza);
handler = this->stanza_handlers.at(stanza.get_name());
}
catch (const std::out_of_range& exception)
{
std::cout << "No handler for stanza of type " << stanza.get_name() << std::endl;
return;
}
handler(stanza);
}
void XmppComponent::send_stream_error(const std::string& name, const std::string& explanation)
@@ -133,5 +138,104 @@ void XmppComponent::close_document()
void XmppComponent::handle_handshake(const Stanza& stanza)
{
(void)stanza;
this->authenticated = true;
}
void XmppComponent::handle_presence(const Stanza& stanza)
{
Bridge* bridge = this->get_user_bridge(stanza["from"]);
Jid to(stanza["to"]);
Iid iid(to.local);
if (!iid.chan.empty() && !iid.server.empty())
bridge->join_irc_channel(iid, to.resource);
}
Bridge* XmppComponent::get_user_bridge(const std::string& user_jid)
{
try
{
return this->bridges.at(user_jid).get();
}
catch (const std::out_of_range& exception)
{
this->bridges.emplace(user_jid, std::make_unique<Bridge>(user_jid, this, this->poller));
return this->bridges.at(user_jid).get();
}
}
void XmppComponent::send_message(const std::string& from, const std::string& body, const std::string& to)
{
XmlNode node("message");
node["to"] = to;
node["from"] = from + "@" + this->served_hostname;
XmlNode body_node("body");
body_node.set_inner(body);
body_node.close();
node.add_child(std::move(body_node));
node.close();
this->send_stanza(node);
}
void XmppComponent::send_user_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"] = "http://jabber.org/protocol/muc#user";
// TODO: put real values here
XmlNode item("item");
item["affiliation"] = "member";
item["role"] = "participant";
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"] = "http://jabber.org/protocol/muc#user";
// 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));
x.close();
node.add_child(std::move(x));
node.close();
this->send_stanza(node);
}
void XmppComponent::send_topic(const std::string& from, const std::string& topic, const std::string& to)
{
XmlNode message("message");
message["to"] = to;
message["from"] = from + "@" + this->served_hostname;
message["type"] = "groupchat";
XmlNode subject("subject");
subject.set_inner(topic);
subject.close();
message.add_child(std::move(subject));
message.close();
this->send_stanza(message);
}
+32 -4
View File
@@ -1,13 +1,13 @@
#ifndef XMPP_COMPONENT_INCLUDED
# define XMPP_COMPONENT_INCLUDED
#include <string>
#include <network/socket_handler.hpp>
#include <xmpp/xmpp_parser.hpp>
#include <bridge/bridge.hpp>
#include <unordered_map>
#include <memory>
#include <string>
/**
* An XMPP component, communicating with an XMPP server using the protocole
@@ -55,13 +55,35 @@ public:
* Send the closing signal for our document (not closing the connection though).
*/
void close_document();
/**
* Send a message from from@served_hostname, with the given body
*/
void send_message(const std::string& from, const std::string& body, const std::string& to);
/**
* Send a join from a new participant
*/
void send_user_join(const std::string& from, const std::string& nick, 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);
/**
* Send the MUC topic to the user
*/
void send_topic(const std::string& from, const std::string& topic, const std::string& to);
/**
* Handle the various stanza types
*/
void handle_handshake(const Stanza& stanza);
void handle_presence(const Stanza& stanza);
private:
/**
* Return the bridge associated with the given full JID. Create a new one
* if none already exist.
*/
Bridge* get_user_bridge(const std::string& user_jid);
XmppParser parser;
std::string stream_id;
std::string served_hostname;
@@ -70,6 +92,12 @@ private:
std::unordered_map<std::string, std::function<void(const Stanza&)>> stanza_handlers;
/**
* One bridge for each user of the component. Indexed by the user's full
* jid
*/
std::unordered_map<std::string, std::unique_ptr<Bridge>> bridges;
XmppComponent(const XmppComponent&) = delete;
XmppComponent(XmppComponent&&) = delete;
XmppComponent& operator=(const XmppComponent&) = delete;