summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bridge/bridge.cpp12
-rw-r--r--src/bridge/bridge.hpp2
-rw-r--r--src/irc/irc_client.cpp20
-rw-r--r--src/irc/irc_client.hpp6
-rw-r--r--src/xmpp/xmpp_component.cpp79
-rw-r--r--src/xmpp/xmpp_component.hpp9
6 files changed, 128 insertions, 0 deletions
diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp
index 0b26a7f..e39cdd3 100644
--- a/src/bridge/bridge.cpp
+++ b/src/bridge/bridge.cpp
@@ -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);
+}
diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp
index 0466ee1..b2124bd 100644
--- a/src/bridge/bridge.hpp
+++ b/src/bridge/bridge.hpp
@@ -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
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index 1d2e487..82abbd9 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -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];
diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp
index 07ff02c..3b22fa0 100644
--- a/src/irc/irc_client.hpp
+++ b/src/irc/irc_client.hpp
@@ -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
diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp
index c36a141..2d891bc 100644
--- a/src/xmpp/xmpp_component.cpp
+++ b/src/xmpp/xmpp_component.cpp
@@ -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);
+}
diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp
index 84b19a9..0c68497 100644
--- a/src/xmpp/xmpp_component.hpp
+++ b/src/xmpp/xmpp_component.hpp
@@ -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:
/**