summaryrefslogtreecommitdiff
path: root/src/xmpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmpp')
-rw-r--r--src/xmpp/biboumi_adhoc_commands.cpp267
-rw-r--r--src/xmpp/biboumi_component.cpp291
-rw-r--r--src/xmpp/biboumi_component.hpp7
3 files changed, 251 insertions, 314 deletions
diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp
index 003b901..ccb3517 100644
--- a/src/xmpp/biboumi_adhoc_commands.cpp
+++ b/src/xmpp/biboumi_adhoc_commands.cpp
@@ -7,6 +7,7 @@
#include <utils/split.hpp>
#include <xmpp/jid.hpp>
#include <algorithm>
+#include <sstream>
#include <iomanip>
#include <biboumi.h>
@@ -25,40 +26,31 @@ void DisconnectUserStep1(XmppComponent& xmpp_component, AdhocSession&, XmlNode&
{
auto& biboumi_component = static_cast<BiboumiComponent&>(xmpp_component);
- XmlNode x("jabber:x:data:x");
+ XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
- XmlNode title("title");
+ XmlSubNode title(x, "title");
title.set_inner("Disconnect a user from the gateway");
- x.add_child(std::move(title));
- XmlNode instructions("instructions");
+ XmlSubNode instructions(x, "instructions");
instructions.set_inner("Choose a user JID and a quit message");
- x.add_child(std::move(instructions));
- XmlNode jids_field("field");
+ XmlSubNode jids_field(x, "field");
jids_field["var"] = "jids";
jids_field["type"] = "list-multi";
jids_field["label"] = "The JIDs to disconnect";
- XmlNode required("required");
- jids_field.add_child(std::move(required));
+ XmlSubNode required(jids_field, "required");
for (Bridge* bridge: biboumi_component.get_bridges())
{
- XmlNode option("option");
+ XmlSubNode option(jids_field, "option");
option["label"] = bridge->get_jid();
- XmlNode value("value");
+ XmlSubNode value(option, "value");
value.set_inner(bridge->get_jid());
- option.add_child(std::move(value));
- jids_field.add_child(std::move(option));
}
- x.add_child(std::move(jids_field));
- XmlNode message_field("field");
+ XmlSubNode message_field(x, "field");
message_field["var"] = "quit-message";
message_field["type"] = "text-single";
message_field["label"] = "Quit message";
- XmlNode message_value("value");
+ XmlSubNode message_value(message_field, "value");
message_value.set_inner("Disconnected by admin");
- message_field.add_child(std::move(message_value));
- x.add_child(std::move(message_field));
- command_node.add_child(std::move(x));
}
void DisconnectUserStep2(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node)
@@ -97,7 +89,7 @@ void DisconnectUserStep2(XmppComponent& xmpp_component, AdhocSession& session, X
}
command_node.delete_all_children();
- XmlNode note("note");
+ XmlSubNode note(command_node, "note");
note["type"] = "info";
if (num == 0)
note.set_inner("No user were disconnected.");
@@ -105,15 +97,12 @@ void DisconnectUserStep2(XmppComponent& xmpp_component, AdhocSession& session, X
note.set_inner("1 user has been disconnected.");
else
note.set_inner(std::to_string(num) + " users have been disconnected.");
- command_node.add_child(std::move(note));
return;
}
}
- XmlNode error(ADHOC_NS":error");
+ XmlSubNode error(command_node, ADHOC_NS":error");
error["type"] = "modify";
- XmlNode condition(STANZA_NS":bad-request");
- error.add_child(std::move(condition));
- command_node.add_child(std::move(error));
+ XmlSubNode condition(error, STANZA_NS":bad-request");
session.terminate();
}
@@ -126,43 +115,38 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman
auto options = Database::get_global_options(owner.bare());
- XmlNode x("jabber:x:data:x");
+ XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
- XmlNode title("title");
+ XmlSubNode title(x, "title");
title.set_inner("Configure some global default settings.");
- x.add_child(std::move(title));
- XmlNode instructions("instructions");
+ XmlSubNode instructions(x, "instructions");
instructions.set_inner("Edit the form, to configure your global settings for the component.");
- x.add_child(std::move(instructions));
-
- XmlNode required("required");
- XmlNode max_histo_length("field");
+ XmlSubNode max_histo_length(x, "field");
max_histo_length["var"] = "max_history_length";
max_histo_length["type"] = "text-single";
max_histo_length["label"] = "Max history length";
max_histo_length["desc"] = "The maximum number of lines in the history that the server sends when joining a channel";
- XmlNode value("value");
- value.set_inner(std::to_string(options.maxHistoryLength.value()));
- max_histo_length.add_child(std::move(value));
- x.add_child(std::move(max_histo_length));
+ {
+ XmlSubNode value(max_histo_length, "value");
+ value.set_inner(std::to_string(options.maxHistoryLength.value()));
+ }
- XmlNode record_history("field");
+ XmlSubNode record_history(x, "field");
record_history["var"] = "record_history";
record_history["type"] = "boolean";
record_history["label"] = "Record history";
record_history["desc"] = "Whether to save the messages into the database, or not";
- value.set_name("value");
- if (options.recordHistory.value())
- value.set_inner("true");
- else
- value.set_inner("false");
- record_history.add_child(std::move(value));
- x.add_child(std::move(record_history));
-
- command_node.add_child(std::move(x));
+ {
+ XmlSubNode value(record_history, "value");
+ value.set_name("value");
+ if (options.recordHistory.value())
+ value.set_inner("true");
+ else
+ value.set_inner("false");
+ }
}
void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node)
@@ -194,17 +178,14 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session,
options.update();
command_node.delete_all_children();
- XmlNode note("note");
+ XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner("Configuration successfully applied.");
- command_node.add_child(std::move(note));
return;
}
- XmlNode error(ADHOC_NS":error");
+ XmlSubNode error(command_node, ADHOC_NS":error");
error["type"] = "modify";
- XmlNode condition(STANZA_NS":bad-request");
- error.add_child(std::move(condition));
- command_node.add_child(std::move(error));
+ XmlSubNode condition(error, STANZA_NS":bad-request");
session.terminate();
}
@@ -218,18 +199,16 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain,
server_domain);
- XmlNode x("jabber:x:data:x");
+ XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
- XmlNode title("title");
+ XmlSubNode title(x, "title");
title.set_inner("Configure the IRC server "s + server_domain);
- x.add_child(std::move(title));
- XmlNode instructions("instructions");
+ XmlSubNode instructions(x, "instructions");
instructions.set_inner("Edit the form, to configure the settings of the IRC server "s + server_domain);
- x.add_child(std::move(instructions));
XmlNode required("required");
- XmlNode ports("field");
+ XmlSubNode ports(x, "field");
ports["var"] = "ports";
ports["type"] = "text-multi";
ports["label"] = "Ports";
@@ -237,15 +216,13 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
auto vals = utils::split(options.ports.value(), ';', false);
for (const auto& val: vals)
{
- XmlNode ports_value("value");
+ XmlSubNode ports_value(ports, "value");
ports_value.set_inner(val);
- ports.add_child(std::move(ports_value));
}
ports.add_child(required);
- x.add_child(std::move(ports));
#ifdef BOTAN_FOUND
- XmlNode tls_ports("field");
+ XmlSubNode tls_ports(x, "field");
tls_ports["var"] = "tls_ports";
tls_ports["type"] = "text-multi";
tls_ports["label"] = "TLS ports";
@@ -253,126 +230,116 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
vals = utils::split(options.tlsPorts.value(), ';', false);
for (const auto& val: vals)
{
- XmlNode tls_ports_value("value");
+ XmlSubNode tls_ports_value(tls_ports, "value");
tls_ports_value.set_inner(val);
- tls_ports.add_child(std::move(tls_ports_value));
}
tls_ports.add_child(required);
- x.add_child(std::move(tls_ports));
- XmlNode verify_cert("field");
+ XmlSubNode verify_cert(x, "field");
verify_cert["var"] = "verify_cert";
verify_cert["type"] = "boolean";
verify_cert["label"] = "Verify certificate";
verify_cert["desc"] = "Whether or not to abort the connection if the server’s TLS certificate is invalid";
- XmlNode verify_cert_value("value");
+ XmlSubNode verify_cert_value(verify_cert, "value");
if (options.verifyCert.value())
verify_cert_value.set_inner("true");
else
verify_cert_value.set_inner("false");
- verify_cert.add_child(std::move(verify_cert_value));
- x.add_child(std::move(verify_cert));
- XmlNode fingerprint("field");
+ XmlSubNode fingerprint(x, "field");
fingerprint["var"] = "fingerprint";
fingerprint["type"] = "text-single";
fingerprint["label"] = "SHA-1 fingerprint of the TLS certificate to trust.";
if (!options.trustedFingerprint.value().empty())
{
- XmlNode fingerprint_value("value");
+ XmlSubNode fingerprint_value(fingerprint, "value");
fingerprint_value.set_inner(options.trustedFingerprint.value());
- fingerprint.add_child(std::move(fingerprint_value));
}
fingerprint.add_child(required);
- x.add_child(std::move(fingerprint));
#endif
- XmlNode pass("field");
+ XmlSubNode pass(x, "field");
pass["var"] = "pass";
pass["type"] = "text-private";
pass["label"] = "Server password (to be used in a PASS command when connecting)";
if (!options.pass.value().empty())
{
- XmlNode pass_value("value");
+ XmlSubNode pass_value(pass, "value");
pass_value.set_inner(options.pass.value());
- pass.add_child(std::move(pass_value));
}
pass.add_child(required);
- x.add_child(std::move(pass));
- XmlNode after_cnt_cmd("field");
+ XmlSubNode after_cnt_cmd(x, "field");
after_cnt_cmd["var"] = "after_connect_command";
after_cnt_cmd["type"] = "text-single";
after_cnt_cmd["desc"] = "Custom IRC command sent after the connection is established with the server.";
after_cnt_cmd["label"] = "After-connection IRC command";
if (!options.afterConnectionCommand.value().empty())
{
- XmlNode after_cnt_cmd_value("value");
+ XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value");
after_cnt_cmd_value.set_inner(options.afterConnectionCommand.value());
- after_cnt_cmd.add_child(std::move(after_cnt_cmd_value));
}
after_cnt_cmd.add_child(required);
- x.add_child(std::move(after_cnt_cmd));
if (Config::get("realname_customization", "true") == "true")
{
- XmlNode username("field");
+ XmlSubNode username(x, "field");
username["var"] = "username";
username["type"] = "text-single";
username["label"] = "Username";
if (!options.username.value().empty())
{
- XmlNode username_value("value");
+ XmlSubNode username_value(username, "value");
username_value.set_inner(options.username.value());
- username.add_child(std::move(username_value));
}
username.add_child(required);
- x.add_child(std::move(username));
- XmlNode realname("field");
+ XmlSubNode realname(x, "field");
realname["var"] = "realname";
realname["type"] = "text-single";
realname["label"] = "Realname";
if (!options.realname.value().empty())
{
- XmlNode realname_value("value");
+ XmlSubNode realname_value(realname, "value");
realname_value.set_inner(options.realname.value());
- realname.add_child(std::move(realname_value));
}
realname.add_child(required);
- x.add_child(std::move(realname));
}
- XmlNode encoding_out("field");
+ XmlSubNode encoding_out(x, "field");
encoding_out["var"] = "encoding_out";
encoding_out["type"] = "text-single";
encoding_out["desc"] = "The encoding used when sending messages to the IRC server.";
encoding_out["label"] = "Out encoding";
if (!options.encodingOut.value().empty())
{
- XmlNode encoding_out_value("value");
+ XmlSubNode encoding_out_value(encoding_out, "value");
encoding_out_value.set_inner(options.encodingOut.value());
- encoding_out.add_child(std::move(encoding_out_value));
}
encoding_out.add_child(required);
- x.add_child(std::move(encoding_out));
- XmlNode encoding_in("field");
+ XmlSubNode encoding_in(x, "field");
encoding_in["var"] = "encoding_in";
encoding_in["type"] = "text-single";
encoding_in["desc"] = "The encoding used to decode message received from the IRC server.";
encoding_in["label"] = "In encoding";
if (!options.encodingIn.value().empty())
{
- XmlNode encoding_in_value("value");
+ XmlSubNode encoding_in_value(encoding_in, "value");
encoding_in_value.set_inner(options.encodingIn.value());
- encoding_in.add_child(std::move(encoding_in_value));
}
encoding_in.add_child(required);
- x.add_child(std::move(encoding_in));
-
- command_node.add_child(std::move(x));
+ XmlSubNode linger_time(x, "field");
+ linger_time["var"] = "linger_time";
+ linger_time["type"] = "text-single";
+ linger_time["desc"] = "The number of seconds to wait before sending a QUIT command, after the last channel on that server has been left.";
+ linger_time["label"] = "Linger time";
+ {
+ XmlSubNode linger_time_value(linger_time, "value");
+ linger_time_value.set_inner(std::to_string(options.lingerTime.value()));
+ }
+ encoding_in.add_child(required);
}
void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
@@ -452,22 +419,23 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
value && !value->get_inner().empty())
options.encodingIn = value->get_inner();
+ else if (field->get_tag("var") == "linger_time" &&
+ value && !value->get_inner().empty())
+ options.lingerTime = value->get_inner();
+
}
options.update();
command_node.delete_all_children();
- XmlNode note("note");
+ XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner("Configuration successfully applied.");
- command_node.add_child(std::move(note));
return;
}
- XmlNode error(ADHOC_NS":error");
+ XmlSubNode error(command_node, ADHOC_NS":error");
error["type"] = "modify";
- XmlNode condition(STANZA_NS":bad-request");
- error.add_child(std::move(condition));
- command_node.add_child(std::move(error));
+ XmlSubNode condition(error, STANZA_NS":bad-request");
session.terminate();
}
@@ -479,46 +447,38 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co
auto options = Database::get_irc_channel_options_with_server_default(owner.local + "@" + owner.domain,
iid.get_server(), iid.get_local());
- XmlNode x("jabber:x:data:x");
+ XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
- XmlNode title("title");
+ XmlSubNode title(x, "title");
title.set_inner("Configure the IRC channel "s + iid.get_local() + " on server "s + iid.get_server());
- x.add_child(std::move(title));
- XmlNode instructions("instructions");
+ XmlSubNode instructions(x, "instructions");
instructions.set_inner("Edit the form, to configure the settings of the IRC channel "s + iid.get_local());
- x.add_child(std::move(instructions));
XmlNode required("required");
- XmlNode encoding_out("field");
+ XmlSubNode encoding_out(x, "field");
encoding_out["var"] = "encoding_out";
encoding_out["type"] = "text-single";
encoding_out["desc"] = "The encoding used when sending messages to the IRC server. Defaults to the server's “out encoding” if unset for the channel";
encoding_out["label"] = "Out encoding";
if (!options.encodingOut.value().empty())
{
- XmlNode encoding_out_value("value");
+ XmlSubNode encoding_out_value(encoding_out, "value");
encoding_out_value.set_inner(options.encodingOut.value());
- encoding_out.add_child(std::move(encoding_out_value));
}
encoding_out.add_child(required);
- x.add_child(std::move(encoding_out));
- XmlNode encoding_in("field");
+ XmlSubNode encoding_in(x, "field");
encoding_in["var"] = "encoding_in";
encoding_in["type"] = "text-single";
encoding_in["desc"] = "The encoding used to decode message received from the IRC server. Defaults to the server's “in encoding” if unset for the channel";
encoding_in["label"] = "In encoding";
if (!options.encodingIn.value().empty())
{
- XmlNode encoding_in_value("value");
+ XmlSubNode encoding_in_value(encoding_in, "value");
encoding_in_value.set_inner(options.encodingIn.value());
- encoding_in.add_child(std::move(encoding_in_value));
}
encoding_in.add_child(required);
- x.add_child(std::move(encoding_in));
-
- command_node.add_child(std::move(x));
}
void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
@@ -547,17 +507,14 @@ void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& co
options.update();
command_node.delete_all_children();
- XmlNode note("note");
+ XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner("Configuration successfully applied.");
- command_node.add_child(std::move(note));
return;
}
- XmlNode error(ADHOC_NS":error");
+ XmlSubNode error(command_node, ADHOC_NS":error");
error["type"] = "modify";
- XmlNode condition(STANZA_NS":bad-request");
- error.add_child(std::move(condition));
- command_node.add_child(std::move(error));
+ XmlSubNode condition(error, STANZA_NS":bad-request");
session.terminate();
}
#endif // USE_DATABASE
@@ -575,31 +532,24 @@ void DisconnectUserFromServerStep1(XmppComponent& xmpp_component, AdhocSession&
{ // Send a form to select the user to disconnect
auto& biboumi_component = static_cast<BiboumiComponent&>(xmpp_component);
- XmlNode x("jabber:x:data:x");
+ XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
- XmlNode title("title");
+ XmlSubNode title(x, "title");
title.set_inner("Disconnect a user from selected IRC servers");
- x.add_child(std::move(title));
- XmlNode instructions("instructions");
+ XmlSubNode instructions(x, "instructions");
instructions.set_inner("Choose a user JID");
- x.add_child(std::move(instructions));
- XmlNode jids_field("field");
+ XmlSubNode jids_field(x, "field");
jids_field["var"] = "jid";
jids_field["type"] = "list-single";
jids_field["label"] = "The JID to disconnect";
- XmlNode required("required");
- jids_field.add_child(std::move(required));
+ XmlSubNode required(jids_field, "required");
for (Bridge* bridge: biboumi_component.get_bridges())
{
- XmlNode option("option");
+ XmlSubNode option(jids_field, "option");
option["label"] = bridge->get_jid();
- XmlNode value("value");
+ XmlSubNode value(option, "value");
value.set_inner(bridge->get_jid());
- option.add_child(std::move(value));
- jids_field.add_child(std::move(option));
}
- x.add_child(std::move(jids_field));
- command_node.add_child(std::move(x));
}
}
@@ -627,53 +577,42 @@ void DisconnectUserFromServerStep2(XmppComponent& xmpp_component, AdhocSession&
command_node.delete_all_children();
auto& biboumi_component = static_cast<BiboumiComponent&>(xmpp_component);
- XmlNode x("jabber:x:data:x");
+ XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
- XmlNode title("title");
+ XmlSubNode title(x, "title");
title.set_inner("Disconnect a user from selected IRC servers");
- x.add_child(std::move(title));
- XmlNode instructions("instructions");
+ XmlSubNode instructions(x, "instructions");
instructions.set_inner("Choose one or more servers to disconnect this JID from");
- x.add_child(std::move(instructions));
- XmlNode jids_field("field");
+ XmlSubNode jids_field(x, "field");
jids_field["var"] = "irc-servers";
jids_field["type"] = "list-multi";
jids_field["label"] = "The servers to disconnect from";
- XmlNode required("required");
- jids_field.add_child(std::move(required));
+ XmlSubNode required(jids_field, "required");
Bridge* bridge = biboumi_component.find_user_bridge(jid_to_disconnect);
if (!bridge || bridge->get_irc_clients().empty())
{
- XmlNode note("note");
+ XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner("User "s + jid_to_disconnect + " is not connected to any IRC server.");
- command_node.add_child(std::move(note));
session.terminate();
return ;
}
for (const auto& pair: bridge->get_irc_clients())
{
- XmlNode option("option");
+ XmlSubNode option(jids_field, "option");
option["label"] = pair.first;
- XmlNode value("value");
+ XmlSubNode value(option, "value");
value.set_inner(pair.first);
- option.add_child(std::move(value));
- jids_field.add_child(std::move(option));
}
- x.add_child(std::move(jids_field));
- XmlNode message_field("field");
+ XmlSubNode message_field(x, "field");
message_field["var"] = "quit-message";
message_field["type"] = "text-single";
message_field["label"] = "Quit message";
- XmlNode message_value("value");
+ XmlSubNode message_value(message_field, "value");
message_value.set_inner("Killed by admin");
- message_field.add_child(std::move(message_value));
- x.add_child(std::move(message_field));
-
- command_node.add_child(std::move(x));
}
void DisconnectUserFromServerStep3(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node)
@@ -718,14 +657,13 @@ void DisconnectUserFromServerStep3(XmppComponent& xmpp_component, AdhocSession&
}
}
command_node.delete_all_children();
- XmlNode note("note");
+ XmlSubNode note(command_node, "note");
note["type"] = "info";
std::string msg = jid_to_disconnect + " was disconnected from " + std::to_string(number) + " IRC server";
if (number > 1)
msg += "s";
msg += ".";
note.set_inner(msg);
- command_node.add_child(std::move(note));
}
void GetIrcConnectionInfoStep1(XmppComponent& component, AdhocSession& session, XmlNode& command_node)
@@ -741,10 +679,9 @@ void GetIrcConnectionInfoStep1(XmppComponent& component, AdhocSession& session,
utils::ScopeGuard sg([&message, &command_node]()
{
command_node.delete_all_children();
- XmlNode note("note");
+ XmlSubNode note(command_node, "note");
note["type"] = "info";
note.set_inner(message);
- command_node.add_child(std::move(note));
});
Bridge* bridge = biboumi_component.get_user_bridge(owner.bare());
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index d6782e2..bd6975e 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -8,7 +8,6 @@
#include <xmpp/biboumi_adhoc_commands.hpp>
#include <bridge/list_element.hpp>
#include <config/config.hpp>
-#include <utils/sha1.hpp>
#include <utils/time.hpp>
#include <xmpp/jid.hpp>
@@ -137,7 +136,7 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
// stanza_error.disable() call at the end of the function.
std::string error_type("cancel");
std::string error_name("internal-server-error");
- utils::ScopeGuard stanza_error([&](){
+ utils::ScopeGuard stanza_error([this, &from_str, &to_str, &id, &error_type, &error_name](){
this->send_stanza_error("presence", from_str, to_str, id,
error_type, error_name, "");
});
@@ -150,7 +149,7 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
{
const std::string own_nick = bridge->get_own_nick(iid);
if (!own_nick.empty() && own_nick != to.resource)
- bridge->send_irc_nick_change(iid, to.resource);
+ bridge->send_irc_nick_change(iid, to.resource, from.resource);
const XmlNode* x = stanza.get_child("x", MUC_NS);
const XmlNode* password = x ? x->get_child("password", MUC_NS): nullptr;
bridge->join_irc_channel(iid, to.resource, password ? password->get_inner(): "",
@@ -162,6 +161,15 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
bridge->leave_irc_channel(std::move(iid), status ? status->get_inner() : "", from.resource);
}
}
+ else if (iid.type == Iid::Type::Server || iid.type == Iid::Type::None)
+ {
+ if (type == "subscribe")
+ { // Auto-accept any subscription request for an IRC server
+ this->accept_subscription(to_str, from.bare());
+ this->ask_subscription(to_str, from.bare());
+ }
+
+ }
else
{
// A user wants to join an invalid IRC channel, return a presence error to him/her
@@ -197,7 +205,7 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
std::string error_type("cancel");
std::string error_name("internal-server-error");
- utils::ScopeGuard stanza_error([&](){
+ utils::ScopeGuard stanza_error([this, &from_str, &to_str, &id, &error_type, &error_name](){
this->send_stanza_error("message", from_str, to_str, id,
error_type, error_name, "");
});
@@ -280,7 +288,7 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
}
// We MUST return an iq, whatever happens, except if the type is
-// "result".
+// "result" or "error".
// To do this, we use a scopeguard. If an exception is raised somewhere, an
// iq of type error "internal-server-error" is sent. If we handle the
// request properly (by calling a function that registers an iq to be sent
@@ -316,7 +324,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
// the scopeguard.
std::string error_type("cancel");
std::string error_name("internal-server-error");
- utils::ScopeGuard stanza_error([&](){
+ utils::ScopeGuard stanza_error([this, &from, &to_str, &id, &error_type, &error_name](){
this->send_stanza_error("iq", from, to_str, id,
error_type, error_name, "");
});
@@ -344,7 +352,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
bridge->send_irc_kick(iid, nick, reason, id, from);
}
else
- bridge->forward_affiliation_role_change(iid, nick, affiliation, role);
+ bridge->forward_affiliation_role_change(iid, from, nick, affiliation, role, id);
stanza_error.disable();
}
}
@@ -548,6 +556,10 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
}
}
}
+ else if (type == "error")
+ {
+ stanza_error.disable();
+ }
}
catch (const IRCNotConnected& ex)
{
@@ -570,13 +582,11 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
Jid to(stanza.get_tag("to"));
const XmlNode* query = stanza.get_child("query", MAM_NS);
- std::string query_id;
- if (query)
- query_id = query->get_tag("queryid");
Iid iid(to.local, {'#', '&'});
- if (iid.type == Iid::Type::Channel && to.resource.empty())
+ if (query && iid.type == Iid::Type::Channel && to.resource.empty())
{
+ const std::string query_id = query->get_tag("queryid");
std::string start;
std::string end;
const XmlNode* x = query->get_child("x", DATAFORM_NS);
@@ -615,39 +625,33 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza)
void BiboumiComponent::send_archived_message(const db::MucLogLine& log_line, const std::string& from, const std::string& to,
const std::string& queryid)
{
- Stanza message("message");
+ Stanza message("message");
+ {
message["from"] = from;
message["to"] = to;
- XmlNode result("result");
+ XmlSubNode result(message, "result");
result["xmlns"] = MAM_NS;
if (!queryid.empty())
result["queryid"] = queryid;
result["id"] = log_line.uuid.value();
- XmlNode forwarded("forwarded");
+ XmlSubNode forwarded(result, "forwarded");
forwarded["xmlns"] = FORWARD_NS;
- XmlNode delay("delay");
+ XmlSubNode delay(forwarded, "delay");
delay["xmlns"] = DELAY_NS;
delay["stamp"] = utils::to_string(log_line.date.value().timeStamp());
- forwarded.add_child(std::move(delay));
-
- XmlNode submessage("message");
+ XmlSubNode submessage(forwarded, "message");
submessage["xmlns"] = CLIENT_NS;
submessage["from"] = from + "/" + log_line.nick.value();
submessage["type"] = "groupchat";
- XmlNode body("body");
+ XmlSubNode body(submessage, "body");
body.set_inner(log_line.body.value());
- submessage.add_child(std::move(body));
-
- forwarded.add_child(std::move(submessage));
- result.add_child(std::move(forwarded));
- message.add_child(std::move(result));
-
- this->send_stanza(message);
+ }
+ this->send_stanza(message);
}
#endif
@@ -689,24 +693,23 @@ std::vector<Bridge*> BiboumiComponent::get_bridges() const
void BiboumiComponent::send_self_disco_info(const std::string& id, const std::string& jid_to)
{
Stanza iq("iq");
- iq["type"] = "result";
- iq["id"] = id;
- iq["to"] = jid_to;
- iq["from"] = this->served_hostname;
- XmlNode query("query");
- query["xmlns"] = DISCO_INFO_NS;
- XmlNode identity("identity");
- identity["category"] = "conference";
- identity["type"] = "irc";
- identity["name"] = "Biboumi XMPP-IRC gateway";
- query.add_child(std::move(identity));
- for (const char* ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS})
- {
- XmlNode feature("feature");
- feature["var"] = ns;
- query.add_child(std::move(feature));
- }
- iq.add_child(std::move(query));
+ {
+ iq["type"] = "result";
+ iq["id"] = id;
+ iq["to"] = jid_to;
+ iq["from"] = this->served_hostname;
+ XmlSubNode query(iq, "query");
+ query["xmlns"] = DISCO_INFO_NS;
+ XmlSubNode identity(query, "identity");
+ identity["category"] = "conference";
+ identity["type"] = "irc";
+ identity["name"] = "Biboumi XMPP-IRC gateway";
+ for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS})
+ {
+ XmlSubNode feature(query, "feature");
+ feature["var"] = ns;
+ }
+ }
this->send_stanza(iq);
}
@@ -714,57 +717,41 @@ void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const s
{
Jid from(jid_from);
Stanza iq("iq");
- iq["type"] = "result";
- iq["id"] = id;
- iq["to"] = jid_to;
- iq["from"] = jid_from;
- XmlNode query("query");
- query["xmlns"] = DISCO_INFO_NS;
- XmlNode identity("identity");
- identity["category"] = "conference";
- identity["type"] = "irc";
- identity["name"] = "IRC server "s + from.local + " over Biboumi";
- query.add_child(std::move(identity));
- for (const char* ns: {DISCO_INFO_NS, ADHOC_NS, PING_NS, VERSION_NS})
- {
- XmlNode feature("feature");
- feature["var"] = ns;
- query.add_child(std::move(feature));
- }
- iq.add_child(std::move(query));
+ {
+ iq["type"] = "result";
+ iq["id"] = id;
+ iq["to"] = jid_to;
+ iq["from"] = jid_from;
+ XmlSubNode query(iq, "query");
+ query["xmlns"] = DISCO_INFO_NS;
+ XmlSubNode identity(query, "identity");
+ identity["category"] = "conference";
+ identity["type"] = "irc";
+ identity["name"] = "IRC server "s + from.local + " over Biboumi";
+ for (const char *ns: {DISCO_INFO_NS, ADHOC_NS, PING_NS, VERSION_NS})
+ {
+ XmlSubNode feature(query, "feature");
+ feature["var"] = ns;
+ }
+ }
this->send_stanza(iq);
}
void BiboumiComponent::send_irc_channel_muc_traffic_info(const std::string id, const std::string& jid_from, const std::string& jid_to)
{
Stanza iq("iq");
- iq["type"] = "result";
- iq["id"] = id;
- iq["from"] = jid_from;
- iq["to"] = jid_to;
-
- XmlNode query("query");
- query["xmlns"] = DISCO_INFO_NS;
- query["node"] = MUC_TRAFFIC_NS;
- // We drop all “special” traffic (like xhtml-im, chatstates, etc), so
- // don’t include any <feature/>
- iq.add_child(std::move(query));
-
- this->send_stanza(iq);
-
-}
-
-void BiboumiComponent::send_iq_version_request(const std::string& from,
- const std::string& jid_to)
-{
- Stanza iq("iq");
- iq["type"] = "get";
- iq["id"] = "version_"s + this->next_id();
- iq["from"] = from + "@" + this->served_hostname;
- iq["to"] = jid_to;
- XmlNode query("query");
- query["xmlns"] = VERSION_NS;
- iq.add_child(std::move(query));
+ {
+ iq["type"] = "result";
+ iq["id"] = id;
+ iq["from"] = jid_from;
+ iq["to"] = jid_to;
+
+ XmlSubNode query(iq, "query");
+ query["xmlns"] = DISCO_INFO_NS;
+ query["node"] = MUC_TRAFFIC_NS;
+ // We drop all “special” traffic (like xhtml-im, chatstates, etc), so
+ // don’t include any <feature/>
+ }
this->send_stanza(iq);
}
@@ -773,13 +760,14 @@ void BiboumiComponent::send_ping_request(const std::string& from,
const std::string& id)
{
Stanza iq("iq");
- iq["type"] = "get";
- iq["id"] = id;
- iq["from"] = from + "@" + this->served_hostname;
- iq["to"] = jid_to;
- XmlNode ping("ping");
- ping["xmlns"] = PING_NS;
- iq.add_child(std::move(ping));
+ {
+ iq["type"] = "get";
+ iq["id"] = id;
+ iq["from"] = from + "@" + this->served_hostname;
+ iq["to"] = jid_to;
+ XmlSubNode ping(iq, "ping");
+ ping["xmlns"] = PING_NS;
+ }
this->send_stanza(iq);
auto result_cb = [from, id](Bridge* bridge, const Stanza& stanza)
@@ -803,48 +791,43 @@ void BiboumiComponent::send_iq_room_list_result(const std::string& id, const std
const ResultSetInfo& rs_info)
{
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;
+ {
+ iq["from"] = from + "@" + this->served_hostname;
+ iq["to"] = to_jid;
+ iq["id"] = id;
+ iq["type"] = "result";
+ XmlSubNode query(iq, "query");
+ query["xmlns"] = DISCO_ITEMS_NS;
for (auto it = begin; it != end; ++it)
- {
- XmlNode item("item");
+ {
+ XmlSubNode item(query, "item");
item["jid"] = it->channel + "@" + this->served_hostname;
- query.add_child(std::move(item));
- }
-
- if ((rs_info.max >= 0 || !rs_info.after.empty() || !rs_info.before.empty()))
- {
- XmlNode set_node("set");
- set_node["xmlns"] = RSM_NS;
+ }
- if (begin != channel_list.channels.cend())
- {
- XmlNode first_node("first");
- first_node["index"] = std::to_string(std::distance(channel_list.channels.cbegin(), begin));
- first_node.set_inner(begin->channel + "@" + this->served_hostname);
- set_node.add_child(std::move(first_node));
- }
- if (end != channel_list.channels.cbegin())
- {
- XmlNode last_node("last");
- last_node.set_inner(std::prev(end)->channel + "@" + this->served_hostname);
- set_node.add_child(std::move(last_node));
- }
- if (channel_list.complete)
- {
- XmlNode count_node("count");
- count_node.set_inner(std::to_string(channel_list.channels.size()));
- set_node.add_child(std::move(count_node));
- }
- query.add_child(std::move(set_node));
- }
+ if ((rs_info.max >= 0 || !rs_info.after.empty() || !rs_info.before.empty()))
+ {
+ XmlSubNode set_node(query, "set");
+ set_node["xmlns"] = RSM_NS;
- iq.add_child(std::move(query));
+ if (begin != channel_list.channels.cend())
+ {
+ XmlSubNode first_node(set_node, "first");
+ first_node["index"] = std::to_string(std::distance(channel_list.channels.cbegin(), begin));
+ first_node.set_inner(begin->channel + "@" + this->served_hostname);
+ }
+ if (end != channel_list.channels.cbegin())
+ {
+ XmlSubNode last_node(set_node, "last");
+ last_node.set_inner(std::prev(end)->channel + "@" + this->served_hostname);
+ }
+ if (channel_list.complete)
+ {
+ XmlSubNode count_node(set_node, "count");
+ count_node.set_inner(std::to_string(channel_list.channels.size()));
+ }
+ }
+ }
this->send_stanza(iq);
}
@@ -853,16 +836,36 @@ void BiboumiComponent::send_invitation(const std::string& room_target,
const std::string& author_nick)
{
Stanza message("message");
- message["from"] = room_target + "@" + this->served_hostname;
- message["to"] = jid_to;
- XmlNode x("x");
- x["xmlns"] = MUC_USER_NS;
- XmlNode invite("invite");
- if (author_nick.empty())
- invite["from"] = room_target + "@" + this->served_hostname;
- else
- invite["from"] = room_target + "@" + this->served_hostname + "/" + author_nick;
- x.add_child(std::move(invite));
- message.add_child(std::move(x));
+ {
+ message["from"] = room_target + "@" + this->served_hostname;
+ message["to"] = jid_to;
+ XmlSubNode x(message, "x");
+ x["xmlns"] = MUC_USER_NS;
+ XmlSubNode invite(x, "invite");
+ if (author_nick.empty())
+ invite["from"] = room_target + "@" + this->served_hostname;
+ else
+ invite["from"] = room_target + "@" + this->served_hostname + "/" + author_nick;
+ }
this->send_stanza(message);
}
+
+void BiboumiComponent::accept_subscription(const std::string& from, const std::string& to)
+{
+ Stanza presence("presence");
+ presence["from"] = from;
+ presence["to"] = to;
+ presence["id"] = this->next_id();
+ presence["type"] = "subscribed";
+ this->send_stanza(presence);
+}
+
+void BiboumiComponent::ask_subscription(const std::string& from, const std::string& to)
+{
+ Stanza presence("presence");
+ presence["from"] = from;
+ presence["to"] = to;
+ presence["id"] = this->next_id();
+ presence["type"] = "subscribe";
+ this->send_stanza(presence);
+}
diff --git a/src/xmpp/biboumi_component.hpp b/src/xmpp/biboumi_component.hpp
index 999001f..7cafdec 100644
--- a/src/xmpp/biboumi_component.hpp
+++ b/src/xmpp/biboumi_component.hpp
@@ -71,11 +71,6 @@ public:
*/
void send_irc_channel_muc_traffic_info(const std::string id, const std::string& jid_from, const std::string& jid_to);
/**
- * Send an iq version request
- */
- void send_iq_version_request(const std::string& from,
- const std::string& jid_to);
- /**
* Send a ping request
*/
void send_ping_request(const std::string& from,
@@ -88,6 +83,8 @@ public:
const ChannelList& channel_list, std::vector<ListElement>::const_iterator begin,
std::vector<ListElement>::const_iterator end, const ResultSetInfo& rs_info);
void send_invitation(const std::string& room_target, const std::string& jid_to, const std::string& author_nick);
+ void accept_subscription(const std::string& from, const std::string& to);
+ void ask_subscription(const std::string& from, const std::string& to);
/**
* Handle the various stanza types
*/