From e75d7ad8ea72044fdfd2317e03f91ba5bea06b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 16 Jun 2017 10:48:54 +0200 Subject: Add a Record History option in the Channel configuration form fix #3269 --- CHANGELOG.rst | 2 ++ doc/biboumi.1.rst | 7 ++++- src/utils/optional_bool.hpp | 10 +++++++ src/xmpp/biboumi_adhoc_commands.cpp | 53 ++++++++++++++++++++++++++++++++++--- src/xmpp/biboumi_adhoc_commands.hpp | 2 +- src/xmpp/biboumi_component.cpp | 2 +- tests/end_to_end/__main__.py | 3 +++ 7 files changed, 72 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9bfecd6..c8cddfe 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,8 @@ Version 6.0 - The LiteSQL dependency was removed. Only libsqlite3 is now necessary to work with the database. + - The RecordHistory option can now also be configured for each IRC channel, + individually. Version 5.0 - 2017-05-24 ======================== diff --git a/doc/biboumi.1.rst b/doc/biboumi.1.rst index 5396015..4a2225e 100644 --- a/doc/biboumi.1.rst +++ b/doc/biboumi.1.rst @@ -358,7 +358,7 @@ History ------- Public channel messages are saved into archives, inside the database, unless -the `record_history` option is set to false for that user `Ad-hoc commands`. +the `record_history` option is set to false by that user (see `Ad-hoc commands`). Private messages (messages that are sent directly to a nickname, not a channel) are never stored in the database. When a channel is joined, biboumi sends the `max_history_length` messages found in the database as the MUC @@ -631,6 +631,11 @@ On a channel JID (e.g on the JID #test%chat.freenode.org@biboumi.example.com) 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. + * Record History: whether or not history messages should be saved in + the database, for this specific channel. If the value is “unset” (the + default), then the value configured globally is used. This option is there, + for example, to be able to enable history recording globally while disabling + it for a few specific “private” channels. Raw IRC messages ---------------- diff --git a/src/utils/optional_bool.hpp b/src/utils/optional_bool.hpp index 824e76d..59bbbab 100644 --- a/src/utils/optional_bool.hpp +++ b/src/utils/optional_bool.hpp @@ -20,6 +20,16 @@ struct OptionalBool this->is_set = false; } + std::string to_string() + { + if (this->is_set == false) + return "unset"; + else if (this->value) + return "true"; + else + return "false"; + } + bool is_set{false}; bool value{false}; }; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index a13dbb8..ad4faf8 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -434,6 +434,26 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, 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"; + + { + // Value selected by default + XmlSubNode value(record_history, "value"); + value.set_inner(options.col().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); + } + XmlSubNode encoding_out(x, "field"); encoding_out["var"] = "encoding_out"; encoding_out["type"] = "text-single"; @@ -471,12 +491,12 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, } } -void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) +void ConfigureIrcChannelStep2(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node) { const Jid owner(session.get_owner_jid()); const Jid target(session.get_target_jid()); - if (handle_irc_channel_configuration_form(command_node, owner, target)) + if (handle_irc_channel_configuration_form(xmpp_component, command_node, owner, target)) { command_node.delete_all_children(); XmlSubNode note(command_node, "note"); @@ -492,7 +512,7 @@ void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& co } } -bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& requester, const Jid& target) +bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const XmlNode& node, const Jid& requester, const Jid& target) { const XmlNode* x = node.get_child("x", "jabber:x:data"); if (x) @@ -500,7 +520,7 @@ bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& reque if (x->get_tag("type") == "submit") { const Iid iid(target.local, {}); - auto options = Database::get_irc_channel_options(requester.local + "@" + requester.domain, + auto options = Database::get_irc_channel_options(requester.bare(), iid.get_server(), iid.get_local()); for (const XmlNode *field: x->get_children("field", "jabber:x:data")) { @@ -517,6 +537,31 @@ bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& reque else if (field->get_tag("var") == "persistent" && value) options.col() = to_bool(value->get_inner()); + else if (field->get_tag("var") == "record_history" && + value && !value->get_inner().empty()) + { + OptionalBool& database_value = options.col(); + if (value->get_inner() == "true") + database_value.set_value(true); + else if (value->get_inner() == "false") + database_value.set_value(false); + else + database_value.unset(); + auto& biboumi_component = dynamic_cast(xmpp_component); + Bridge* bridge = biboumi_component.find_user_bridge(requester.bare()); + if (bridge) + { + if (database_value.is_set) + bridge->set_record_history(database_value.value); + else + { // It is unset, we need to fetch the Global option, to + // know if it’s enabled or not + auto g_options = Database::get_global_options(requester.bare()); + bridge->set_record_history(g_options.col()); + } + } + } + } options.save(Database::db); diff --git a/src/xmpp/biboumi_adhoc_commands.hpp b/src/xmpp/biboumi_adhoc_commands.hpp index 7d29cc2..cb6acb9 100644 --- a/src/xmpp/biboumi_adhoc_commands.hpp +++ b/src/xmpp/biboumi_adhoc_commands.hpp @@ -20,7 +20,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com void ConfigureIrcChannelStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, const Jid& target); void ConfigureIrcChannelStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); -bool handle_irc_channel_configuration_form(const XmlNode& node, const Jid& requester, const Jid& target); +bool handle_irc_channel_configuration_form(XmppComponent&, const XmlNode& node, const Jid& requester, const Jid& target); void DisconnectUserFromServerStep1(XmppComponent&, AdhocSession& session, XmlNode& command_node); void DisconnectUserFromServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node); diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 881e757..32f3968 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -719,7 +719,7 @@ bool BiboumiComponent::handle_room_configuration_form(const XmlNode& query, cons return false; Jid requester(from); - if (!handle_irc_channel_configuration_form(query, requester, to)) + if (!handle_irc_channel_configuration_form(*this, query, requester, to)) return false; Stanza iq("iq"); diff --git a/tests/end_to_end/__main__.py b/tests/end_to_end/__main__.py index 8f108ee..f7fa2ff 100644 --- a/tests/end_to_end/__main__.py +++ b/tests/end_to_end/__main__.py @@ -2467,6 +2467,7 @@ if __name__ == '__main__': partial(expect_stanza, ("/iq[@type='result']/commands:command[@node='configure'][@sessionid][@status='executing']", "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']", "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_out']", + "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='list-single'][@var='record_history']/dataform:value[text()='unset']", ), after = partial(save_value, "sessionid", partial(extract_attribute, "/iq[@type='result']/commands:command[@node='configure']", "sessionid")) ), @@ -2476,6 +2477,7 @@ if __name__ == '__main__': "" "UTF-8" "latin-1" + "true" ""), partial(expect_stanza, "/iq[@type='result']/commands:command[@node='configure'][@status='completed']/commands:note[@type='info'][text()='Configuration successfully applied.']"), @@ -2484,6 +2486,7 @@ if __name__ == '__main__': "/iq/commands:command/dataform:x[@type='form']/dataform:title[text()='Configure the IRC channel #foo on server irc.localhost']", "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']/dataform:value[text()='latin-1']", "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_out']/dataform:value[text()='UTF-8']", + "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='list-single'][@var='record_history']/dataform:value[text()='true']", "/iq/commands:command/commands:actions/commands:next", ), after = partial(save_value, "sessionid", partial(extract_attribute, "/iq[@type='result']/commands:command[@node='configure']", "sessionid")) -- cgit v1.2.3