Commit 8cf0b833 authored by louiz’'s avatar louiz’

Make the IRC channel configuration form available from the MUC config

fix #3250
parent 577a8639
...@@ -17,6 +17,8 @@ Version 5.0 ...@@ -17,6 +17,8 @@ Version 5.0
- Configuration options can be overridden by values found in the process env. - Configuration options can be overridden by values found in the process env.
- Botan’s TLS policies can be customized by the administrator, for each - Botan’s TLS policies can be customized by the administrator, for each
IRC server, with simple text files. IRC server, with simple text files.
- The IRC channel configuration form is now also available using the MUC
configuration, in addition to the ad-hoc command.
Version 4.3 - 2017-05-02 Version 4.3 - 2017-05-02
======================== ========================
......
...@@ -418,11 +418,18 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co ...@@ -418,11 +418,18 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co
{ {
const Jid owner(session.get_owner_jid()); const Jid owner(session.get_owner_jid());
const Jid target(session.get_target_jid()); const Jid target(session.get_target_jid());
insert_irc_channel_configuration_form(command_node, owner, target);
}
void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, const Jid& target)
{
const Iid iid(target.local, {}); const Iid iid(target.local, {});
auto options = Database::get_irc_channel_options_with_server_default(owner.local + "@" + owner.domain,
auto options = Database::get_irc_channel_options_with_server_default(requester.local + "@" + requester.domain,
iid.get_server(), iid.get_local()); iid.get_server(), iid.get_local());
XmlSubNode x(command_node, "jabber:x:data:x"); XmlSubNode x(node, "jabber:x:data:x");
x["type"] = "form"; x["type"] = "form";
XmlSubNode title(x, "title"); XmlSubNode title(x, "title");
title.set_inner("Configure the IRC channel "s + iid.get_local() + " on server "s + iid.get_server()); title.set_inner("Configure the IRC channel "s + iid.get_local() + " on server "s + iid.get_server());
...@@ -468,17 +475,38 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co ...@@ -468,17 +475,38 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co
void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
{ {
const XmlNode* x = command_node.get_child("x", "jabber:x:data");
if (x)
{
const Jid owner(session.get_owner_jid()); const Jid owner(session.get_owner_jid());
const Jid target(session.get_target_jid()); const Jid target(session.get_target_jid());
if (handle_irc_channel_configuration_form(command_node, owner, target))
{
command_node.delete_all_children();
XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner("Configuration successfully applied.");
}
else
{
XmlSubNode error(command_node, ADHOC_NS":error");
error["type"] = "modify";
XmlSubNode condition(error, STANZA_NS":bad-request");
session.terminate();
}
}
bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& requester, const Jid& target)
{
const XmlNode* x = node.get_child("x", "jabber:x:data");
if (x)
{
if (x->get_tag("type") == "submit")
{
const Iid iid(target.local, {}); const Iid iid(target.local, {});
auto options = Database::get_irc_channel_options(owner.local + "@" + owner.domain, auto options = Database::get_irc_channel_options(requester.local + "@" + requester.domain,
iid.get_server(), iid.get_local()); iid.get_server(), iid.get_local());
for (const XmlNode* field: x->get_children("field", "jabber:x:data")) for (const XmlNode *field: x->get_children("field", "jabber:x:data"))
{ {
const XmlNode* value = field->get_child("value", "jabber:x:data"); const XmlNode *value = field->get_child("value", "jabber:x:data");
if (field->get_tag("var") == "encoding_out" && if (field->get_tag("var") == "encoding_out" &&
value && !value->get_inner().empty()) value && !value->get_inner().empty())
...@@ -494,17 +522,10 @@ void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& co ...@@ -494,17 +522,10 @@ void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& co
} }
options.update(); options.update();
command_node.delete_all_children();
XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner("Configuration successfully applied.");
return;
} }
XmlSubNode error(command_node, ADHOC_NS":error"); return true;
error["type"] = "modify"; }
XmlSubNode condition(error, STANZA_NS":bad-request"); return false;
session.terminate();
} }
#endif // USE_DATABASE #endif // USE_DATABASE
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <xmpp/adhoc_command.hpp> #include <xmpp/adhoc_command.hpp>
#include <xmpp/adhoc_session.hpp> #include <xmpp/adhoc_session.hpp>
#include <xmpp/xmpp_stanza.hpp> #include <xmpp/xmpp_stanza.hpp>
#include <xmpp/jid.hpp>
class XmppComponent; class XmppComponent;
...@@ -17,7 +18,9 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com ...@@ -17,7 +18,9 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node);
void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node);
void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, const Jid& target);
void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node);
bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& requester, const Jid& target);
void DisconnectUserFromServerStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); void DisconnectUserFromServerStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node);
void DisconnectUserFromServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); void DisconnectUserFromServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node);
......
...@@ -392,6 +392,11 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) ...@@ -392,6 +392,11 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
if (this->handle_mam_request(stanza)) if (this->handle_mam_request(stanza))
stanza_error.disable(); stanza_error.disable();
} }
else if ((query = stanza.get_child("query", MUC_OWNER_NS)))
{
if (this->handle_room_configuration_form(*query, from, to, id))
stanza_error.disable();
}
#endif #endif
} }
else if (type == "get") else if (type == "get")
...@@ -529,6 +534,13 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) ...@@ -529,6 +534,13 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
} }
stanza_error.disable(); stanza_error.disable();
} }
#ifdef USE_DATABASE
else if ((query = stanza.get_child("query", MUC_OWNER_NS)))
{
if (this->handle_room_configuration_form_request(from, to, id))
stanza_error.disable();
}
#endif
} }
else if (type == "result") else if (type == "result")
{ {
...@@ -679,6 +691,50 @@ void BiboumiComponent::send_archived_message(const db::MucLogLine& log_line, con ...@@ -679,6 +691,50 @@ void BiboumiComponent::send_archived_message(const db::MucLogLine& log_line, con
this->send_stanza(message); this->send_stanza(message);
} }
bool BiboumiComponent::handle_room_configuration_form_request(const std::string& from, const Jid& to, const std::string& id)
{
Iid iid(to.local, {'#', '&'});
if (iid.type != Iid::Type::Channel)
return false;
Stanza iq("iq");
{
iq["from"] = to.full();
iq["to"] = from;
iq["id"] = id;
iq["type"] = "result";
XmlSubNode query(iq, "query");
query["xmlns"] = MUC_OWNER_NS;
Jid requester(from);
insert_irc_channel_configuration_form(query, requester, to);
}
this->send_stanza(iq);
return true;
}
bool BiboumiComponent::handle_room_configuration_form(const XmlNode& query, const std::string &from, const Jid &to, const std::string &id)
{
Iid iid(to.local, {'#', '&'});
if (iid.type != Iid::Type::Channel)
return false;
Jid requester(from);
if (!handle_irc_channel_configuration_form(query, requester, to))
return false;
Stanza iq("iq");
iq["type"] = "result";
iq["from"] = to.full();
iq["to"] = from;
iq["id"] = id;
this->send_stanza(iq);
return true;
}
#endif #endif
Bridge* BiboumiComponent::get_user_bridge(const std::string& user_jid) Bridge* BiboumiComponent::get_user_bridge(const std::string& user_jid)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <xmpp/xmpp_component.hpp> #include <xmpp/xmpp_component.hpp>
#include <xmpp/jid.hpp>
#include <bridge/bridge.hpp> #include <bridge/bridge.hpp>
...@@ -97,6 +98,8 @@ public: ...@@ -97,6 +98,8 @@ public:
bool handle_mam_request(const Stanza& stanza); bool handle_mam_request(const Stanza& stanza);
void send_archived_message(const db::MucLogLine& log_line, const std::string& from, const std::string& to, void send_archived_message(const db::MucLogLine& log_line, const std::string& from, const std::string& to,
const std::string& queryid); const std::string& queryid);
bool handle_room_configuration_form_request(const std::string& from, const Jid& to, const std::string& id);
bool handle_room_configuration_form(const XmlNode& query, const std::string& from, const Jid& to, const std::string& id);
#endif #endif
/** /**
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#define MUC_NS "http://jabber.org/protocol/muc" #define MUC_NS "http://jabber.org/protocol/muc"
#define MUC_USER_NS MUC_NS"#user" #define MUC_USER_NS MUC_NS"#user"
#define MUC_ADMIN_NS MUC_NS"#admin" #define MUC_ADMIN_NS MUC_NS"#admin"
#define MUC_OWNER_NS MUC_NS"#owner"
#define DISCO_NS "http://jabber.org/protocol/disco" #define DISCO_NS "http://jabber.org/protocol/disco"
#define DISCO_ITEMS_NS DISCO_NS"#items" #define DISCO_ITEMS_NS DISCO_NS"#items"
#define DISCO_INFO_NS DISCO_NS"#info" #define DISCO_INFO_NS DISCO_NS"#info"
......
...@@ -118,6 +118,7 @@ def match(stanza, xpath): ...@@ -118,6 +118,7 @@ def match(stanza, xpath):
tree = lxml.etree.parse(io.StringIO(str(stanza))) tree = lxml.etree.parse(io.StringIO(str(stanza)))
matched = tree.xpath(xpath, namespaces={'re': 'http://exslt.org/regular-expressions', matched = tree.xpath(xpath, namespaces={'re': 'http://exslt.org/regular-expressions',
'muc_user': 'http://jabber.org/protocol/muc#user', 'muc_user': 'http://jabber.org/protocol/muc#user',
'muc_owner': 'http://jabber.org/protocol/muc#owner',
'muc': 'http://jabber.org/protocol/muc', 'muc': 'http://jabber.org/protocol/muc',
'disco_info': 'http://jabber.org/protocol/disco#info', 'disco_info': 'http://jabber.org/protocol/disco#info',
'muc_traffic': 'http://jabber.org/protocol/muc#traffic', 'muc_traffic': 'http://jabber.org/protocol/muc#traffic',
...@@ -2382,6 +2383,26 @@ if __name__ == '__main__': ...@@ -2382,6 +2383,26 @@ if __name__ == '__main__':
partial(send_stanza, "<iq type='set' id='id4' from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}'><command xmlns='http://jabber.org/protocol/commands' action='cancel' node='configure' sessionid='{sessionid}' /></iq>"), partial(send_stanza, "<iq type='set' id='id4' from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}'><command xmlns='http://jabber.org/protocol/commands' action='cancel' node='configure' sessionid='{sessionid}' /></iq>"),
partial(expect_stanza, "/iq[@type='result']/commands:command[@node='configure'][@status='canceled']"), partial(expect_stanza, "/iq[@type='result']/commands:command[@node='configure'][@status='canceled']"),
]), ]),
Scenario("irc_channel_configure_xep0045",
[
handshake_sequence(),
partial(send_stanza, "<iq type='get' id='id1' from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}'><query xmlns='http://jabber.org/protocol/muc#owner'/></iq>"),
partial(expect_stanza, ("/iq[@type='result']/muc_owner:query",
"/iq/muc_owner:query/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']",
"/iq/muc_owner:query/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_out']",
),
),
partial(send_stanza, "<iq type='set' id='id2' from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}'>"
"<query xmlns='http://jabber.org/protocol/muc#owner'>"
"<x xmlns='jabber:x:data' type='submit'>"
"<field var='ports' />"
"<field var='encoding_out'><value>UTF-8</value></field>"
"<field var='encoding_in'><value>latin-1</value></field>"
"</x></query></iq>"),
partial(expect_stanza, "/iq[@type='result']"),
partial(send_stanza, "<iq type='set' id='id3' from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}'><query xmlns='http://jabber.org/protocol/muc#owner'> <x xmlns='jabber:x:data' type='cancel'/></query></iq>"),
partial(expect_stanza, "/iq[@type='result']"),
]),
Scenario("irc_channel_configure_fixed", Scenario("irc_channel_configure_fixed",
[ [
handshake_sequence(), handshake_sequence(),
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment