summaryrefslogtreecommitdiff
path: root/src/xmpp
diff options
context:
space:
mode:
authorlouiz’ <louiz@louiz.org>2017-07-28 18:03:16 +0200
committerlouiz’ <louiz@louiz.org>2017-07-28 18:03:16 +0200
commit8c92473a6681aaf671b21780202dde731772cee8 (patch)
tree6ff2ae92dc06ff873c2d0e162f50cc649f3b8198 /src/xmpp
parent76f5fa81f2026770c907bee0e931aae8d8c7a1bd (diff)
parent6187423e6ed834570783ef3097a6ef73cc58107a (diff)
downloadbiboumi-8c92473a6681aaf671b21780202dde731772cee8.tar.gz
biboumi-8c92473a6681aaf671b21780202dde731772cee8.tar.bz2
biboumi-8c92473a6681aaf671b21780202dde731772cee8.tar.xz
biboumi-8c92473a6681aaf671b21780202dde731772cee8.zip
Merge branch 'master' into debian
Diffstat (limited to 'src/xmpp')
-rw-r--r--src/xmpp/adhoc_command.cpp2
-rw-r--r--src/xmpp/adhoc_commands_handler.cpp8
-rw-r--r--src/xmpp/biboumi_adhoc_commands.cpp400
-rw-r--r--src/xmpp/biboumi_component.cpp141
-rw-r--r--src/xmpp/biboumi_component.hpp9
-rw-r--r--src/xmpp/xmpp_component.cpp50
-rw-r--r--src/xmpp/xmpp_component.hpp13
7 files changed, 375 insertions, 248 deletions
diff --git a/src/xmpp/adhoc_command.cpp b/src/xmpp/adhoc_command.cpp
index e02bf35..fbf4ce2 100644
--- a/src/xmpp/adhoc_command.cpp
+++ b/src/xmpp/adhoc_command.cpp
@@ -59,7 +59,7 @@ void HelloStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
command_node.delete_all_children();
XmlSubNode note(command_node, "note");
note["type"] = "info";
- note.set_inner("Hello "s + value_str + "!"s);
+ note.set_inner("Hello " + value_str + "!"s);
return;
}
}
diff --git a/src/xmpp/adhoc_commands_handler.cpp b/src/xmpp/adhoc_commands_handler.cpp
index 040d0ff..e4dcd5c 100644
--- a/src/xmpp/adhoc_commands_handler.cpp
+++ b/src/xmpp/adhoc_commands_handler.cpp
@@ -19,7 +19,7 @@ void AdhocCommandsHandler::add_command(std::string name, AdhocCommand command)
{
const auto found = this->commands.find(name);
if (found != this->commands.end())
- throw std::runtime_error("Trying to add an ad-hoc command that already exist: "s + name);
+ throw std::runtime_error("Trying to add an ad-hoc command that already exist: " + name);
this->commands.emplace(std::make_pair(std::move(name), std::move(command)));
}
@@ -59,7 +59,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co
std::forward_as_tuple(command_it->second, executor_jid, to));
TimedEventsManager::instance().add_event(TimedEvent(std::chrono::steady_clock::now() + 3600s,
std::bind(&AdhocCommandsHandler::remove_session, this, sessionid, executor_jid),
- "adhocsession"s + sessionid + executor_jid));
+ "adhocsession" + sessionid + executor_jid));
}
auto session_it = this->sessions.find(std::make_pair(sessionid, executor_jid));
if ((session_it != this->sessions.end()) &&
@@ -74,7 +74,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co
{
this->sessions.erase(session_it);
command_node["status"] = "completed";
- TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid);
+ TimedEventsManager::instance().cancel("adhocsession" + sessionid + executor_jid);
}
else
{
@@ -87,7 +87,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co
{
this->sessions.erase(session_it);
command_node["status"] = "canceled";
- TimedEventsManager::instance().cancel("adhocsession"s + sessionid + executor_jid);
+ TimedEventsManager::instance().cancel("adhocsession" + sessionid + executor_jid);
}
else // unsupported action
{
diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp
index ad4faf8..60af506 100644
--- a/src/xmpp/biboumi_adhoc_commands.cpp
+++ b/src/xmpp/biboumi_adhoc_commands.cpp
@@ -122,30 +122,48 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman
XmlSubNode instructions(x, "instructions");
instructions.set_inner("Edit the form, to configure your global settings for the component.");
- 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";
-
{
- XmlSubNode value(max_histo_length, "value");
- value.set_inner(std::to_string(options.col<Database::MaxHistoryLength>()));
+ 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";
+ {
+ XmlSubNode value(max_histo_length, "value");
+ value.set_inner(std::to_string(options.col<Database::MaxHistoryLength>()));
+ }
}
- 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";
+ {
+ 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";
+ {
+ XmlSubNode value(record_history, "value");
+ value.set_name("value");
+ if (options.col<Database::RecordHistory>())
+ value.set_inner("true");
+ else
+ value.set_inner("false");
+ }
+ }
{
- XmlSubNode value(record_history, "value");
- value.set_name("value");
- if (options.col<Database::RecordHistory>())
- value.set_inner("true");
- else
- value.set_inner("false");
+ XmlSubNode persistent(x, "field");
+ persistent["var"] = "persistent";
+ persistent["type"] = "boolean";
+ persistent["label"] = "Make all channels persistent";
+ persistent["desc"] = "If true, all channels will be persistent";
+ {
+ XmlSubNode value(persistent, "value");
+ value.set_name("value");
+ if (options.col<Database::Persistent>())
+ value.set_inner("true");
+ else
+ value.set_inner("false");
+ }
}
}
@@ -173,6 +191,9 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session,
if (bridge)
bridge->set_record_history(options.col<Database::RecordHistory>());
}
+ else if (field->get_tag("var") == "persistent" &&
+ value)
+ options.col<Database::Persistent>() = to_bool(value->get_inner());
}
options.save(Database::db);
@@ -202,100 +223,116 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
XmlSubNode x(command_node, "jabber:x:data:x");
x["type"] = "form";
XmlSubNode title(x, "title");
- title.set_inner("Configure the IRC server "s + server_domain);
+ title.set_inner("Configure the IRC server " + server_domain);
XmlSubNode instructions(x, "instructions");
- instructions.set_inner("Edit the form, to configure the settings of the IRC server "s + server_domain);
-
- XmlSubNode ports(x, "field");
- ports["var"] = "ports";
- ports["type"] = "text-multi";
- ports["label"] = "Ports";
- ports["desc"] = "List of ports to try, without TLS. Defaults: 6667.";
- for (const auto& val: utils::split(options.col<Database::Ports>(), ';', false))
- {
- XmlSubNode ports_value(ports, "value");
- ports_value.set_inner(val);
- }
+ instructions.set_inner("Edit the form, to configure the settings of the IRC server " + server_domain);
+
+ {
+ XmlSubNode ports(x, "field");
+ ports["var"] = "ports";
+ ports["type"] = "text-multi";
+ ports["label"] = "Ports";
+ ports["desc"] = "List of ports to try, without TLS. Defaults: 6667.";
+ for (const auto& val: utils::split(options.col<Database::Ports>(), ';', false))
+ {
+ XmlSubNode ports_value(ports, "value");
+ ports_value.set_inner(val);
+ }
+ }
#ifdef BOTAN_FOUND
- XmlSubNode tls_ports(x, "field");
- tls_ports["var"] = "tls_ports";
- tls_ports["type"] = "text-multi";
- tls_ports["label"] = "TLS ports";
- tls_ports["desc"] = "List of ports to try, with TLS. Defaults: 6697, 6670.";
- for (const auto& val: utils::split(options.col<Database::TlsPorts>(), ';', false))
- {
- XmlSubNode tls_ports_value(tls_ports, "value");
- tls_ports_value.set_inner(val);
- }
+ {
+ XmlSubNode tls_ports(x, "field");
+ tls_ports["var"] = "tls_ports";
+ tls_ports["type"] = "text-multi";
+ tls_ports["label"] = "TLS ports";
+ tls_ports["desc"] = "List of ports to try, with TLS. Defaults: 6697, 6670.";
+ for (const auto& val: utils::split(options.col<Database::TlsPorts>(), ';', false))
+ {
+ XmlSubNode tls_ports_value(tls_ports, "value");
+ tls_ports_value.set_inner(val);
+ }
+ }
- 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";
- XmlSubNode verify_cert_value(verify_cert, "value");
- if (options.col<Database::VerifyCert>())
- verify_cert_value.set_inner("true");
- else
- verify_cert_value.set_inner("false");
+ {
+ 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";
+ XmlSubNode verify_cert_value(verify_cert, "value");
+ if (options.col<Database::VerifyCert>())
+ verify_cert_value.set_inner("true");
+ else
+ verify_cert_value.set_inner("false");
+ }
- XmlSubNode fingerprint(x, "field");
- fingerprint["var"] = "fingerprint";
- fingerprint["type"] = "text-single";
- fingerprint["label"] = "SHA-1 fingerprint of the TLS certificate to trust.";
- if (!options.col<Database::TrustedFingerprint>().empty())
- {
- XmlSubNode fingerprint_value(fingerprint, "value");
- fingerprint_value.set_inner(options.col<Database::TrustedFingerprint>());
- }
+ {
+ XmlSubNode fingerprint(x, "field");
+ fingerprint["var"] = "fingerprint";
+ fingerprint["type"] = "text-single";
+ fingerprint["label"] = "SHA-1 fingerprint of the TLS certificate to trust.";
+ if (!options.col<Database::TrustedFingerprint>().empty())
+ {
+ XmlSubNode fingerprint_value(fingerprint, "value");
+ fingerprint_value.set_inner(options.col<Database::TrustedFingerprint>());
+ }
+ }
#endif
+ {
+ XmlSubNode pass(x, "field");
+ pass["var"] = "pass";
+ pass["type"] = "text-private";
+ pass["label"] = "Server password";
+ pass["desc"] = "Will be used in a PASS command when connecting";
+ if (!options.col<Database::Pass>().empty())
+ {
+ XmlSubNode pass_value(pass, "value");
+ pass_value.set_inner(options.col<Database::Pass>());
+ }
+ }
- XmlSubNode pass(x, "field");
- pass["var"] = "pass";
- pass["type"] = "text-private";
- pass["label"] = "Server password";
- pass["desc"] = "Will be used in a PASS command when connecting";
- if (!options.col<Database::Pass>().empty())
- {
- XmlSubNode pass_value(pass, "value");
- pass_value.set_inner(options.col<Database::Pass>());
- }
-
- 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.col<Database::AfterConnectionCommand>().empty())
- {
- XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value");
- after_cnt_cmd_value.set_inner(options.col<Database::AfterConnectionCommand>());
- }
+ {
+ 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.col<Database::AfterConnectionCommand>().empty())
+ {
+ XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value");
+ after_cnt_cmd_value.set_inner(options.col<Database::AfterConnectionCommand>());
+ }
+ }
if (Config::get("realname_customization", "true") == "true")
{
- XmlSubNode username(x, "field");
- username["var"] = "username";
- username["type"] = "text-single";
- username["label"] = "Username";
- if (!options.col<Database::Username>().empty())
- {
- XmlSubNode username_value(username, "value");
- username_value.set_inner(options.col<Database::Username>());
- }
-
- XmlSubNode realname(x, "field");
- realname["var"] = "realname";
- realname["type"] = "text-single";
- realname["label"] = "Realname";
- if (!options.col<Database::Realname>().empty())
- {
- XmlSubNode realname_value(realname, "value");
- realname_value.set_inner(options.col<Database::Realname>());
- }
+ {
+ XmlSubNode username(x, "field");
+ username["var"] = "username";
+ username["type"] = "text-single";
+ username["label"] = "Username";
+ if (!options.col<Database::Username>().empty())
+ {
+ XmlSubNode username_value(username, "value");
+ username_value.set_inner(options.col<Database::Username>());
+ }
+ }
+
+ {
+ XmlSubNode realname(x, "field");
+ realname["var"] = "realname";
+ realname["type"] = "text-single";
+ realname["label"] = "Realname";
+ if (!options.col<Database::Realname>().empty())
+ {
+ XmlSubNode realname_value(realname, "value");
+ realname_value.set_inner(options.col<Database::Realname>());
+ }
+ }
}
+ {
XmlSubNode encoding_out(x, "field");
encoding_out["var"] = "encoding_out";
encoding_out["type"] = "text-single";
@@ -306,17 +343,20 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
XmlSubNode encoding_out_value(encoding_out, "value");
encoding_out_value.set_inner(options.col<Database::EncodingOut>());
}
+ }
- 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.col<Database::EncodingIn>().empty())
- {
- XmlSubNode encoding_in_value(encoding_in, "value");
- encoding_in_value.set_inner(options.col<Database::EncodingIn>());
- }
+ {
+ 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.col<Database::EncodingIn>().empty())
+ {
+ XmlSubNode encoding_in_value(encoding_in, "value");
+ encoding_in_value.set_inner(options.col<Database::EncodingIn>());
+ }
+ }
}
void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
@@ -359,24 +399,20 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
options.col<Database::VerifyCert>() = val;
}
- else if (field->get_tag("var") == "fingerprint" && value &&
- !value->get_inner().empty())
+ else if (field->get_tag("var") == "fingerprint" && value)
{
options.col<Database::TrustedFingerprint>() = value->get_inner();
}
#endif // BOTAN_FOUND
- else if (field->get_tag("var") == "pass" &&
- value && !value->get_inner().empty())
+ else if (field->get_tag("var") == "pass" && value)
options.col<Database::Pass>() = value->get_inner();
- else if (field->get_tag("var") == "after_connect_command" &&
- value && !value->get_inner().empty())
+ else if (field->get_tag("var") == "after_connect_command")
options.col<Database::AfterConnectionCommand>() = value->get_inner();
- else if (field->get_tag("var") == "username" &&
- value && !value->get_inner().empty())
+ else if (field->get_tag("var") == "username" && value)
{
auto username = value->get_inner();
// The username must not contain spaces
@@ -384,16 +420,13 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
options.col<Database::Username>() = username;
}
- else if (field->get_tag("var") == "realname" &&
- value && !value->get_inner().empty())
+ else if (field->get_tag("var") == "realname" && value)
options.col<Database::Realname>() = value->get_inner();
- else if (field->get_tag("var") == "encoding_out" &&
- value && !value->get_inner().empty())
+ else if (field->get_tag("var") == "encoding_out" && value)
options.col<Database::EncodingOut>() = value->get_inner();
- else if (field->get_tag("var") == "encoding_in" &&
- value && !value->get_inner().empty())
+ else if (field->get_tag("var") == "encoding_in" && value)
options.col<Database::EncodingIn>() = value->get_inner();
}
@@ -426,68 +459,74 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester,
auto options = Database::get_irc_channel_options_with_server_default(requester.local + "@" + requester.domain,
iid.get_server(), iid.get_local());
-
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());
+ title.set_inner("Configure the IRC channel " + iid.get_local() + " on server " + iid.get_server());
XmlSubNode instructions(x, "instructions");
- instructions.set_inner("Edit the form, to configure the settings of the IRC channel "s + iid.get_local());
-
- XmlSubNode record_history(x, "field");
- record_history["var"] = "record_history";
- record_history["type"] = "list-single";
- record_history["label"] = "Record history for this channel";
- record_history["desc"] = "If unset, the value is the one configured globally";
+ instructions.set_inner("Edit the form, to configure the settings of the IRC channel " + iid.get_local());
{
- // Value selected by default
- XmlSubNode value(record_history, "value");
- value.set_inner(options.col<Database::RecordHistoryOptional>().to_string());
+ XmlSubNode record_history(x, "field");
+ record_history["var"] = "record_history";
+ record_history["type"] = "list-single";
+ record_history["label"] = "Record history for this channel";
+ record_history["desc"] = "If unset, the value is the one configured globally";
+ {
+ // Value selected by default
+ XmlSubNode value(record_history, "value");
+ value.set_inner(options.col<Database::RecordHistoryOptional>().to_string());
+ }
+ // All three possible values
+ for (const auto& val: {"unset", "true", "false"})
+ {
+ XmlSubNode option(record_history, "option");
+ option["label"] = val;
+ XmlSubNode value(option, "value");
+ value.set_inner(val);
+ }
}
- // All three possible values
- for (const auto& val: {"unset", "true", "false"})
+
{
- XmlSubNode option(record_history, "option");
- option["label"] = val;
- XmlSubNode value(option, "value");
- value.set_inner(val);
+ 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.col<Database::EncodingOut>().empty())
+ {
+ XmlSubNode encoding_out_value(encoding_out, "value");
+ encoding_out_value.set_inner(options.col<Database::EncodingOut>());
+ }
}
- 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.col<Database::EncodingOut>().empty())
- {
- XmlSubNode encoding_out_value(encoding_out, "value");
- encoding_out_value.set_inner(options.col<Database::EncodingOut>());
- }
+ {
+ 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.col<Database::EncodingIn>().empty())
+ {
+ XmlSubNode encoding_in_value(encoding_in, "value");
+ encoding_in_value.set_inner(options.col<Database::EncodingIn>());
+ }
+ }
- 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.col<Database::EncodingIn>().empty())
+ {
+ XmlSubNode persistent(x, "field");
+ persistent["var"] = "persistent";
+ persistent["type"] = "boolean";
+ persistent["desc"] = "If set to true, when all XMPP clients have left this channel, biboumi will stay idle in it, without sending a PART command.";
+ persistent["label"] = "Persistent";
{
- XmlSubNode encoding_in_value(encoding_in, "value");
- encoding_in_value.set_inner(options.col<Database::EncodingIn>());
+ XmlSubNode value(persistent, "value");
+ value.set_name("value");
+ if (options.col<Database::Persistent>())
+ value.set_inner("true");
+ else
+ value.set_inner("false");
}
-
- XmlSubNode persistent(x, "field");
- persistent["var"] = "persistent";
- persistent["type"] = "boolean";
- persistent["desc"] = "If set to true, when all XMPP clients have left this channel, biboumi will stay idle in it, without sending a PART command.";
- persistent["label"] = "Persistent";
- {
- XmlSubNode value(persistent, "value");
- value.set_name("value");
- if (options.col<Database::Persistent>())
- value.set_inner("true");
- else
- value.set_inner("false");
}
}
@@ -526,16 +565,13 @@ bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const
{
const XmlNode *value = field->get_child("value", "jabber:x:data");
- if (field->get_tag("var") == "encoding_out" &&
- value && !value->get_inner().empty())
+ if (field->get_tag("var") == "encoding_out" && value)
options.col<Database::EncodingOut>() = value->get_inner();
- else if (field->get_tag("var") == "encoding_in" &&
- value && !value->get_inner().empty())
+ else if (field->get_tag("var") == "encoding_in" && value)
options.col<Database::EncodingIn>() = value->get_inner();
- else if (field->get_tag("var") == "persistent" &&
- value)
+ else if (field->get_tag("var") == "persistent" && value)
options.col<Database::Persistent>() = to_bool(value->get_inner());
else if (field->get_tag("var") == "record_history" &&
value && !value->get_inner().empty())
@@ -647,7 +683,7 @@ void DisconnectUserFromServerStep2(XmppComponent& xmpp_component, AdhocSession&
{
XmlSubNode note(command_node, "note");
note["type"] = "info";
- note.set_inner("User "s + jid_to_disconnect + " is not connected to any IRC server.");
+ note.set_inner("User " + jid_to_disconnect + " is not connected to any IRC server.");
session.terminate();
return ;
}
@@ -751,7 +787,7 @@ void GetIrcConnectionInfoStep1(XmppComponent& component, AdhocSession& session,
IrcClient* irc = bridge->find_irc_client(hostname);
if (!irc || !irc->is_connected())
{
- message = "You are not connected to the IRC server "s + hostname;
+ message = "You are not connected to the IRC server " + hostname;
return;
}
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index 32f3968..0e1d270 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -83,6 +83,14 @@ void BiboumiComponent::shutdown()
{
for (auto& pair: this->bridges)
pair.second->shutdown("Gateway shutdown");
+#ifdef USE_DATABASE
+ for (const Database::RosterItem& roster_item: Database::get_full_roster())
+ {
+ this->send_presence_to_contact(roster_item.col<Database::LocalJid>(),
+ roster_item.col<Database::RemoteJid>(),
+ "unavailable");
+ }
+#endif
}
void BiboumiComponent::clean()
@@ -160,16 +168,50 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
{
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());
+ this->send_presence_to_contact(to_str, from.bare(), "subscribed", id);
+ if (iid.type == Iid::Type::None || bridge->find_irc_client(iid.get_server()))
+ this->send_presence_to_contact(to_str, from.bare(), "");
+ this->send_presence_to_contact(to_str, from.bare(), "subscribe");
+#ifdef USE_DATABASE
+ if (!Database::has_roster_item(to_str, from.bare()))
+ Database::add_roster_item(to_str, from.bare());
+#endif
+ }
+ else if (type == "unsubscribe")
+ {
+ this->send_presence_to_contact(to_str, from.bare(), "unavailable", id);
+ this->send_presence_to_contact(to_str, from.bare(), "unsubscribed");
+ this->send_presence_to_contact(to_str, from.bare(), "unsubscribe");
+#ifdef USE_DATABASE
+ const bool res = Database::has_roster_item(to_str, from.bare());
+ if (res)
+ Database::delete_roster_item(to_str, from.bare());
+#endif
+ }
+ else if (type == "probe")
+ {
+ if ((iid.type == Iid::Type::Server && bridge->find_irc_client(iid.get_server()))
+ || iid.type == Iid::Type::None)
+ {
+#ifdef USE_DATABASE
+ if (Database::has_roster_item(to_str, from.bare()))
+#endif
+ this->send_presence_to_contact(to_str, from.bare(), "");
+#ifdef USE_DATABASE
+ else // rfc 6121 4.3.2.1
+ this->send_presence_to_contact(to_str, from.bare(), "unsubscribed");
+#endif
+ }
+ }
+ else if (type.empty())
+ { // We just receive a presence from someone (as the result of a probe,
+ // or a directed presence, or a normal presence change)
+ if (iid.type == Iid::Type::None)
+ this->send_presence_to_contact(to_str, from.bare(), "");
}
-
}
- else
- {
- // A user wants to join an invalid IRC channel, return a presence error to him/her
- if (type.empty())
- this->send_invalid_room_error(to.local, to.resource, from_str);
+ else if (iid.type == Iid::Type::User)
+ { // Do nothing yet
}
}
catch (const IRCNotConnected& ex)
@@ -177,7 +219,7 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
if (type != "unavailable")
this->send_stanza_error("presence", from_str, to_str, id,
"cancel", "remote-server-not-found",
- "Not connected to IRC server "s + ex.hostname,
+ "Not connected to IRC server " + ex.hostname,
true);
}
stanza_error.disable();
@@ -268,7 +310,11 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
const auto invite_to = invite->get_tag("to");
if (!invite_to.empty())
{
- bridge->send_irc_invitation(iid, invite_to);
+ Jid invited_jid{invite_to};
+ if (invited_jid.domain == this->get_served_hostname() || invited_jid.local.empty())
+ bridge->send_irc_invitation(iid, invite_to);
+ else
+ this->send_invitation_from_fulljid(std::to_string(iid), invite_to, from_str);
}
}
@@ -277,7 +323,7 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
{
this->send_stanza_error("message", from_str, to_str, id,
"cancel", "remote-server-not-found",
- "Not connected to IRC server "s + ex.hostname,
+ "Not connected to IRC server " + ex.hostname,
true);
}
stanza_error.disable();
@@ -586,7 +632,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
{
this->send_stanza_error("iq", from, to_str, id,
"cancel", "remote-server-not-found",
- "Not connected to IRC server "s + ex.hostname,
+ "Not connected to IRC server " + ex.hostname,
true);
stanza_error.disable();
return;
@@ -806,7 +852,7 @@ void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const s
XmlSubNode identity(query, "identity");
identity["category"] = "conference";
identity["type"] = "irc";
- identity["name"] = "IRC server "s + from.local + " over Biboumi";
+ identity["name"] = "IRC server " + from.local + " over Biboumi";
for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS})
{
XmlSubNode feature(query, "feature");
@@ -849,7 +895,7 @@ void BiboumiComponent::send_irc_channel_disco_info(const std::string& id, const
XmlSubNode identity(query, "identity");
identity["category"] = "conference";
identity["type"] = "irc";
- identity["name"] = "IRC channel "s + iid.get_local() + " from server " + iid.get_server() + " over biboumi";
+ identity["name"] = "IRC channel " + iid.get_local() + " from server " + iid.get_server() + " over biboumi";
for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS})
{
XmlSubNode feature(query, "feature");
@@ -945,6 +991,16 @@ void BiboumiComponent::send_invitation(const std::string& room_target,
const std::string& jid_to,
const std::string& author_nick)
{
+ if (author_nick.empty())
+ this->send_invitation_from_fulljid(room_target, jid_to, room_target + "@" + this->served_hostname);
+ else
+ this->send_invitation_from_fulljid(room_target, jid_to, room_target + "@" + this->served_hostname + "/" + author_nick);
+}
+
+void BiboumiComponent::send_invitation_from_fulljid(const std::string& room_target,
+ const std::string& jid_to,
+ const std::string& from)
+{
Stanza message("message");
{
message["from"] = room_target + "@" + this->served_hostname;
@@ -952,10 +1008,7 @@ void BiboumiComponent::send_invitation(const std::string& room_target,
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;
+ invite["from"] = from;
}
this->send_stanza(message);
}
@@ -979,3 +1032,55 @@ void BiboumiComponent::ask_subscription(const std::string& from, const std::stri
presence["type"] = "subscribe";
this->send_stanza(presence);
}
+
+void BiboumiComponent::send_presence_to_contact(const std::string& from, const std::string& to,
+ const std::string& type, const std::string& id)
+{
+ Stanza presence("presence");
+ presence["from"] = from;
+ presence["to"] = to;
+ if (!type.empty())
+ presence["type"] = type;
+ if (!id.empty())
+ presence["id"] = id;
+ this->send_stanza(presence);
+}
+
+void BiboumiComponent::on_irc_client_connected(const std::string& irc_hostname, const std::string& jid)
+{
+#ifdef USE_DATABASE
+ const auto local_jid = irc_hostname + "@" + this->served_hostname;
+ if (Database::has_roster_item(local_jid, jid))
+ this->send_presence_to_contact(local_jid, jid, "");
+#endif
+}
+
+void BiboumiComponent::on_irc_client_disconnected(const std::string& irc_hostname, const std::string& jid)
+{
+#ifdef USE_DATABASE
+ const auto local_jid = irc_hostname + "@" + this->served_hostname;
+ if (Database::has_roster_item(local_jid, jid))
+ this->send_presence_to_contact(irc_hostname + "@" + this->served_hostname, jid, "unavailable");
+#endif
+}
+
+void BiboumiComponent::after_handshake()
+{
+ XmppComponent::after_handshake();
+
+#ifdef USE_DATABASE
+ const auto contacts = Database::get_contact_list(this->get_served_hostname());
+
+ for (const Database::RosterItem& roster_item: contacts)
+ {
+ const auto remote_jid = roster_item.col<Database::RemoteJid>();
+ // In response, we will receive a presence indicating the
+ // contact is online, to which we will respond with our own
+ // presence.
+ // If the contact removed us from their roster while we were
+ // offline, we will receive an unsubscribed presence, letting us
+ // stay in sync.
+ this->send_presence_to_contact(this->get_served_hostname(), remote_jid, "probe");
+ }
+#endif
+}
diff --git a/src/xmpp/biboumi_component.hpp b/src/xmpp/biboumi_component.hpp
index 87311f9..caf990e 100644
--- a/src/xmpp/biboumi_component.hpp
+++ b/src/xmpp/biboumi_component.hpp
@@ -36,6 +36,8 @@ public:
BiboumiComponent& operator=(const BiboumiComponent&) = delete;
BiboumiComponent& operator=(BiboumiComponent&&) = delete;
+ void after_handshake() override final;
+
/**
* Returns the bridge for the given user. If it does not exist, return
* nullptr.
@@ -85,8 +87,15 @@ 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);
+private:
+ void send_invitation_from_fulljid(const std::string& room_target, const std::string& jid_to, const std::string& from);
+public:
void accept_subscription(const std::string& from, const std::string& to);
void ask_subscription(const std::string& from, const std::string& to);
+ void send_presence_to_contact(const std::string& from, const std::string& to, const std::string& type, const std::string& id="");
+ void on_irc_client_connected(const std::string& irc_hostname, const std::string& jid);
+ void on_irc_client_disconnected(const std::string& irc_hostname, const std::string& jid);
+
/**
* Handle the various stanza types
*/
diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp
index b138ed9..42a5392 100644
--- a/src/xmpp/xmpp_component.cpp
+++ b/src/xmpp/xmpp_component.cpp
@@ -92,7 +92,7 @@ void XmppComponent::on_connected()
{
log_info("connected to XMPP server");
this->first_connection_try = true;
- auto data = "<stream:stream to='"s + this->served_hostname + \
+ auto data = "<stream:stream to='" + this->served_hostname + \
"' xmlns:stream='http://etherx.jabber.org/streams' xmlns='" COMPONENT_NS "'>";
log_debug("XMPP SENDING: ", data);
this->send_data(std::move(data));
@@ -142,7 +142,7 @@ void XmppComponent::on_remote_stream_open(const XmlNode& node)
}
// Try to authenticate
- auto data = "<handshake xmlns='" COMPONENT_NS "'>"s + get_handshake_digest(this->stream_id, this->secret) + "</handshake>";
+ auto data = "<handshake xmlns='" COMPONENT_NS "'>" + get_handshake_digest(this->stream_id, this->secret) + "</handshake>";
log_debug("XMPP SENDING: ", data);
this->send_data(std::move(data));
}
@@ -261,7 +261,6 @@ void XmppComponent::handle_error(const Stanza& stanza)
if (!this->ever_auth)
sd_notifyf(0, "STATUS=Failed to authenticate to the XMPP server: %s", error_message.data());
#endif
-
}
void* XmppComponent::get_receive_buffer(const size_t size) const
@@ -338,35 +337,6 @@ void XmppComponent::send_user_join(const std::string& from,
this->send_stanza(presence);
}
-void XmppComponent::send_invalid_room_error(const std::string& muc_name,
- const std::string& nick,
- const std::string& to)
-{
- Stanza presence("presence");
- {
- if (!muc_name.empty ())
- presence["from"] = muc_name + "@" + this->served_hostname + "/" + nick;
- else
- presence["from"] = this->served_hostname;
- presence["to"] = to;
- presence["type"] = "error";
- XmlSubNode x(presence, "x");
- x["xmlns"] = MUC_NS;
- XmlSubNode error(presence, "error");
- error["by"] = muc_name + "@" + this->served_hostname;
- error["type"] = "cancel";
- XmlSubNode item_not_found(error, "item-not-found");
- item_not_found["xmlns"] = STANZA_NS;
- XmlSubNode text(error, "text");
- text["xmlns"] = STANZA_NS;
- text["xml:lang"] = "en";
- text.set_inner(muc_name +
- " is not a valid IRC channel name. A correct room jid is of the form: #<chan>%<server>@" +
- this->served_hostname);
- }
- this->send_stanza(presence);
-}
-
void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, const std::string& to, const std::string& who)
{
Stanza message("message");
@@ -441,7 +411,8 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std:
this->send_stanza(message);
}
-void XmppComponent::send_muc_leave(const std::string& muc_name, const std::string& nick, Xmpp::body&& message, const std::string& jid_to, const bool self)
+void XmppComponent::send_muc_leave(const std::string& muc_name, const std::string& nick, Xmpp::body&& message,
+ const std::string& jid_to, const bool self, const bool user_requested)
{
Stanza presence("presence");
{
@@ -453,8 +424,15 @@ void XmppComponent::send_muc_leave(const std::string& muc_name, const std::strin
x["xmlns"] = MUC_USER_NS;
if (self)
{
- XmlSubNode status(x, "status");
- status["code"] = "110";
+ {
+ XmlSubNode status(x, "status");
+ status["code"] = "110";
+ }
+ if (!user_requested)
+ {
+ XmlSubNode status(x, "status");
+ status["code"] = "332";
+ }
}
if (!message_str.empty())
{
@@ -642,7 +620,7 @@ void XmppComponent::send_iq_version_request(const std::string& from,
Stanza iq("iq");
{
iq["type"] = "get";
- iq["id"] = "version_"s + XmppComponent::next_id();
+ iq["id"] = "version_" + XmppComponent::next_id();
iq["from"] = from + "@" + this->served_hostname;
iq["to"] = jid_to;
XmlSubNode query(iq, "query");
diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp
index ebe3ec8..22d5c48 100644
--- a/src/xmpp/xmpp_component.hpp
+++ b/src/xmpp/xmpp_component.hpp
@@ -124,12 +124,6 @@ public:
const std::string& to,
const bool self);
/**
- * Send an error to indicate that the user tried to join an invalid room
- */
- void send_invalid_room_error(const std::string& muc_jid,
- const std::string& nick,
- const std::string& to);
- /**
* Send the MUC topic to the user
*/
void send_topic(const std::string& from, Xmpp::body&& xmpp_topic, const std::string& to, const std::string& who);
@@ -146,7 +140,12 @@ public:
/**
* Send an unavailable presence for this nick
*/
- void send_muc_leave(const std::string& muc_name, const std::string& nick, Xmpp::body&& message, const std::string& jid_to, const bool self);
+ void send_muc_leave(const std::string& muc_name,
+ const std::string& nick,
+ Xmpp::body&& message,
+ const std::string& jid_to,
+ const bool self,
+ const bool user_requested);
/**
* Indicate that a participant changed his nick
*/