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
- Configuration options can be overridden by values found in the process env.
- Botan’s TLS policies can be customized by the administrator, for each
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
========================
......
......@@ -418,11 +418,18 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co
{
const Jid owner(session.get_owner_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, {});
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());
XmlSubNode x(command_node, "jabber:x:data:x");
XmlSubNode x(node, "jabber:x:data:x");
x["type"] = "form";
XmlSubNode title(x, "title");
title.set_inner("Configure the IRC channel "s + iid.get_local() + " on server "s + iid.get_server());
......@@ -468,43 +475,57 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co
void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
{
const XmlNode* x = command_node.get_child("x", "jabber:x:data");
const Jid owner(session.get_owner_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)
{
const Jid owner(session.get_owner_jid());
const Jid target(session.get_target_jid());
const Iid iid(target.local, {});
auto options = Database::get_irc_channel_options(owner.local + "@" + owner.domain,
iid.get_server(), iid.get_local());
for (const XmlNode* field: x->get_children("field", "jabber:x:data"))
if (x->get_tag("type") == "submit")
{
const XmlNode* value = field->get_child("value", "jabber:x:data");
if (field->get_tag("var") == "encoding_out" &&
value && !value->get_inner().empty())
options.encodingOut = value->get_inner();
const Iid iid(target.local, {});
auto options = Database::get_irc_channel_options(requester.local + "@" + requester.domain,
iid.get_server(), iid.get_local());
for (const XmlNode *field: x->get_children("field", "jabber:x:data"))
{
const XmlNode *value = field->get_child("value", "jabber:x:data");
else if (field->get_tag("var") == "encoding_in" &&
value && !value->get_inner().empty())
options.encodingIn = value->get_inner();
if (field->get_tag("var") == "encoding_out" &&
value && !value->get_inner().empty())
options.encodingOut = value->get_inner();
else if (field->get_tag("var") == "persistent" &&
value)
options.persistent = to_bool(value->get_inner());
}
else if (field->get_tag("var") == "encoding_in" &&
value && !value->get_inner().empty())
options.encodingIn = value->get_inner();
options.update();
else if (field->get_tag("var") == "persistent" &&
value)
options.persistent = to_bool(value->get_inner());
}
command_node.delete_all_children();
XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner("Configuration successfully applied.");
return;
options.update();
}
return true;
}
XmlSubNode error(command_node, ADHOC_NS":error");
error["type"] = "modify";
XmlSubNode condition(error, STANZA_NS":bad-request");
session.terminate();
return false;
}
#endif // USE_DATABASE
......
......@@ -4,6 +4,7 @@
#include <xmpp/adhoc_command.hpp>
#include <xmpp/adhoc_session.hpp>
#include <xmpp/xmpp_stanza.hpp>
#include <xmpp/jid.hpp>
class XmppComponent;
......@@ -17,7 +18,9 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
void ConfigureIrcServerStep2(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);
bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& requester, const Jid& target);
void DisconnectUserFromServerStep1(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)
if (this->handle_mam_request(stanza))
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
}
else if (type == "get")
......@@ -529,6 +534,13 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
}
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")
{
......@@ -679,6 +691,50 @@ void BiboumiComponent::send_archived_message(const db::MucLogLine& log_line, con
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
Bridge* BiboumiComponent::get_user_bridge(const std::string& user_jid)
......
......@@ -2,6 +2,7 @@
#include <xmpp/xmpp_component.hpp>
#include <xmpp/jid.hpp>
#include <bridge/bridge.hpp>
......@@ -97,6 +98,8 @@ public:
bool handle_mam_request(const Stanza& stanza);
void send_archived_message(const db::MucLogLine& log_line, const std::string& from, const std::string& to,
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
/**
......
......@@ -17,6 +17,7 @@
#define MUC_NS "http://jabber.org/protocol/muc"
#define MUC_USER_NS MUC_NS"#user"
#define MUC_ADMIN_NS MUC_NS"#admin"
#define MUC_OWNER_NS MUC_NS"#owner"
#define DISCO_NS "http://jabber.org/protocol/disco"
#define DISCO_ITEMS_NS DISCO_NS"#items"
#define DISCO_INFO_NS DISCO_NS"#info"
......
......@@ -118,6 +118,7 @@ def match(stanza, xpath):
tree = lxml.etree.parse(io.StringIO(str(stanza)))
matched = tree.xpath(xpath, namespaces={'re': 'http://exslt.org/regular-expressions',
'muc_user': 'http://jabber.org/protocol/muc#user',
'muc_owner': 'http://jabber.org/protocol/muc#owner',
'muc': 'http://jabber.org/protocol/muc',
'disco_info': 'http://jabber.org/protocol/disco#info',
'muc_traffic': 'http://jabber.org/protocol/muc#traffic',
......@@ -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(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",
[
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