bfcf29451787d10c747ad79cb3fd177ac86e9cf1 — louiz’ 5 years ago 8d99374
Add the persistent_by_default configuration option

fix #3293
M CHANGELOG.rst => CHANGELOG.rst +3 -0
@@ 15,6 15,9 @@ Version 6.0
 - Invitations can now be sent to any JID, not only JIDs served by the biboumi
   instance itself.
 - The persistent_by_default configuration option has been added, this
   lets the administrator decide whether or not the rooms should be
   persistent or not by default, for all users.

Version 5.0 - 2017-05-24

M doc/biboumi.1.rst => doc/biboumi.1.rst +22 -4
@@ 100,6 100,21 @@ be used by an administrator that just wants to let their users join their own
IRC server using an XMPP client, while forbidding access to any other IRC


If this option is set to `true`, all rooms will be persistent by default:
the value of the “persistent” option in the global configuration of each
user will be “true”, but the value of each individual room will still
default to false. This means that a user just needs to change the global
“persistent” configuration option to false in order to override this.

If it is set to false (the default value), all rooms are not persistent by

Each room can be configured individually by each user, to override this
default value. See `Ad-hoc commands`_.


@@ 595,10 610,13 @@ On the gateway itself (e.g on the JID biboumi.example.com):
      the database.
    * Max history length: The maximum number of lines in the history
      that the server is allowed to send when joining a channel.
    * Persistent: Overrides the value specified in each individual channel,
      all channels are persistent, whether or not their specific value is
      true or false. See below for more details on what a persistent
      channel is.

    * Persistent: Overrides the value specified in each individual channel.
      If this option is set to true, all channels are persistent, whether
      or not their specific value is true or false. This option is true by
      default for everyone if the `persistent_by_default` configuration
      option is true, otherwise it’s false. See below for more details on
      what a persistent channel is. This value is

On a server JID (e.g on the JID chat.freenode.org@biboumi.example.com)

M src/bridge/bridge.cpp => src/bridge/bridge.cpp +1 -1
@@ 435,7 435,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con
      bool persistent = false;
      const auto goptions = Database::get_global_options(this->user_jid);
      if (goptions.col<Database::Persistent>())
      if (goptions.col<Database::GlobalPersistent>())
        persistent = true;

M src/config/config.cpp => src/config/config.cpp +8 -0
@@ 23,6 23,14 @@ std::string Config::get(const std::string& option, const std::string& def)
  return it->second;

bool Config::get_bool(const std::string& option, const bool def)
  auto res = Config::get(option, "");
  if (res.empty())
    return def;
  return res == "true";

int Config::get_int(const std::string& option, const int& def)
  std::string res = Config::get(option, "");

M src/config/config.hpp => src/config/config.hpp +1 -0
@@ 44,6 44,7 @@ public:
   * the second argument as the default.
  static int get_int(const std::string&, const int&);
  static bool get_bool(const std::string&, const bool);
   * Set a value for the given option. And write all the config
   * in the file from which it was read if save is true.

M src/database/database.cpp => src/database/database.cpp +5 -0
@@ 6,6 6,8 @@
#include <utils/get_first_non_empty.hpp>
#include <utils/time.hpp>

#include <config/config.hpp>

#include <database/index.hpp>

#include <sqlite3.h>

@@ 18,6 20,9 @@ Database::IrcChannelOptionsTable Database::irc_channel_options("IrcChannelOption
Database::RosterTable Database::roster("roster");
std::map<Database::CacheKey, Database::EncodingIn::real_type> Database::encoding_in_cache{};

    Column<bool>{Config::get_bool("persistent_by_default", false)}

void Database::open(const std::string& filename)

M src/database/database.hpp => src/database/database.hpp +4 -1
@@ 73,6 73,9 @@ class Database
  struct Persistent: Column<bool> { static constexpr auto name = "persistent_";
    Persistent(): Column<bool>(false) {} };

  struct GlobalPersistent: Column<bool> { static constexpr auto name = "persistent_";
    GlobalPersistent(); };

  struct LocalJid: Column<std::string> { static constexpr auto name = "local"; };

  struct RemoteJid: Column<std::string> { static constexpr auto name = "remote"; };

@@ 81,7 84,7 @@ class Database
  using MucLogLineTable = Table<Id, Uuid, Owner, IrcChanName, IrcServerName, Date, Body, Nick>;
  using MucLogLine = MucLogLineTable::RowType;

  using GlobalOptionsTable = Table<Id, Owner, MaxHistoryLength, RecordHistory, Persistent>;
  using GlobalOptionsTable = Table<Id, Owner, MaxHistoryLength, RecordHistory, GlobalPersistent>;
  using GlobalOptions = GlobalOptionsTable::RowType;

  using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, AfterConnectionCommand, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength>;

M src/xmpp/biboumi_adhoc_commands.cpp => src/xmpp/biboumi_adhoc_commands.cpp +2 -2
@@ 159,7 159,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman
      XmlSubNode value(persistent, "value");
      if (options.col<Database::Persistent>())
      if (options.col<Database::GlobalPersistent>())

@@ 193,7 193,7 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session, 
          else if (field->get_tag("var") == "persistent" &&
            options.col<Database::Persistent>() = to_bool(value->get_inner());
            options.col<Database::GlobalPersistent>() = to_bool(value->get_inner());


M tests/end_to_end/__main__.py => tests/end_to_end/__main__.py +24 -1
@@ 377,7 377,15 @@ port=8811


common_replacements = {
    'irc_server_one': 'irc.localhost@biboumi.localhost',

@@ 2650,6 2658,7 @@ if __name__ == '__main__':
                                            "/iq/commands:command/dataform:x[@type='form']/dataform:instructions[text()='Edit the form, to configure your global settings for the component.']",
                            after = partial(save_value, "sessionid", partial(extract_attribute, "/iq[@type='result']/commands:command[@node='configure']", "sessionid"))

@@ 2671,6 2680,20 @@ if __name__ == '__main__':
                    partial(send_stanza, "<iq type='set' id='id4' from='{jid_one}/{resource_one}' to='{biboumi_host}'><command xmlns='http://jabber.org/protocol/commands' action='cancel' node='configure' sessionid='{sessionid}' /></iq>"),
                    partial(expect_stanza, "/iq[@type='result']/commands:command[@node='configure'][@status='canceled']"),
                    partial(send_stanza, "<iq type='set' id='id1' from='{jid_one}/{resource_one}' to='{biboumi_host}'><command xmlns='http://jabber.org/protocol/commands' node='configure' action='execute' /></iq>"),
                    partial(expect_stanza, ("/iq[@type='result']/commands:command[@node='configure'][@sessionid][@status='executing']",
                                            "/iq/commands:command/dataform:x[@type='form']/dataform:title[text()='Configure some global default settings.']",
                                            "/iq/commands:command/dataform:x[@type='form']/dataform:instructions[text()='Edit the form, to configure your global settings for the component.']",