summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bridge/bridge.cpp55
-rw-r--r--src/bridge/bridge.hpp3
-rw-r--r--src/irc/irc_client.cpp5
-rw-r--r--src/xmpp/biboumi_component.cpp11
4 files changed, 72 insertions, 2 deletions
diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp
index cc2ef66..24959d1 100644
--- a/src/bridge/bridge.cpp
+++ b/src/bridge/bridge.cpp
@@ -569,6 +569,57 @@ void Bridge::send_irc_channel_list_request(const Iid& iid, const std::string& iq
}
}
+void Bridge::force_connect_to_server(const std::string& hostname, const std::string& resource)
+{
+ auto soptions = Database::get_irc_server_options(this->get_bare_jid(), hostname);
+ const auto& nickname = soptions.col<Database::Nick>();
+ IrcClient* irc = nullptr;
+ if (nickname.empty())
+ {
+ irc = this->find_irc_client(hostname);
+ if (!irc)
+ return;
+ }
+ else
+ {
+ irc = this->make_irc_client(hostname, nickname);
+ this->add_resource_to_server(hostname, resource);
+ irc->start();
+ }
+ auto result = this->force_connected_resources.insert(std::make_pair(irc, std::set<Resource>{resource}));
+ const bool& inserted = result.second;
+ if (!inserted)
+ {
+ auto& it = result.first;
+ std::set<Resource>& resources = it->second;
+ resources.insert(resource);
+ }
+}
+
+void Bridge::unforce_connect_to_server(const std::string& hostname, const std::string& resource)
+{
+ IrcClient* irc = this->find_irc_client(hostname);
+ if (!irc)
+ return;
+ auto server_it = this->force_connected_resources.find(irc);
+ if (server_it == this->force_connected_resources.end())
+ return;
+ std::set<Resource>& forced_resources = server_it->second;
+ auto resource_it = forced_resources.find(resource);
+ if (resource_it == forced_resources.end())
+ return;
+ forced_resources.erase(resource_it);
+ if (forced_resources.empty())
+ {
+ this->force_connected_resources.erase(server_it);
+ irc->send_quit_command("");
+ }
+ else
+ {
+ this->remove_resource_from_server(hostname, resource);
+ }
+}
+
bool Bridge::send_matching_channel_list(const ChannelList& channel_list, const ResultSetInfo& rs_info,
const std::string& id, const std::string& to_jid, const std::string& from)
{
@@ -902,7 +953,9 @@ void Bridge::send_muc_leave(const Iid& iid, const IrcUser& user,
}
}
IrcClient* irc = this->find_irc_client(iid.get_server());
- if (self && irc && irc->number_of_joined_channels() == 0)
+ auto forced_resources = this->force_connected_resources.find(irc);
+ const bool force_connected = forced_resources != this->force_connected_resources.end() && !forced_resources->second.empty();
+ if (self && irc && irc->number_of_joined_channels() == 0 && !force_connected)
irc->send_quit_command("");
}
diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp
index 5c547ff..a1934bb 100644
--- a/src/bridge/bridge.hpp
+++ b/src/bridge/bridge.hpp
@@ -97,6 +97,8 @@ public:
const std::string& from_jid);
void send_irc_channel_list_request(const Iid& iid, const std::string& iq_id, const std::string& to_jid,
ResultSetInfo rs_info);
+ void force_connect_to_server(const std::string& hostname, const std::string& resource);
+ void unforce_connect_to_server(const std::string& hostname, const std::string& resource);
/**
* Check if the channel list contains what is needed to answer the RSM request,
* if it does, send the iq result. If the list is complete but does not contain
@@ -310,6 +312,7 @@ private:
public:
std::map<ChannelKey, std::set<Resource>> resources_in_chan;
std::map<IrcHostname, std::set<Resource>> resources_in_server;
+ std::map<const IrcClient*, std::set<Resource>> force_connected_resources;
private:
/**
* Manage which resource is in which channel
diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp
index 0b5715e..b72c078 100644
--- a/src/irc/irc_client.cpp
+++ b/src/irc/irc_client.cpp
@@ -481,7 +481,10 @@ void IrcClient::send_topic_command(const std::string& chan_name, const std::stri
void IrcClient::send_quit_command(const std::string& reason)
{
- this->send_message(IrcMessage("QUIT", {reason}), {}, false);
+ if (!reason.empty())
+ this->send_message(IrcMessage("QUIT", {reason}), {}, false);
+ else
+ this->send_message(IrcMessage("QUIT", {}), {}, false);
}
void IrcClient::send_join_command(const std::string& chan_name, const std::string& password)
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index 4ed47cf..c6dc323 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -238,11 +238,22 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
#endif
}
}
+ else if (type == "unavailable")
+ {
+ if (iid.type == Iid::Type::Server)
+ {
+ bridge->unforce_connect_to_server(iid.get_server(), from.resource);
+ }
+ }
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 if (iid.type == Iid::Type::Server)
+ {
+ bridge->force_connect_to_server(iid.get_server(), from.resource);
+ }
}
}
else if (iid.type == Iid::Type::User)