@@ -46,6 +46,8 @@
|
|||||||
|
|
||||||
<field name="maxHistoryLength" type="integer" default="20"/>
|
<field name="maxHistoryLength" type="integer" default="20"/>
|
||||||
|
|
||||||
|
<field name="persistent" type="boolean" default="false"/>
|
||||||
|
|
||||||
<index unique="true">
|
<index unique="true">
|
||||||
<indexfield name="owner"/>
|
<indexfield name="owner"/>
|
||||||
<indexfield name="server"/>
|
<indexfield name="server"/>
|
||||||
|
|||||||
@@ -564,6 +564,13 @@ On a channel JID (e.g on the JID #test%chat.freenode.org@biboumi.example.com)
|
|||||||
* In encoding: see the option with the same name in the server configuration
|
* In encoding: see the option with the same name in the server configuration
|
||||||
form.
|
form.
|
||||||
* Out encoding: Currently ignored.
|
* Out encoding: Currently ignored.
|
||||||
|
* Persistent: If set to true, biboumi will stay in this channel even when
|
||||||
|
all the XMPP resources have left the room. I.e. it will not send a PART
|
||||||
|
command, and will stay idle in the channel until the connection is
|
||||||
|
forcibly closed. If a resource comes back in the room again, and if
|
||||||
|
the archiving of messages is enabled for this room, the client will
|
||||||
|
receive the messages that where sent in this channel. This option can be
|
||||||
|
used to make biboumi act as an IRC bouncer.
|
||||||
|
|
||||||
Raw IRC messages
|
Raw IRC messages
|
||||||
----------------
|
----------------
|
||||||
|
|||||||
+33
-9
@@ -62,7 +62,7 @@ void Bridge::shutdown(const std::string& exit_message)
|
|||||||
for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it)
|
for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it)
|
||||||
{
|
{
|
||||||
it->second->send_quit_command(exit_message);
|
it->second->send_quit_command(exit_message);
|
||||||
it->second->leave_dummy_channel(exit_message);
|
it->second->leave_dummy_channel(exit_message, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,33 +422,48 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con
|
|||||||
if (!this->is_resource_in_chan(key, resource))
|
if (!this->is_resource_in_chan(key, resource))
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
|
IrcChannel* channel = irc->get_channel(iid.get_local());
|
||||||
|
auto nick = channel->get_self()->nick;
|
||||||
|
|
||||||
const auto resources = this->number_of_resources_in_chan(key);
|
const auto resources = this->number_of_resources_in_chan(key);
|
||||||
if (resources == 1)
|
if (resources == 1)
|
||||||
{
|
{
|
||||||
// Do not send a PART message if we actually are not in that channel
|
// Do not send a PART message if we actually are not in that channel
|
||||||
// or if we already sent a PART but we are just waiting for the
|
// or if we already sent a PART but we are just waiting for the
|
||||||
// acknowledgment from the server
|
// acknowledgment from the server
|
||||||
IrcChannel* channel = irc->get_channel(iid.get_local());
|
bool persistent = false;
|
||||||
if (channel->joined && !channel->parting)
|
#ifdef USE_DATABASE
|
||||||
|
const auto coptions = Database::get_irc_channel_options_with_server_default(this->user_jid,
|
||||||
|
iid.get_server(), iid.get_local());
|
||||||
|
persistent = coptions.persistent.value();
|
||||||
|
#endif
|
||||||
|
if (channel->joined && !channel->parting && !persistent)
|
||||||
|
{
|
||||||
|
const auto chan_name = iid.get_local();
|
||||||
|
if (chan_name.empty())
|
||||||
|
irc->leave_dummy_channel(status_message, resource);
|
||||||
|
else
|
||||||
irc->send_part_command(iid.get_local(), status_message);
|
irc->send_part_command(iid.get_local(), status_message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->send_muc_leave(std::move(iid), std::move(nick), "", true, resource);
|
||||||
|
}
|
||||||
// Since there are no resources left in that channel, we don't
|
// Since there are no resources left in that channel, we don't
|
||||||
// want to receive private messages using this room's JID
|
// want to receive private messages using this room's JID
|
||||||
this->remove_all_preferred_from_jid_of_room(iid.get_local());
|
this->remove_all_preferred_from_jid_of_room(iid.get_local());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IrcChannel* chan = irc->get_channel(iid.get_local());
|
if (channel)
|
||||||
if (chan)
|
|
||||||
{
|
|
||||||
auto nick = chan->get_self()->nick;
|
|
||||||
this->remove_resource_from_chan(key, resource);
|
|
||||||
this->send_muc_leave(std::move(iid), std::move(nick),
|
this->send_muc_leave(std::move(iid), std::move(nick),
|
||||||
"Biboumi note: "s + std::to_string(resources - 1) + " resources are still in this channel.",
|
"Biboumi note: "s + std::to_string(resources - 1) + " resources are still in this channel.",
|
||||||
true, resource);
|
true, resource);
|
||||||
|
this->remove_resource_from_chan(key, resource);
|
||||||
if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0)
|
if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0)
|
||||||
this->remove_resource_from_server(iid.get_server(), resource);
|
this->remove_resource_from_server(iid.get_server(), resource);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick, const std::string& requesting_resource)
|
void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick, const std::string& requesting_resource)
|
||||||
@@ -862,9 +877,13 @@ void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& me
|
|||||||
this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message),
|
this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message),
|
||||||
this->user_jid + "/" + resource, self);
|
this->user_jid + "/" + resource, self);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
for (const auto &res: this->resources_in_chan[iid.to_tuple()])
|
for (const auto &res: this->resources_in_chan[iid.to_tuple()])
|
||||||
this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message),
|
this->xmpp.send_muc_leave(std::to_string(iid), std::move(nick), this->make_xmpp_body(message),
|
||||||
this->user_jid + "/" + res, self);
|
this->user_jid + "/" + res, self);
|
||||||
|
this->remove_all_resources_from_chan(iid.to_tuple());
|
||||||
|
|
||||||
|
}
|
||||||
IrcClient* irc = this->find_irc_client(iid.get_server());
|
IrcClient* irc = this->find_irc_client(iid.get_server());
|
||||||
if (irc && irc->number_of_joined_channels() == 0)
|
if (irc && irc->number_of_joined_channels() == 0)
|
||||||
this->quit_or_start_linger_timer(iid.get_server());
|
this->quit_or_start_linger_timer(iid.get_server());
|
||||||
@@ -1137,6 +1156,11 @@ bool Bridge::is_resource_in_chan(const Bridge::ChannelKey& channel, const std::s
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bridge::remove_all_resources_from_chan(const Bridge::ChannelKey& channel_key)
|
||||||
|
{
|
||||||
|
this->resources_in_chan.erase(channel_key);
|
||||||
|
}
|
||||||
|
|
||||||
void Bridge::add_resource_to_server(const Bridge::IrcHostname& irc_hostname, const std::string& resource)
|
void Bridge::add_resource_to_server(const Bridge::IrcHostname& irc_hostname, const std::string& resource)
|
||||||
{
|
{
|
||||||
auto it = this->resources_in_server.find(irc_hostname);
|
auto it = this->resources_in_server.find(irc_hostname);
|
||||||
|
|||||||
@@ -312,6 +312,7 @@ private:
|
|||||||
void add_resource_to_chan(const ChannelKey& channel_key, const std::string& resource);
|
void add_resource_to_chan(const ChannelKey& channel_key, const std::string& resource);
|
||||||
void remove_resource_from_chan(const ChannelKey& channel_key, const std::string& resource);
|
void remove_resource_from_chan(const ChannelKey& channel_key, const std::string& resource);
|
||||||
bool is_resource_in_chan(const ChannelKey& channel_key, const std::string& resource) const;
|
bool is_resource_in_chan(const ChannelKey& channel_key, const std::string& resource) const;
|
||||||
|
void remove_all_resources_from_chan(const ChannelKey& channel_key);
|
||||||
std::size_t number_of_resources_in_chan(const ChannelKey& channel_key) const;
|
std::size_t number_of_resources_in_chan(const ChannelKey& channel_key) const;
|
||||||
|
|
||||||
void add_resource_to_server(const IrcHostname& irc_hostname, const std::string& resource);
|
void add_resource_to_server(const IrcHostname& irc_hostname, const std::string& resource);
|
||||||
|
|||||||
+2
-10
@@ -501,15 +501,7 @@ void IrcClient::send_private_message(const std::string& username, const std::str
|
|||||||
|
|
||||||
void IrcClient::send_part_command(const std::string& chan_name, const std::string& status_message)
|
void IrcClient::send_part_command(const std::string& chan_name, const std::string& status_message)
|
||||||
{
|
{
|
||||||
IrcChannel* channel = this->get_channel(chan_name);
|
|
||||||
if (channel->joined == true)
|
|
||||||
{
|
|
||||||
if (chan_name.empty())
|
|
||||||
this->leave_dummy_channel(status_message);
|
|
||||||
else
|
|
||||||
this->send_message(IrcMessage("PART", {chan_name, status_message}));
|
this->send_message(IrcMessage("PART", {chan_name, status_message}));
|
||||||
channel->parting = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrcClient::send_mode_command(const std::string& chan_name, const std::vector<std::string>& arguments)
|
void IrcClient::send_mode_command(const std::string& chan_name, const std::vector<std::string>& arguments)
|
||||||
@@ -1160,14 +1152,14 @@ DummyIrcChannel& IrcClient::get_dummy_channel()
|
|||||||
return this->dummy_channel;
|
return this->dummy_channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrcClient::leave_dummy_channel(const std::string& exit_message)
|
void IrcClient::leave_dummy_channel(const std::string& exit_message, const std::string& resource)
|
||||||
{
|
{
|
||||||
if (!this->dummy_channel.joined)
|
if (!this->dummy_channel.joined)
|
||||||
return;
|
return;
|
||||||
this->dummy_channel.joined = false;
|
this->dummy_channel.joined = false;
|
||||||
this->dummy_channel.joining = false;
|
this->dummy_channel.joining = false;
|
||||||
this->dummy_channel.remove_all_users();
|
this->dummy_channel.remove_all_users();
|
||||||
this->bridge.send_muc_leave(Iid("%"s + this->hostname, this->chantypes), std::string(this->current_nick), exit_message, true);
|
this->bridge.send_muc_leave(Iid("%"s + this->hostname, this->chantypes), std::string(this->current_nick), exit_message, true, resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BOTAN_FOUND
|
#ifdef BOTAN_FOUND
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ public:
|
|||||||
* Leave the dummy channel: forward a message to the user to indicate that
|
* Leave the dummy channel: forward a message to the user to indicate that
|
||||||
* he left it, and mark it as not joined.
|
* he left it, and mark it as not joined.
|
||||||
*/
|
*/
|
||||||
void leave_dummy_channel(const std::string& exit_message);
|
void leave_dummy_channel(const std::string& exit_message, const std::string& resource);
|
||||||
|
|
||||||
const std::string& get_hostname() const { return this->hostname; }
|
const std::string& get_hostname() const { return this->hostname; }
|
||||||
std::string get_nick() const { return this->current_nick; }
|
std::string get_nick() const { return this->current_nick; }
|
||||||
|
|||||||
@@ -256,7 +256,8 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
XmlSubNode pass(x, "field");
|
XmlSubNode pass(x, "field");
|
||||||
pass["var"] = "pass";
|
pass["var"] = "pass";
|
||||||
pass["type"] = "text-private";
|
pass["type"] = "text-private";
|
||||||
pass["label"] = "Server password (to be used in a PASS command when connecting)";
|
pass["label"] = "Server password";
|
||||||
|
pass["desc"] = "Will be used in a PASS command when connecting";
|
||||||
if (!options.pass.value().empty())
|
if (!options.pass.value().empty())
|
||||||
{
|
{
|
||||||
XmlSubNode pass_value(pass, "value");
|
XmlSubNode pass_value(pass, "value");
|
||||||
@@ -463,6 +464,20 @@ void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& co
|
|||||||
XmlSubNode encoding_in_value(encoding_in, "value");
|
XmlSubNode encoding_in_value(encoding_in, "value");
|
||||||
encoding_in_value.set_inner(options.encodingIn.value());
|
encoding_in_value.set_inner(options.encodingIn.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.persistent.value())
|
||||||
|
value.set_inner("true");
|
||||||
|
else
|
||||||
|
value.set_inner("false");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
|
void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node)
|
||||||
@@ -486,6 +501,10 @@ void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& co
|
|||||||
else if (field->get_tag("var") == "encoding_in" &&
|
else if (field->get_tag("var") == "encoding_in" &&
|
||||||
value && !value->get_inner().empty())
|
value && !value->get_inner().empty())
|
||||||
options.encodingIn = value->get_inner();
|
options.encodingIn = value->get_inner();
|
||||||
|
|
||||||
|
else if (field->get_tag("var") == "persistent" &&
|
||||||
|
value)
|
||||||
|
options.persistent = to_bool(value->get_inner());
|
||||||
}
|
}
|
||||||
|
|
||||||
options.update();
|
options.update();
|
||||||
|
|||||||
Reference in New Issue
Block a user