From 99389eefba1883753c15c6f411fb8543c93f58a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 10 Feb 2018 17:36:33 +0100 Subject: Always return the oldest matching messages from MAM, even if no date is set --- src/bridge/bridge.cpp | 2 +- src/database/database.cpp | 25 ++++++++++++++++++++++++- src/database/database.hpp | 9 +++++++++ src/xmpp/biboumi_component.cpp | 2 +- 4 files changed, 35 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 54bee84..acb8e18 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1020,7 +1020,7 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam auto limit = coptions.col(); if (history_limit.stanzas >= 0 && history_limit.stanzas < limit) limit = history_limit.stanzas; - const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since); + const auto lines = Database::get_muc_most_recent_logs(this->user_jid, chan_name, hostname, limit, history_limit.since); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { diff --git a/src/database/database.cpp b/src/database/database.cpp index 3622963..c43ace4 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -185,13 +185,36 @@ std::vector Database::get_muc_logs(const std::string& owne request << " and " << Database::Date{} << "<=" << end_time; } + if (limit >= 0) + request.limit() << limit; + + auto result = request.execute(*Database::db); + + return {result.cbegin(), result.cend()}; +} + +std::vector Database::get_muc_most_recent_logs(const std::string& owner, const std::string& chan_name, const std::string& server, + int limit, const std::string& start) +{ + auto request = Database::muc_log_lines.select(); + request.where() << Database::Owner{} << "=" << owner << \ + " and " << Database::IrcChanName{} << "=" << chan_name << \ + " and " << Database::IrcServerName{} << "=" << server; + + if (!start.empty()) + { + const auto start_time = utils::parse_datetime(start); + if (start_time != -1) + request << " and " << Database::Date{} << ">=" << start_time; + } + request.order_by() << Id{} << " DESC "; if (limit >= 0) request.limit() << limit; auto result = request.execute(*Database::db); - + return {result.crbegin(), result.crend()}; } diff --git a/src/database/database.hpp b/src/database/database.hpp index ec44543..f9aed2b 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -118,8 +118,17 @@ class Database static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner, const std::string& server, const std::string& channel); + /** + * Get all the lines between (optional) start and end dates, with a (optional) limit. + */ static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit=-1, const std::string& start="", const std::string& end=""); + + /** + * Get the most recent messages from the archive, with optional limit and start date + */ + static std::vector get_muc_most_recent_logs(const std::string& owner, const std::string& chan_name, const std::string& server, + int limit=-1, const std::string& start=""); static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, time_point date, const std::string& body, const std::string& nick); diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 481ebb9..250007e 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -721,7 +721,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) if (max) limit = std::atoi(max->get_inner().data()); } - // Do send more than 100 messages, even if the client asked for more, + // Do not send more than 100 messages, even if the client asked for more, // or if it didn’t specify any limit. // 101 is just a trick to know if there are more available messages. // If our query returns 101 message, we know it’s incomplete, but we -- cgit v1.2.3 From 0280343ced6c520700c3ca508e2d04c6b512d319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 10 Feb 2018 19:51:59 +0100 Subject: =?UTF-8?q?Handle=20the=20=E2=80=9Cafter=E2=80=9D=20RSM=20value=20?= =?UTF-8?q?to=20page=20through=20results?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/database/database.cpp | 35 ++++++++++++++++++++++++++++++++++- src/database/database.hpp | 9 ++++++++- src/xmpp/biboumi_component.cpp | 10 +++++++++- 3 files changed, 51 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/database/database.cpp b/src/database/database.cpp index c43ace4..2d6fbbd 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -165,7 +165,7 @@ std::string Database::store_muc_message(const std::string& owner, const std::str } std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start, const std::string& end) + int limit, const std::string& start, const std::string& end, const Id::real_type after_id) { auto request = Database::muc_log_lines.select(); request.where() << Database::Owner{} << "=" << owner << \ @@ -184,6 +184,10 @@ std::vector Database::get_muc_logs(const std::string& owne if (end_time != -1) request << " and " << Database::Date{} << "<=" << end_time; } + if (after_id != Id::unset_value) + { + request << " and " << Id{} << ">" << after_id; + } if (limit >= 0) request.limit() << limit; @@ -218,6 +222,35 @@ std::vector Database::get_muc_most_recent_logs(const std:: return {result.crbegin(), result.crend()}; } +Database::MucLogLine Database::get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, + const std::string& uuid, const std::string& start, const std::string& end) +{ + auto request = Database::muc_log_lines.select(); + request.where() << Database::Owner{} << "=" << owner << \ + " and " << Database::IrcChanName{} << "=" << chan_name << \ + " and " << Database::IrcServerName{} << "=" << server << \ + " and " << Database::Uuid{} << "=" << uuid; + + if (!start.empty()) + { + const auto start_time = utils::parse_datetime(start); + if (start_time != -1) + request << " and " << Database::Date{} << ">=" << start_time; + } + if (!end.empty()) + { + const auto end_time = utils::parse_datetime(end); + if (end_time != -1) + request << " and " << Database::Date{} << "<=" << end_time; + } + + auto result = request.execute(*Database::db); + + if (result.empty()) + throw Database::RecordNotFound{}; + return result.front(); +} + void Database::add_roster_item(const std::string& local, const std::string& remote) { auto roster_item = Database::roster.row(); diff --git a/src/database/database.hpp b/src/database/database.hpp index f9aed2b..810af16 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -120,15 +120,22 @@ class Database const std::string& channel); /** * Get all the lines between (optional) start and end dates, with a (optional) limit. + * If after_id is set, only the records after it will be returned. */ static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit=-1, const std::string& start="", const std::string& end=""); + int limit=-1, const std::string& start="", const std::string& end="", + const Id::real_type after_id=Id::unset_value); /** * Get the most recent messages from the archive, with optional limit and start date */ static std::vector get_muc_most_recent_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit=-1, const std::string& start=""); + /** + * Get just one single record matching the given uuid, between (optional) end and start. + * If it does not exist (or is not between end and start), throw a RecordNotFound exception. + */ + static MucLogLine get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, const std::string& uuid, const std::string& start="", const std::string& end=""); static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, time_point date, const std::string& body, const std::string& nick); diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 250007e..cd6d570 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -715,11 +715,19 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) } const XmlNode* set = query->get_child("set", RSM_NS); int limit = -1; + Id::real_type after_id{Id::unset_value}; if (set) { const XmlNode* max = set->get_child("max", RSM_NS); if (max) limit = std::atoi(max->get_inner().data()); + const XmlNode* after = set->get_child("after", RSM_NS); + if (after) + { + auto after_record = Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), + after->get_inner(), start, end); + after_id = after_record.col(); + } } // Do not send more than 100 messages, even if the client asked for more, // or if it didn’t specify any limit. @@ -729,7 +737,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) if ((limit == -1 && start.empty() && end.empty()) || limit > 100) limit = 101; - auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end); + auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, after_id); bool complete = true; if (lines.size() > 100) { -- cgit v1.2.3 From d70554143554f1a4ed3d225d30a6e49227f40fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 11 Feb 2018 23:29:58 +0100 Subject: =?UTF-8?q?Send=20a=20item-not-found=20error=20when=20the=20?= =?UTF-8?q?=E2=80=9Cafter=E2=80=9D=20value=20is=20not=20in=20the=20archive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/database/database.hpp | 1 + src/xmpp/biboumi_component.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index 810af16..fb62c34 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -22,6 +22,7 @@ class Database { public: using time_point = std::chrono::system_clock::time_point; + struct RecordNotFound: public std::exception {}; struct Uuid: Column { static constexpr auto name = "uuid_"; }; diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index cd6d570..405ac15 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -467,8 +467,12 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) #ifdef USE_DATABASE else if ((query = stanza.get_child("query", MAM_NS))) { - if (this->handle_mam_request(stanza)) - stanza_error.disable(); + try { + if (this->handle_mam_request(stanza)) + stanza_error.disable(); + } catch (const Database::RecordNotFound& exc) { + error_name = "item-not-found"; + } } else if ((query = stanza.get_child("query", MUC_OWNER_NS))) { -- cgit v1.2.3 From fd9c7139386e773ee64fe970089d77fede75181f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 11 Feb 2018 23:39:42 +0100 Subject: Fix a few warnings --- src/database/column.hpp | 2 +- src/database/insert_query.hpp | 2 +- src/database/query.cpp | 9 +++++++++ src/database/query.hpp | 2 ++ src/database/sqlite3_statement.hpp | 1 - 5 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/database/column.hpp b/src/database/column.hpp index 1f16bcf..9367701 100644 --- a/src/database/column.hpp +++ b/src/database/column.hpp @@ -18,5 +18,5 @@ struct Id: Column { static constexpr auto name = "id_"; static constexpr auto options = "PRIMARY KEY"; - Id(): Column(-1) {} + Id(): Column(unset_value) {} }; diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 9726424..04c098c 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -22,7 +22,7 @@ update_autoincrement_id(std::tuple& columns, Statement& statement) template typename std::enable_if::type -update_autoincrement_id(std::tuple&, Statement& statement) +update_autoincrement_id(std::tuple&, Statement&) {} struct InsertQuery: public Query diff --git a/src/database/query.cpp b/src/database/query.cpp index d27dc59..9611c97 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -21,6 +21,15 @@ void actual_bind(Statement& statement, const OptionalBool& value, int index) statement.bind_int64(index, -1); } +void actual_bind(Statement& statement, const std::size_t value, int index) +{ + actual_bind(statement, static_cast(value), index); +} + +void actual_bind(Statement& statement, const int value, int index) +{ + actual_bind(statement, static_cast(value), index); +} void actual_add_param(Query& query, const std::string& val) { diff --git a/src/database/query.hpp b/src/database/query.hpp index 8434944..25c3a62 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -13,6 +13,8 @@ void actual_bind(Statement& statement, const std::string& value, int index); void actual_bind(Statement& statement, const std::int64_t value, int index); +void actual_bind(Statement& statement, const std::size_t value, int index); +void actual_bind(Statement& statement, const int value, int index); void actual_bind(Statement& statement, const OptionalBool& value, int index); #ifdef DEBUG_SQL_QUERIES diff --git a/src/database/sqlite3_statement.hpp b/src/database/sqlite3_statement.hpp index 7738fa6..3ed60c0 100644 --- a/src/database/sqlite3_statement.hpp +++ b/src/database/sqlite3_statement.hpp @@ -88,5 +88,4 @@ class Sqlite3Statement: public Statement private: sqlite3_stmt* stmt; - int last_step_result{SQLITE_OK}; }; -- cgit v1.2.3 From fd7c365288b9c4db1d441b553d42b26e81715b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Feb 2018 03:10:00 +0100 Subject: Use the same function for both history orders --- src/bridge/bridge.cpp | 2 +- src/database/database.cpp | 40 +++++++++++++--------------------------- src/database/database.hpp | 8 ++------ 3 files changed, 16 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index acb8e18..fefab40 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1020,7 +1020,7 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam auto limit = coptions.col(); if (history_limit.stanzas >= 0 && history_limit.stanzas < limit) limit = history_limit.stanzas; - const auto lines = Database::get_muc_most_recent_logs(this->user_jid, chan_name, hostname, limit, history_limit.since); + const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, Id::unset_value, Database::Paging::last); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { diff --git a/src/database/database.cpp b/src/database/database.cpp index 2d6fbbd..2a63a6b 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -165,8 +165,11 @@ std::string Database::store_muc_message(const std::string& owner, const std::str } std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start, const std::string& end, const Id::real_type after_id) + int limit, const std::string& start, const std::string& end, const Id::real_type after_id, Database::Paging paging) { + if (limit == 0) + return {}; + auto request = Database::muc_log_lines.select(); request.where() << Database::Owner{} << "=" << owner << \ " and " << Database::IrcChanName{} << "=" << chan_name << \ @@ -189,37 +192,20 @@ std::vector Database::get_muc_logs(const std::string& owne request << " and " << Id{} << ">" << after_id; } - if (limit >= 0) - request.limit() << limit; - - auto result = request.execute(*Database::db); - - return {result.cbegin(), result.cend()}; -} - -std::vector Database::get_muc_most_recent_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start) -{ - auto request = Database::muc_log_lines.select(); - request.where() << Database::Owner{} << "=" << owner << \ - " and " << Database::IrcChanName{} << "=" << chan_name << \ - " and " << Database::IrcServerName{} << "=" << server; - - if (!start.empty()) - { - const auto start_time = utils::parse_datetime(start); - if (start_time != -1) - request << " and " << Database::Date{} << ">=" << start_time; - } - - request.order_by() << Id{} << " DESC "; + if (paging == Database::Paging::first) + request.order_by() << Id{} << " ASC "; + else + request.order_by() << Id{} << " DESC "; if (limit >= 0) request.limit() << limit; auto result = request.execute(*Database::db); - - return {result.crbegin(), result.crend()}; + + if (paging == Database::Paging::first) + return result; + else + return {result.crbegin(), result.crend()}; } Database::MucLogLine Database::get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, diff --git a/src/database/database.hpp b/src/database/database.hpp index fb62c34..9c483f4 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -23,6 +23,7 @@ class Database public: using time_point = std::chrono::system_clock::time_point; struct RecordNotFound: public std::exception {}; + enum class Paging { first, last }; struct Uuid: Column { static constexpr auto name = "uuid_"; }; @@ -125,13 +126,8 @@ class Database */ static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit=-1, const std::string& start="", const std::string& end="", - const Id::real_type after_id=Id::unset_value); + const Id::real_type after_id=Id::unset_value, Paging=Paging::first); - /** - * Get the most recent messages from the archive, with optional limit and start date - */ - static std::vector get_muc_most_recent_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit=-1, const std::string& start=""); /** * Get just one single record matching the given uuid, between (optional) end and start. * If it does not exist (or is not between end and start), throw a RecordNotFound exception. -- cgit v1.2.3 From 50d3c4a0b20a4fde582d186e4c9a2226755b1a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Feb 2018 03:39:13 +0100 Subject: Do not forget an early return, to return the correct item-not-found error --- src/xmpp/biboumi_component.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 405ac15..75a55e6 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -472,6 +472,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) stanza_error.disable(); } catch (const Database::RecordNotFound& exc) { error_name = "item-not-found"; + return; } } else if ((query = stanza.get_child("query", MUC_OWNER_NS))) -- cgit v1.2.3 From 4a2a280d76e45e165d5c4657f4a46eebf71594bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 13 Feb 2018 03:51:03 +0100 Subject: Support the element in MAM requests --- src/database/database.cpp | 16 +++++++++++----- src/database/database.hpp | 2 +- src/xmpp/biboumi_component.cpp | 17 ++++++++++++++--- 3 files changed, 26 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/database/database.cpp b/src/database/database.cpp index 2a63a6b..b2413d0 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -165,7 +165,7 @@ std::string Database::store_muc_message(const std::string& owner, const std::str } std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start, const std::string& end, const Id::real_type after_id, Database::Paging paging) + int limit, const std::string& start, const std::string& end, const Id::real_type reference_record_id, Database::Paging paging) { if (limit == 0) return {}; @@ -187,15 +187,21 @@ std::vector Database::get_muc_logs(const std::string& owne if (end_time != -1) request << " and " << Database::Date{} << "<=" << end_time; } - if (after_id != Id::unset_value) + if (reference_record_id != Id::unset_value) { - request << " and " << Id{} << ">" << after_id; + request << " and " << Id{}; + if (paging == Database::Paging::first) + request << ">"; + else + request << "<"; + request << reference_record_id; } + request.order_by() << Id{}; if (paging == Database::Paging::first) - request.order_by() << Id{} << " ASC "; + request << " ASC "; else - request.order_by() << Id{} << " DESC "; + request << " DESC "; if (limit >= 0) request.limit() << limit; diff --git a/src/database/database.hpp b/src/database/database.hpp index 9c483f4..ce7595b 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -126,7 +126,7 @@ class Database */ static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit=-1, const std::string& start="", const std::string& end="", - const Id::real_type after_id=Id::unset_value, Paging=Paging::first); + const Id::real_type reference_record_id=Id::unset_value, Paging=Paging::first); /** * Get just one single record matching the given uuid, between (optional) end and start. diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 75a55e6..fe6cc1b 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -720,7 +720,8 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) } const XmlNode* set = query->get_child("set", RSM_NS); int limit = -1; - Id::real_type after_id{Id::unset_value}; + Id::real_type reference_record_id{Id::unset_value}; + Database::Paging paging_order{Database::Paging::first}; if (set) { const XmlNode* max = set->get_child("max", RSM_NS); @@ -731,7 +732,17 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) { auto after_record = Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), after->get_inner(), start, end); - after_id = after_record.col(); + reference_record_id = after_record.col(); + } + const XmlNode* before = set->get_child("before", RSM_NS); + if (before) + { + paging_order = Database::Paging::last; + if (!before->get_inner().empty()) + { + auto before_record = Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), before->get_inner(), start, end); + reference_record_id = before_record.col(); + } } } // Do not send more than 100 messages, even if the client asked for more, @@ -742,7 +753,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) if ((limit == -1 && start.empty() && end.empty()) || limit > 100) limit = 101; - auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, after_id); + auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, reference_record_id, paging_order); bool complete = true; if (lines.size() > 100) { -- cgit v1.2.3 From 505deda1763137fd807e16586c8a2e1aa978c647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 14 Feb 2018 23:25:12 +0100 Subject: Fix a memory leak when psql connection fails --- src/database/postgresql_engine.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/database/postgresql_engine.cpp b/src/database/postgresql_engine.cpp index 984a959..518c23a 100644 --- a/src/database/postgresql_engine.cpp +++ b/src/database/postgresql_engine.cpp @@ -34,6 +34,7 @@ std::unique_ptr PostgresqlEngine::open(const std::string& connin { const char* errmsg = PQerrorMessage(con); log_error("Postgresql connection failed: ", errmsg); + PQfinish(con); throw std::runtime_error("failed to open connection."); } return std::make_unique(con); -- cgit v1.2.3 From dbb86bcc12921576c270009537b81b951d2ed84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 15 Feb 2018 16:54:54 +0100 Subject: Fix the actual_bind versions for integrals --- src/database/query.cpp | 12 +----------- src/database/query.hpp | 9 ++++++--- 2 files changed, 7 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/database/query.cpp b/src/database/query.cpp index 9611c97..d72066e 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -6,7 +6,7 @@ void actual_bind(Statement& statement, const std::string& value, int index) statement.bind_text(index, value); } -void actual_bind(Statement& statement, const std::int64_t value, int index) +void actual_bind(Statement& statement, const std::int64_t& value, int index) { statement.bind_int64(index, value); } @@ -21,16 +21,6 @@ void actual_bind(Statement& statement, const OptionalBool& value, int index) statement.bind_int64(index, -1); } -void actual_bind(Statement& statement, const std::size_t value, int index) -{ - actual_bind(statement, static_cast(value), index); -} - -void actual_bind(Statement& statement, const int value, int index) -{ - actual_bind(statement, static_cast(value), index); -} - void actual_add_param(Query& query, const std::string& val) { query.params.push_back(val); diff --git a/src/database/query.hpp b/src/database/query.hpp index 25c3a62..ba28b1a 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -12,9 +12,12 @@ #include void actual_bind(Statement& statement, const std::string& value, int index); -void actual_bind(Statement& statement, const std::int64_t value, int index); -void actual_bind(Statement& statement, const std::size_t value, int index); -void actual_bind(Statement& statement, const int value, int index); +void actual_bind(Statement& statement, const std::int64_t& value, int index); +template ::value>* = 0> +void actual_bind(Statement& statement, const T& value, int index) +{ + actual_bind(statement, static_cast(value), index); +} void actual_bind(Statement& statement, const OptionalBool& value, int index); #ifdef DEBUG_SQL_QUERIES -- cgit v1.2.3 From d3e07eee1335822643d7086b95590b60a4e002c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 16 Feb 2018 00:56:07 +0100 Subject: Sort archive messages by date (and only then by id) fix #3337 Because apparently the IDs are not always incrementing. We still use them to know the order of two messages that were received at the same second (in this case, the ID will always be incrementing). --- src/database/database.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/database/database.cpp b/src/database/database.cpp index b2413d0..d19ed7a 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -197,11 +197,10 @@ std::vector Database::get_muc_logs(const std::string& owne request << reference_record_id; } - request.order_by() << Id{}; if (paging == Database::Paging::first) - request << " ASC "; + request.order_by() << Database::Date{} << " ASC, " << Id{} << " ASC "; else - request << " DESC "; + request.order_by() << Database::Date{} << " DESC, " << Id{} << " DESC "; if (limit >= 0) request.limit() << limit; -- cgit v1.2.3 From b1750843008b7928c72699c592776fb56c66ec26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 16 Feb 2018 00:57:49 +0100 Subject: Log the warn/error messages coming from libpq in a correct format --- src/database/postgresql_engine.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src') diff --git a/src/database/postgresql_engine.cpp b/src/database/postgresql_engine.cpp index 518c23a..59bc885 100644 --- a/src/database/postgresql_engine.cpp +++ b/src/database/postgresql_engine.cpp @@ -11,6 +11,8 @@ #include +#include + PostgresqlEngine::PostgresqlEngine(PGconn*const conn): conn(conn) {} @@ -20,6 +22,15 @@ PostgresqlEngine::~PostgresqlEngine() PQfinish(this->conn); } +static void logging_notice_processor(void*, const char* original) +{ + if (original && std::strlen(original) > 0) + { + std::string message{original, std::strlen(original) - 1}; + log_warning("PostgreSQL: ", message); + } +} + std::unique_ptr PostgresqlEngine::open(const std::string& conninfo) { PGconn* con = PQconnectdb(conninfo.data()); @@ -37,6 +48,7 @@ std::unique_ptr PostgresqlEngine::open(const std::string& connin PQfinish(con); throw std::runtime_error("failed to open connection."); } + PQsetNoticeProcessor(con, &logging_notice_processor, nullptr); return std::make_unique(con); } -- cgit v1.2.3 From 8503d1f6831fc8522a16e0670578d1157d23e116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 16 Feb 2018 00:58:49 +0100 Subject: Actually display the error message from postgresql when a query failed --- src/database/postgresql_statement.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/database/postgresql_statement.hpp b/src/database/postgresql_statement.hpp index 571c8f1..5665aed 100644 --- a/src/database/postgresql_statement.hpp +++ b/src/database/postgresql_statement.hpp @@ -6,6 +6,8 @@ #include +#include + class PostgresqlStatement: public Statement { public: @@ -108,7 +110,9 @@ private: const auto status = PQresultStatus(this->result); if (status != PGRES_TUPLES_OK && status != PGRES_COMMAND_OK) { - log_error("Failed to execute command: ", PQresultErrorMessage(this->result)); + const char* original = PQerrorMessage(this->conn); + if (original && std::strlen(original) > 0) + log_error("Failed to execute command: ", std::string{original, std::strlen(original) - 1}); return false; } return true; -- cgit v1.2.3 From 158d743bf539399e48c64044639b90e5c1705ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 4 Mar 2018 22:18:58 +0100 Subject: Remove the virtual channel feature altogether --- src/bridge/bridge.cpp | 39 +------------------------------- src/irc/irc_channel.cpp | 6 ----- src/irc/irc_channel.hpp | 30 ------------------------- src/irc/irc_client.cpp | 51 ++---------------------------------------- src/irc/irc_client.hpp | 14 ------------ src/xmpp/biboumi_component.cpp | 3 +-- 6 files changed, 4 insertions(+), 139 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index fefab40..cd3492f 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -63,7 +63,6 @@ void Bridge::shutdown(const std::string& exit_message) for (auto& pair: this->irc_clients) { pair.second->send_quit_command(exit_message); - pair.second->leave_dummy_channel(exit_message, {}); } } @@ -176,35 +175,6 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const auto res_in_chan = this->is_resource_in_chan(ChannelKey{iid.get_local(), hostname}, resource); if (!res_in_chan) this->add_resource_to_chan(ChannelKey{iid.get_local(), hostname}, resource); - if (iid.get_local().empty()) - { // Join the dummy channel - if (irc->is_welcomed()) - { - if (res_in_chan) - return false; - // Immediately simulate a message coming from the IRC server saying that we - // joined the channel - if (irc->get_dummy_channel().joined) - { - this->generate_channel_join_for_resource(iid, resource); - } - else - { - const IrcMessage join_message(irc->get_nick(), "JOIN", {""}); - irc->on_channel_join(join_message); - const IrcMessage end_join_message(std::string(iid.get_server()), "366", - {irc->get_nick(), - "", "End of NAMES list"}); - irc->on_channel_completely_joined(end_join_message); - } - } - else - { - irc->get_dummy_channel().joining = true; - irc->start(); - } - return true; - } if (irc->is_channel_joined(iid.get_local()) == false) { irc->send_join_command(iid.get_local(), password); @@ -445,11 +415,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con #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 if (channel->joined) { @@ -1254,9 +1220,6 @@ std::size_t Bridge::number_of_channels_the_resource_is_in(const std::string& irc res++; } - IrcClient* irc = this->find_irc_client(irc_hostname); - if (irc && (irc->get_dummy_channel().joined || irc->get_dummy_channel().joining)) - res++; return res; } diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 53043c7..1fd34aa 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -58,9 +58,3 @@ void IrcChannel::remove_all_users() this->users.clear(); this->self = nullptr; } - -DummyIrcChannel::DummyIrcChannel(): - IrcChannel(), - joining(false) -{ -} diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index 8f85edb..dff1b78 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -42,33 +42,3 @@ protected: IrcUser* self{nullptr}; std::vector> users{}; }; - -/** - * A special channel that is not actually linked to any real irc - * channel. This is just a channel representing a connection to the - * server. If an user wants to maintain the connection to the server without - * having to be on any irc channel of that server, he can just join this - * dummy channel. - * It’s not actually dummy because it’s useful and it does things, but well. - */ -class DummyIrcChannel: public IrcChannel -{ -public: - explicit DummyIrcChannel(); - DummyIrcChannel(const DummyIrcChannel&) = delete; - DummyIrcChannel(DummyIrcChannel&&) = delete; - DummyIrcChannel& operator=(const DummyIrcChannel&) = delete; - DummyIrcChannel& operator=(DummyIrcChannel&&) = delete; - - /** - * This flag is at true whenever the user wants to join this channel, but - * he is not yet connected to the server. When the connection is made, we - * check that flag and if it’s true, we inform the user that he has just - * joined that channel. - * If the user is already connected to the server when he tries to join - * the channel, we don’t use that flag, we just join it immediately. - */ - bool joining; -}; - - diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 40078d9..a866726 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -145,14 +145,6 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, chanmodes({"", "", "", ""}), chantypes({'#', '&'}) { - this->dummy_channel.topic = "This is a virtual channel provided for " - "convenience by biboumi, it is not connected " - "to any actual IRC channel of the server '" + this->hostname + - "', and sending messages in it has no effect. " - "Its main goal is to keep the connection to the IRC server " - "alive without having to join a real channel of that server. " - "To disconnect from the IRC server, leave this room and all " - "other IRC channels of that server."; #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); @@ -315,8 +307,6 @@ void IrcClient::on_connection_close(const std::string& error_msg) IrcChannel* IrcClient::get_channel(const std::string& n) { - if (n.empty()) - return &this->dummy_channel; const std::string name = utils::tolower(n); try { @@ -670,10 +660,7 @@ void IrcClient::on_channel_join(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[0]); IrcChannel* channel; - if (chan_name.empty()) - channel = &this->dummy_channel; - else - channel = this->get_channel(chan_name); + channel = this->get_channel(chan_name); const std::string nick = message.prefix; IrcUser* user = channel->add_user(nick, this->prefix_to_mode); if (channel->joined == false) @@ -948,18 +935,6 @@ void IrcClient::on_welcome_message(const IrcMessage& message) if (!channels_with_key.empty()) this->send_join_command(channels_with_key, keys); this->channels_to_join.clear(); - // Indicate that the dummy channel is joined as well, if needed - if (this->dummy_channel.joining) - { - // Simulate a message coming from the IRC server saying that we joined - // the channel - const IrcMessage join_message(this->get_nick(), "JOIN", {""}); - this->on_channel_join(join_message); - const IrcMessage end_join_message(std::string(this->hostname), "366", - {this->get_nick(), - "", "End of NAMES list"}); - this->on_channel_completely_joined(end_join_message); - } } void IrcClient::on_part(const IrcMessage& message) @@ -1062,10 +1037,6 @@ void IrcClient::on_nick(const IrcMessage& message) } }; - if (this->get_dummy_channel().joined) - { - change_nick_func("", &this->get_dummy_channel()); - } for (const auto& pair: this->channels) { change_nick_func(pair.first, pair.second.get()); @@ -1248,25 +1219,7 @@ void IrcClient::on_unknown_message(const IrcMessage& message) size_t IrcClient::number_of_joined_channels() const { - if (this->dummy_channel.joined) - return this->channels.size() + 1; - else - return this->channels.size(); -} - -DummyIrcChannel& IrcClient::get_dummy_channel() -{ - return this->dummy_channel; -} - -void IrcClient::leave_dummy_channel(const std::string& exit_message, const std::string& resource) -{ - if (!this->dummy_channel.joined) - return; - this->dummy_channel.joined = false; - this->dummy_channel.joining = false; - this->dummy_channel.remove_all_users(); - this->bridge.send_muc_leave(Iid("%" + this->hostname, this->chantypes), std::string(this->current_nick), exit_message, true, true, resource); + return this->channels.size(); } #ifdef BOTAN_FOUND diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index de5c520..fd97fe6 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -279,15 +279,6 @@ public: * Return the number of joined channels */ size_t number_of_joined_channels() const; - /** - * Get a reference to the unique dummy channel - */ - DummyIrcChannel& get_dummy_channel(); - /** - * Leave the dummy channel: forward a message to the user to indicate that - * he left it, and mark it as not joined. - */ - void leave_dummy_channel(const std::string& exit_message, const std::string& resource); const std::string& get_hostname() const { return this->hostname; } std::string get_nick() const { return this->current_nick; } @@ -339,11 +330,6 @@ private: * The list of joined channels, indexed by name */ std::unordered_map> channels; - /** - * A single channel with a iid of the form "hostname" (normal channel have - * an iid of the form "chan%hostname". - */ - DummyIrcChannel dummy_channel; /** * A list of chan we want to join (tuples with the channel name and the * password, if any), but we need a response 001 from the server before diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index fe6cc1b..891b715 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -148,8 +148,7 @@ void BiboumiComponent::handle_presence(const Stanza& stanza) try { if (iid.type == Iid::Type::Channel && !iid.get_server().empty()) - { // presence toward a MUC that corresponds to an irc channel, or a - // dummy channel if iid.chan is empty + { // presence toward a MUC that corresponds to an irc channel if (type.empty()) { const std::string own_nick = bridge->get_own_nick(iid); -- cgit v1.2.3 From bb596582bd2d8b9aab3fe08e76a7d24d82bf614a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 00:04:26 +0100 Subject: Add a node in the presence of a leaving participant fix #3339 --- src/bridge/bridge.cpp | 24 +++++++++++++++++------- src/bridge/bridge.hpp | 2 +- src/irc/irc_channel.cpp | 5 ++++- src/irc/irc_channel.hpp | 2 +- src/irc/irc_client.cpp | 17 ++++++++--------- src/xmpp/xmpp_component.cpp | 6 +++++- src/xmpp/xmpp_component.hpp | 3 ++- 7 files changed, 38 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index cd3492f..9269bb7 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -419,7 +419,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con } else if (channel->joined) { - this->send_muc_leave(iid, channel->get_self()->nick, "", true, true, resource); + this->send_muc_leave(iid, *channel->get_self(), "", true, true, resource); } if (persistent) this->remove_resource_from_chan(key, resource); @@ -430,7 +430,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con else { if (channel && channel->joined) - this->send_muc_leave(iid, channel->get_self()->nick, + this->send_muc_leave(iid, *channel->get_self(), "Biboumi note: " + std::to_string(resources - 1) + " resources are still in this channel.", true, true, resource); this->remove_resource_from_chan(key, resource); @@ -847,19 +847,29 @@ void Bridge::send_presence_error(const Iid& iid, const std::string& nick, this->xmpp.send_presence_error(std::to_string(iid), nick, this->user_jid, type, condition, error_code, text); } -void Bridge::send_muc_leave(const Iid& iid, const std::string& nick, +void Bridge::send_muc_leave(const Iid& iid, const IrcUser& user, const std::string& message, const bool self, const bool user_requested, const std::string& resource) { + const IrcClient* client = this->find_irc_client(iid.get_server()); + if (!client) + { + log_error("Tried to send an unavailable presence for non existant client: ", std::to_string(iid)); + return; + } + std::string affiliation; + std::string role; + std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user.get_most_significant_mode(client->get_sorted_user_modes())); + if (!resource.empty()) - this->xmpp.send_muc_leave(std::to_string(iid), nick, this->make_xmpp_body(message), - this->user_jid + "/" + resource, self, user_requested); + this->xmpp.send_muc_leave(std::to_string(iid), user.nick, this->make_xmpp_body(message), + this->user_jid + "/" + resource, self, user_requested, affiliation, role); else { for (const auto &res: this->resources_in_chan[iid.to_tuple()]) - this->xmpp.send_muc_leave(std::to_string(iid), nick, this->make_xmpp_body(message), - this->user_jid + "/" + res, self, user_requested); + this->xmpp.send_muc_leave(std::to_string(iid), user.nick, this->make_xmpp_body(message), + this->user_jid + "/" + res, self, user_requested, affiliation, role); if (self) { // Copy the resources currently in that channel diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index c2f0233..44df4c2 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -170,7 +170,7 @@ public: /** * Send an unavailable presence from this participant */ - void send_muc_leave(const Iid& iid, const std::string& nick, + void send_muc_leave(const Iid& iid, const IrcUser& nick, const std::string& message, const bool self, const bool user_requested, const std::string& resource=""); diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 1fd34aa..58f8d5c 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -33,8 +33,9 @@ IrcUser* IrcChannel::find_user(const std::string& name) const return nullptr; } -void IrcChannel::remove_user(const IrcUser* user) +std::unique_ptr IrcChannel::remove_user(const IrcUser* user) { + std::unique_ptr result{}; const auto nick = user->nick; const bool is_self = (user == this->self); const auto it = std::find_if(this->users.begin(), this->users.end(), @@ -44,6 +45,7 @@ void IrcChannel::remove_user(const IrcUser* user) }); if (it != this->users.end()) { + result = std::move(*it); this->users.erase(it); if (is_self) { @@ -57,4 +59,5 @@ void IrcChannel::remove_all_users() { this->users.clear(); this->self = nullptr; + return result; } diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index dff1b78..ee89209 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -32,8 +32,8 @@ public: IrcUser* add_user(const std::string& name, const std::map& prefix_to_mode); IrcUser* find_user(const std::string& name) const; - void remove_user(const IrcUser* user); void remove_all_users(); + std::unique_ptr remove_user(const IrcUser* user); const std::vector>& get_users() const { return this->users; } diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index a866726..c5ef36c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -951,18 +951,18 @@ void IrcClient::on_part(const IrcMessage& message) { std::string nick = user->nick; bool self = channel->get_self() && channel->get_self()->nick == nick; - channel->remove_user(user); - Iid iid; - iid.set_local(chan_name); - iid.set_server(this->hostname); - iid.type = Iid::Type::Channel; + auto user_ptr = channel->remove_user(user); if (self) { this->channels.erase(utils::tolower(chan_name)); // channel pointer is now invalid channel = nullptr; } - this->bridge.send_muc_leave(iid, std::move(nick), txt, self, true); + Iid iid; + iid.set_local(chan_name); + iid.set_server(this->hostname); + iid.type = Iid::Type::Channel; + this->bridge.send_muc_leave(iid, *user_ptr, txt, self, true); } } @@ -979,8 +979,7 @@ void IrcClient::on_error(const IrcMessage& message) IrcChannel* channel = pair.second.get(); if (!channel->joined) continue; - std::string own_nick = channel->get_self()->nick; - this->bridge.send_muc_leave(iid, std::move(own_nick), leave_message, true, false); + this->bridge.send_muc_leave(iid, *channel->get_self(), leave_message, true, false); } this->channels.clear(); this->send_gateway_message("ERROR: " + leave_message); @@ -1005,7 +1004,7 @@ void IrcClient::on_quit(const IrcMessage& message) iid.set_local(chan_name); iid.set_server(this->hostname); iid.type = Iid::Type::Channel; - this->bridge.send_muc_leave(iid, user->nick, txt, self, false); + this->bridge.send_muc_leave(iid, *user, txt, self, false); channel->remove_user(user); } } diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index 9be9e34..a71d810 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -425,7 +425,8 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std: #endif 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) + const std::string& jid_to, const bool self, const bool user_requested, + const std::string& affiliation, const std::string& role) { Stanza presence("presence"); { @@ -447,6 +448,9 @@ void XmppComponent::send_muc_leave(const std::string& muc_name, const std::strin status["code"] = "332"; } } + XmlSubNode item(x, "item"); + item["affiliation"] = affiliation; + item["role"] = role; if (!message_str.empty()) { XmlSubNode status(presence, "status"); diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index 1daa6fb..06cc6ff 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -150,7 +150,8 @@ public: Xmpp::body&& message, const std::string& jid_to, const bool self, - const bool user_requested); + const bool user_requested, + const std::string& affiliation, const std::string& role); /** * Indicate that a participant changed his nick */ -- cgit v1.2.3 From 9e4a3e2b054ee4604b6a42c73895216c68fa96e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 00:17:03 +0100 Subject: =?UTF-8?q?Fix=20the=20INSERT=20query=20for=20types=20that=20don?= =?UTF-8?q?=E2=80=99t=20have=20any=20Id=20column?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/database/row.hpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/database/row.hpp b/src/database/row.hpp index 4dc98be..3703ff7 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -50,7 +50,8 @@ struct Row } private: - void insert(DatabaseEngine& db) + template + void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) { InsertQuery query(this->table_name, this->columns); // Ugly workaround for non portable stuff @@ -58,6 +59,13 @@ struct Row query.execute(db, this->columns); } + template + void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) + { + InsertQuery query(this->table_name, this->columns); + query.execute(db, this->columns); + } + void update(DatabaseEngine& db) { UpdateQuery query(this->table_name, this->columns); -- cgit v1.2.3 From bb476f4a0d60bbc41393a86a370aa94ab405b081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 01:00:17 +0100 Subject: Allow to override the addresses used to connect to an IRC network fix #3273 --- src/database/database.hpp | 3 ++- src/irc/irc_client.cpp | 16 +++++++++------- src/xmpp/biboumi_adhoc_commands.cpp | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index ce7595b..79b16d6 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -84,6 +84,7 @@ class Database struct RemoteJid: Column { static constexpr auto name = "remote"; }; + struct Address: Column { static constexpr auto name = "hostname_"; }; using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; @@ -91,7 +92,7 @@ class Database using GlobalOptionsTable = Table; using GlobalOptions = GlobalOptionsTable::RowType; - using IrcServerOptionsTable = Table; + using IrcServerOptionsTable = Table; using IrcServerOptions = IrcServerOptionsTable::RowType; using IrcChannelOptionsTable = Table; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index c5ef36c..764f37b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -186,20 +186,22 @@ void IrcClient::start() bool tls; std::tie(port, tls) = this->ports_to_try.top(); this->ports_to_try.pop(); - this->bridge.send_xmpp_message(this->hostname, "", "Connecting to " + - this->hostname + ":" + port + " (" + - (tls ? "encrypted" : "not encrypted") + ")"); - this->bind_addr = Config::get("outgoing_bind", ""); + std::string address = this->hostname; -#ifdef BOTAN_FOUND -# ifdef USE_DATABASE +#ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); +# ifdef BOTAN_FOUND this->credential_manager.set_trusted_fingerprint(options.col()); # endif + if (!options.col().empty()) + address = options.col(); #endif - this->connect(this->hostname, port, tls); + this->bridge.send_xmpp_message(this->hostname, "", "Connecting to " + + address + ":" + port + " (" + + (tls ? "encrypted" : "not encrypted") + ")"); + this->connect(address, port, tls); } void IrcClient::on_connection_failed(const std::string& reason) diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index bcdac39..0a25bd4 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -227,6 +227,19 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com XmlSubNode instructions(x, "instructions"); instructions.set_inner("Edit the form, to configure the settings of the IRC server " + server_domain); + { + XmlSubNode hostname(x, "field"); + hostname["var"] = "hostname"; + hostname["type"] = "text-single"; + hostname["label"] = "Address"; + hostname["desc"] = "The hostname (or IP) to connect to."; + XmlSubNode value(hostname, "value"); + if (options.col().empty()) + value.set_inner(server_domain); + else + value.set_inner(options.col()); + } + { XmlSubNode ports(x, "field"); ports["var"] = "ports"; @@ -375,6 +388,11 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com { const XmlNode* value = field->get_child("value", "jabber:x:data"); const std::vector values = field->get_children("value", "jabber:x:data"); + + if (field->get_tag("var") == "hostname") + { + options.col() = value->get_inner(); + } if (field->get_tag("var") == "ports") { std::string ports; -- cgit v1.2.3 From b3b90139dbb0a09988477fdab4f19d717ac05cab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 01:06:15 +0100 Subject: =?UTF-8?q?Rename=20a=20few=20=E2=80=9Chostname=E2=80=9D=20into=20?= =?UTF-8?q?=E2=80=9Caddress=E2=80=9D,=20regarding=20last=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #3273 --- src/database/database.hpp | 2 +- src/xmpp/biboumi_adhoc_commands.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index 79b16d6..8a967d8 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -84,7 +84,7 @@ class Database struct RemoteJid: Column { static constexpr auto name = "remote"; }; - struct Address: Column { static constexpr auto name = "hostname_"; }; + struct Address: Column { static constexpr auto name = "address_"; }; using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 0a25bd4..942d98d 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -228,12 +228,12 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com instructions.set_inner("Edit the form, to configure the settings of the IRC server " + server_domain); { - XmlSubNode hostname(x, "field"); - hostname["var"] = "hostname"; - hostname["type"] = "text-single"; - hostname["label"] = "Address"; - hostname["desc"] = "The hostname (or IP) to connect to."; - XmlSubNode value(hostname, "value"); + XmlSubNode field(x, "field"); + field["var"] = "hostname"; + field["type"] = "text-single"; + field["label"] = "Address"; + field["desc"] = "The address (hostname or IP) to connect to."; + XmlSubNode value(field, "value"); if (options.col().empty()) value.set_inner(server_domain); else @@ -389,7 +389,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com const XmlNode* value = field->get_child("value", "jabber:x:data"); const std::vector values = field->get_children("value", "jabber:x:data"); - if (field->get_tag("var") == "hostname") + if (field->get_tag("var") == "address") { options.col() = value->get_inner(); } -- cgit v1.2.3 From b4a01758b02c4bb022d7a8cf7981de0e0cbc6ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 01:10:54 +0100 Subject: And this one (hostname -> address) ref #3273 --- src/xmpp/biboumi_adhoc_commands.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 942d98d..38b6165 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -229,7 +229,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com { XmlSubNode field(x, "field"); - field["var"] = "hostname"; + field["var"] = "address"; field["type"] = "text-single"; field["label"] = "Address"; field["desc"] = "The address (hostname or IP) to connect to."; -- cgit v1.2.3 From 06438fe8ecf5eea62456e6da41c13bad916664fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 12 Mar 2018 01:34:10 +0100 Subject: Remove an unused function --- src/irc/irc_channel.cpp | 6 ------ src/irc/irc_channel.hpp | 1 - 2 files changed, 7 deletions(-) (limited to 'src') diff --git a/src/irc/irc_channel.cpp b/src/irc/irc_channel.cpp index 58f8d5c..2dd20fe 100644 --- a/src/irc/irc_channel.cpp +++ b/src/irc/irc_channel.cpp @@ -53,11 +53,5 @@ std::unique_ptr IrcChannel::remove_user(const IrcUser* user) this->joined = false; } } -} - -void IrcChannel::remove_all_users() -{ - this->users.clear(); - this->self = nullptr; return result; } diff --git a/src/irc/irc_channel.hpp b/src/irc/irc_channel.hpp index ee89209..7000ada 100644 --- a/src/irc/irc_channel.hpp +++ b/src/irc/irc_channel.hpp @@ -32,7 +32,6 @@ public: IrcUser* add_user(const std::string& name, const std::map& prefix_to_mode); IrcUser* find_user(const std::string& name) const; - void remove_all_users(); std::unique_ptr remove_user(const IrcUser* user); const std::vector>& get_users() const { return this->users; } -- cgit v1.2.3 From cf618d55723e645cfe7865b8a55ec718b1ddd2bb Mon Sep 17 00:00:00 2001 From: Ailin Nemui Date: Tue, 13 Mar 2018 11:25:50 +0100 Subject: optional identd --- src/main.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index c877e43..c2b5431 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -135,7 +135,9 @@ int main(int ac, char** av) std::make_shared(p, hostname, password); xmpp_component->start(); - IdentdServer identd(*xmpp_component, p, static_cast(Config::get_int("identd_port", 113))); + std::unique_ptr identd; + if (Config::get_int("identd_port", 113) != 0) + identd = std::make_unique(*xmpp_component, p, static_cast(Config::get_int("identd_port", 113))); auto timeout = TimedEventsManager::instance().get_timeout(); while (p->poll(timeout) != -1) @@ -144,7 +146,7 @@ int main(int ac, char** av) // Check for empty irc_clients (not connected, or with no joined // channel) and remove them xmpp_component->clean(); - identd.clean(); + if (identd) identd->clean(); if (stop) { log_info("Signal received, exiting..."); @@ -157,7 +159,7 @@ int main(int ac, char** av) #ifdef UDNS_FOUND dns_handler.destroy(); #endif - identd.shutdown(); + if (identd) identd->shutdown(); // Cancel the timer for a potential reconnection TimedEventsManager::instance().cancel("XMPP reconnection"); } @@ -199,7 +201,7 @@ int main(int ac, char** av) #ifdef UDNS_FOUND dns_handler.destroy(); #endif - identd.shutdown(); + if (identd) identd->shutdown(); } } // If the only existing connection is the one to the XMPP component: -- cgit v1.2.3 From 5ea51fea1b4efadbf3d3ec26dbef930280e7275c Mon Sep 17 00:00:00 2001 From: Ailin Nemui Date: Thu, 15 Mar 2018 10:18:15 +0100 Subject: follow coding style --- src/main.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index c2b5431..59fda4e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -146,7 +146,8 @@ int main(int ac, char** av) // Check for empty irc_clients (not connected, or with no joined // channel) and remove them xmpp_component->clean(); - if (identd) identd->clean(); + if (identd) + identd->clean(); if (stop) { log_info("Signal received, exiting..."); @@ -159,7 +160,8 @@ int main(int ac, char** av) #ifdef UDNS_FOUND dns_handler.destroy(); #endif - if (identd) identd->shutdown(); + if (identd) + identd->shutdown(); // Cancel the timer for a potential reconnection TimedEventsManager::instance().cancel("XMPP reconnection"); } @@ -201,7 +203,8 @@ int main(int ac, char** av) #ifdef UDNS_FOUND dns_handler.destroy(); #endif - if (identd) identd->shutdown(); + if (identd) + identd->shutdown(); } } // If the only existing connection is the one to the XMPP component: -- cgit v1.2.3 From ba879a882e031d7b8503f78fe41d1210000c96ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 16 Mar 2018 00:53:47 +0100 Subject: Use std::optional instead of OptionalBool --- src/database/database.hpp | 2 +- src/database/query.cpp | 12 +++++----- src/database/query.hpp | 4 ++-- src/database/select_query.hpp | 9 ++++--- src/utils/optional_bool.cpp | 4 ++-- src/utils/optional_bool.hpp | 48 +++++++++++++------------------------ src/xmpp/biboumi_adhoc_commands.cpp | 14 +++++------ 7 files changed, 38 insertions(+), 55 deletions(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index 8a967d8..03d82ae 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -69,7 +69,7 @@ class Database struct RecordHistory: Column { static constexpr auto name = "recordhistory_"; RecordHistory(): Column(true) {}}; - struct RecordHistoryOptional: Column { static constexpr auto name = "recordhistory_"; }; + struct RecordHistoryOptional: Column> { static constexpr auto name = "recordhistory_"; }; struct VerifyCert: Column { static constexpr auto name = "verifycert_"; VerifyCert(): Column(true) {} }; diff --git a/src/database/query.cpp b/src/database/query.cpp index d72066e..13c881b 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -11,11 +11,11 @@ void actual_bind(Statement& statement, const std::int64_t& value, int index) statement.bind_int64(index, value); } -void actual_bind(Statement& statement, const OptionalBool& value, int index) +void actual_bind(Statement& statement, const std::optional& value, int index) { - if (!value.is_set) + if (!value) statement.bind_int64(index, 0); - else if (value.value) + else if (*value) statement.bind_int64(index, 1); else statement.bind_int64(index, -1); @@ -26,11 +26,11 @@ void actual_add_param(Query& query, const std::string& val) query.params.push_back(val); } -void actual_add_param(Query& query, const OptionalBool& val) +void actual_add_param(Query& query, const std::optional& val) { - if (!val.is_set) + if (!val) query.params.push_back("0"); - else if (val.value) + else if (*val) query.params.push_back("1"); else query.params.push_back("-1"); diff --git a/src/database/query.hpp b/src/database/query.hpp index ba28b1a..1c4a5ff 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -18,7 +18,7 @@ void actual_bind(Statement& statement, const T& value, int index) { actual_bind(statement, static_cast(value), index); } -void actual_bind(Statement& statement, const OptionalBool& value, int index); +void actual_bind(Statement& statement, const std::optional& value, int index); #ifdef DEBUG_SQL_QUERIES #include @@ -71,7 +71,6 @@ void actual_add_param(Query& query, const T& val) } void actual_add_param(Query& query, const std::string& val); -void actual_add_param(Query& query, const OptionalBool& val); template typename std::enable_if::value, Query&>::type @@ -80,6 +79,7 @@ operator<<(Query& query, const T&) query.body += T::name; return query; } +void actual_add_param(Query& query, const std::optional& val); Query& operator<<(Query& query, const char* str); Query& operator<<(Query& query, const std::string& str); diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 5a17f38..cd9943c 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -29,16 +29,15 @@ extract_row_value(Statement& statement, const int i) } template -typename std::enable_if::value, T>::type +typename std::enable_if, T>::value, T>::type extract_row_value(Statement& statement, const int i) { const auto integer = statement.get_column_int(i); - OptionalBool result; if (integer > 0) - result.set_value(true); + return true; else if (integer < 0) - result.set_value(false); - return result; + return false; + return std::nullopt; } template diff --git a/src/utils/optional_bool.cpp b/src/utils/optional_bool.cpp index 56fdca2..1d1c375 100644 --- a/src/utils/optional_bool.cpp +++ b/src/utils/optional_bool.cpp @@ -1,8 +1,8 @@ #include -std::ostream& operator<<(std::ostream& os, const OptionalBool& o) +std::ostream& operator<<(std::ostream& os, const std::optional& o) { - os << o.to_string(); + os << std::to_string(o); return os; } diff --git a/src/utils/optional_bool.hpp b/src/utils/optional_bool.hpp index 867aca2..c652ed3 100644 --- a/src/utils/optional_bool.hpp +++ b/src/utils/optional_bool.hpp @@ -1,37 +1,21 @@ #pragma once +#include + #include -struct OptionalBool +namespace std { - OptionalBool() = default; - - OptionalBool(bool value): - is_set(true), value(value) {} - - void set_value(bool value) - { - this->is_set = true; - this->value = value; - } - - void unset() - { - this->is_set = false; - } - - std::string to_string() const - { - if (this->is_set == false) - return "unset"; - else if (this->value) - return "true"; - else - return "false"; - } - - bool is_set{false}; - bool value{false}; -}; - -std::ostream& operator<<(std::ostream& os, const OptionalBool& o); +inline +std::string to_string(const std::optional b) +{ + if (!b) + return "unset"; + else if (*b) + return "true"; + else + return "false"; +} +} + +std::ostream& operator<<(std::ostream& os, const std::optional& o); diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 38b6165..53ec98b 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -493,7 +493,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, { // Value selected by default XmlSubNode value(record_history, "value"); - value.set_inner(options.col().to_string()); + value.set_inner(std::to_string(options.col())); } // All three possible values for (const auto& val: {"unset", "true", "false"}) @@ -594,19 +594,19 @@ bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const else if (field->get_tag("var") == "record_history" && value && !value->get_inner().empty()) { - OptionalBool& database_value = options.col(); + std::optional& database_value = options.col(); if (value->get_inner() == "true") - database_value.set_value(true); + database_value = true; else if (value->get_inner() == "false") - database_value.set_value(false); + database_value = false; else - database_value.unset(); + database_value.reset(); 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); + if (database_value) + bridge->set_record_history(*database_value); else { // It is unset, we need to fetch the Global option, to // know if it’s enabled or not -- cgit v1.2.3 From d62ca9f87906be6f046fe9d07afb8bfb69c166e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 16 Mar 2018 01:11:47 +0100 Subject: Use if constexpr to make things a lot more readable --- src/database/index.hpp | 21 +++++----- src/database/insert_query.hpp | 91 +++++++++++++++++++------------------------ src/database/query.hpp | 41 +++++++------------ src/database/row.hpp | 52 ++++++++++++------------- src/database/select_query.hpp | 77 +++++++++++++++--------------------- src/database/table.hpp | 44 ++++++++++----------- src/database/update_query.hpp | 51 +++++++++++------------- 7 files changed, 164 insertions(+), 213 deletions(-) (limited to 'src') diff --git a/src/database/index.hpp b/src/database/index.hpp index 30766ab..094a36a 100644 --- a/src/database/index.hpp +++ b/src/database/index.hpp @@ -8,19 +8,16 @@ namespace { template -typename std::enable_if::type -add_column_name(std::string&) -{ } - -template -typename std::enable_if::type -add_column_name(std::string& out) +void add_column_name(std::string& out) { - using ColumnType = typename std::remove_reference(std::declval>()))>::type; - out += ColumnType::name; - if (N != sizeof...(T) - 1) - out += ","; - add_column_name(out); + if constexpr(N < sizeof...(T)) + { + using ColumnType = typename std::remove_reference(std::declval>()))>::type; + out += ColumnType::name; + if (N != sizeof...(T) - 1) + out += ","; + add_column_name(out); + } } } diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 04c098c..ed1944f 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -11,20 +11,17 @@ #include template -typename std::enable_if::type -update_autoincrement_id(std::tuple& columns, Statement& statement) +void update_autoincrement_id(std::tuple& columns, Statement& statement) { - using ColumnType = typename std::decay(columns))>::type; - if (std::is_same::value) - auto&& column = std::get(columns); - update_autoincrement_id(columns, statement); + if constexpr(N < sizeof...(T)) + { + using ColumnType = typename std::decay(columns))>::type; + if (std::is_same::value) + auto&& column = std::get(columns); + update_autoincrement_id(columns, statement); + } } -template -typename std::enable_if::type -update_autoincrement_id(std::tuple&, Statement&) -{} - struct InsertQuery: public Query { template @@ -53,23 +50,20 @@ struct InsertQuery: public Query } template - typename std::enable_if::type - bind_param(const std::tuple& columns, Statement& statement, int index=1) + void bind_param(const std::tuple& columns, Statement& statement, int index=1) { - auto&& column = std::get(columns); - using ColumnType = std::decay_t; + if constexpr(N < sizeof...(T)) + { + auto&& column = std::get(columns); + using ColumnType = std::decay_t; - if (!std::is_same::value) - actual_bind(statement, column.value, index++); + if constexpr(!std::is_same::value) + actual_bind(statement, column.value, index++); - this->bind_param(columns, statement, index); + this->bind_param(columns, statement, index); + } } - template - typename std::enable_if::type - bind_param(const std::tuple&, Statement&, int) - {} - template void insert_values(const std::tuple& columns) { @@ -79,23 +73,21 @@ struct InsertQuery: public Query } template - typename std::enable_if::type - insert_value(const std::tuple& columns, int index=1) + void insert_value(const std::tuple& columns, int index=1) { - using ColumnType = std::decay_t(columns))>; - - if (!std::is_same::value) + if constexpr(N < sizeof...(T)) { - this->body += "$" + std::to_string(index++); - if (N != sizeof...(T) - 1) - this->body += ", "; + using ColumnType = std::decay_t(columns))>; + + if (!std::is_same::value) + { + this->body += "$" + std::to_string(index++); + if (N != sizeof...(T) - 1) + this->body += ", "; + } + this->insert_value(columns, index); } - this->insert_value(columns, index); } - template - typename std::enable_if::type - insert_value(const std::tuple&, const int) - { } template void insert_col_names(const std::tuple& columns) @@ -106,24 +98,21 @@ struct InsertQuery: public Query } template - typename std::enable_if::type - insert_col_name(const std::tuple& columns) + void insert_col_name(const std::tuple& columns) { - using ColumnType = std::decay_t(columns))>; - - if (!std::is_same::value) + if constexpr(N < sizeof...(T)) { - this->body += ColumnType::name; + using ColumnType = std::decay_t(columns))>; - if (N < (sizeof...(T) - 1)) - this->body += ", "; - } + if (!std::is_same::value) + { + this->body += ColumnType::name; - this->insert_col_name(columns); - } + if (N < (sizeof...(T) - 1)) + this->body += ", "; + } - template - typename std::enable_if::type - insert_col_name(const std::tuple&) - {} + this->insert_col_name(columns); + } + } }; diff --git a/src/database/query.hpp b/src/database/query.hpp index 1c4a5ff..2a2d2d4 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -13,12 +13,12 @@ void actual_bind(Statement& statement, const std::string& value, int index); void actual_bind(Statement& statement, const std::int64_t& value, int index); -template ::value>* = 0> +void actual_bind(Statement& statement, const std::optional& value, int index); +template void actual_bind(Statement& statement, const T& value, int index) { actual_bind(statement, static_cast(value), index); } -void actual_bind(Statement& statement, const std::optional& value, int index); #ifdef DEBUG_SQL_QUERIES #include @@ -57,38 +57,27 @@ struct Query #endif }; -template -void add_param(Query& query, const ColumnType& column) -{ - std::cout << "add_param" << std::endl; - actual_add_param(query, column.value); -} - +void actual_add_param(Query& query, const std::string& val); +void actual_add_param(Query& query, const std::optional& val); template void actual_add_param(Query& query, const T& val) { query.params.push_back(std::to_string(val)); } -void actual_add_param(Query& query, const std::string& val); - -template -typename std::enable_if::value, Query&>::type -operator<<(Query& query, const T&) -{ - query.body += T::name; - return query; -} -void actual_add_param(Query& query, const std::optional& val); - Query& operator<<(Query& query, const char* str); Query& operator<<(Query& query, const std::string& str); -template -typename std::enable_if::value, Query&>::type -operator<<(Query& query, const Integer& i) +template +Query& operator<<(Query& query, const T& i) { - query.body += "$" + std::to_string(query.current_param++); - actual_add_param(query, i); + if constexpr(std::is_integral::value) + { + query.body += "$" + std::to_string(query.current_param++); + actual_add_param(query, i); + } + else + { + query.body += T::name; + } return query; } - diff --git a/src/database/row.hpp b/src/database/row.hpp index 3703ff7..194a9c5 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -29,41 +29,39 @@ struct Row return col.value; } - template - void save(std::unique_ptr& db, typename std::enable_if && Coucou>::type* = nullptr) + void save(std::unique_ptr& db) { - this->insert(*db); - } - - template - void save(std::unique_ptr& db, typename std::enable_if && Coucou>::type* = nullptr) - { - const Id& id = std::get(this->columns); - if (id.value == Id::unset_value) + if constexpr(is_one_of) { - this->insert(*db); - if (db->last_inserted_rowid >= 0) - std::get(this->columns).value = static_cast(db->last_inserted_rowid); + const Id& id = std::get(this->columns); + if (id.value == Id::unset_value) + { + this->insert(*db); + if (db->last_inserted_rowid >= 0) + std::get(this->columns).value = static_cast(db->last_inserted_rowid); + } + else + this->update(*db); } else - this->update(*db); + this->insert(*db); } private: - template - void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) - { - InsertQuery query(this->table_name, this->columns); - // Ugly workaround for non portable stuff - query.body += db.get_returning_id_sql_string(Id::name); - query.execute(db, this->columns); - } - - template - void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) + void insert(DatabaseEngine& db) { - InsertQuery query(this->table_name, this->columns); - query.execute(db, this->columns); + if constexpr(is_one_of) + { + InsertQuery query(this->table_name, this->columns); + // Ugly workaround for non portable stuff + query.body += db.get_returning_id_sql_string(Id::name); + query.execute(db, this->columns); + } + else + { + InsertQuery query(this->table_name, this->columns); + query.execute(db, this->columns); + } } void update(DatabaseEngine& db) diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index cd9943c..f7496a4 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -15,48 +15,37 @@ using namespace std::string_literals; template -typename std::enable_if::value, std::int64_t>::type -extract_row_value(Statement& statement, const int i) +auto extract_row_value(Statement& statement, const int i) { - return statement.get_column_int64(i); -} - -template -typename std::enable_if::value, T>::type -extract_row_value(Statement& statement, const int i) -{ - return statement.get_column_text(i); -} - -template -typename std::enable_if, T>::value, T>::type -extract_row_value(Statement& statement, const int i) -{ - const auto integer = statement.get_column_int(i); - if (integer > 0) - return true; - else if (integer < 0) - return false; - return std::nullopt; + if constexpr(std::is_integral::value) + return statement.get_column_int64(i); + else if constexpr (std::is_same::value) + return statement.get_column_text(i); + else if (std::is_same, T>::value) + { + const auto integer = statement.get_column_int(i); + if (integer > 0) + return std::optional{true}; + else if (integer < 0) + return std::optional{false}; + return std::optional{}; + } } template -typename std::enable_if::type -extract_row_values(Row& row, Statement& statement) +void extract_row_values(Row& row, Statement& statement) { - using ColumnType = typename std::remove_reference(row.columns))>::type; + if constexpr(N < sizeof...(T)) + { + using ColumnType = typename std::remove_reference(row.columns))>::type; - auto&& column = std::get(row.columns); - column.value = static_cast(extract_row_value(statement, N)); + auto&& column = std::get(row.columns); + column.value = static_cast(extract_row_value(statement, N)); - extract_row_values(row, statement); + extract_row_values(row, statement); + } } -template -typename std::enable_if::type -extract_row_values(Row&, Statement&) -{} - template struct SelectQuery: public Query { @@ -69,23 +58,21 @@ struct SelectQuery: public Query } template - typename std::enable_if::type - insert_col_name() + void insert_col_name() { - using ColumnsType = std::tuple; - using ColumnType = typename std::remove_reference(std::declval()))>::type; + if constexpr(N < sizeof...(T)) + { + using ColumnsType = std::tuple; + using ColumnType = typename std::remove_reference(std::declval()))>::type; - this->body += " " + std::string{ColumnType::name}; + this->body += " " + std::string{ColumnType::name}; - if (N < (sizeof...(T) - 1)) - this->body += ", "; + if (N < (sizeof...(T) - 1)) + this->body += ", "; - this->insert_col_name(); + this->insert_col_name(); + } } - template - typename std::enable_if::type - insert_col_name() - {} SelectQuery& where() { diff --git a/src/database/table.hpp b/src/database/table.hpp index 680e7cc..eb68418 100644 --- a/src/database/table.hpp +++ b/src/database/table.hpp @@ -93,36 +93,32 @@ class Table private: template - typename std::enable_if::type - add_column_if_not_exists(DatabaseEngine& db, const std::set& existing_columns) + void add_column_if_not_exists(DatabaseEngine& db, const std::set& existing_columns) { - using ColumnType = typename std::remove_reference(std::declval()))>::type; - if (existing_columns.count(ColumnType::name) == 0) - add_column_to_table(db, this->name); - add_column_if_not_exists(db, existing_columns); + if constexpr(N < sizeof...(T)) + { + using ColumnType = typename std::remove_reference(std::declval()))>::type; + if (existing_columns.count(ColumnType::name) == 0) + add_column_to_table(db, this->name); + add_column_if_not_exists(db, existing_columns); + } } - template - typename std::enable_if::type - add_column_if_not_exists(DatabaseEngine&, const std::set&) - {} template - typename std::enable_if::type - add_column_create(DatabaseEngine& db, std::string& str) + void add_column_create(DatabaseEngine& db, std::string& str) { - using ColumnType = typename std::remove_reference(std::declval()))>::type; - str += ColumnType::name; - str += " "; - str += ToSQLType(db); - if (N != sizeof...(T) - 1) - str += ","; - - add_column_create(db, str); + if constexpr(N < sizeof...(T)) + { + using ColumnType = typename std::remove_reference(std::declval()))>::type; + str += ColumnType::name; + str += " "; + str += ToSQLType(db); + if (N != sizeof...(T) - 1) + str += ","; + + add_column_create(db, str); + } } - template - typename std::enable_if::type - add_column_create(DatabaseEngine&, std::string&) - { } const std::string name; }; diff --git a/src/database/update_query.hpp b/src/database/update_query.hpp index a29ac3f..0ee2bd9 100644 --- a/src/database/update_query.hpp +++ b/src/database/update_query.hpp @@ -39,27 +39,25 @@ struct UpdateQuery: public Query } template - typename std::enable_if::type - insert_col_name_and_value(const std::tuple& columns) + void insert_col_name_and_value(const std::tuple& columns) { - using ColumnType = std::decay_t(columns))>; - - if (!std::is_same::value) + if constexpr(N < sizeof...(T)) { - this->body += ColumnType::name + "=$"s + std::to_string(this->current_param); - this->current_param++; + using ColumnType = std::decay_t(columns))>; - if (N < (sizeof...(T) - 1)) - this->body += ", "; - } + if (!std::is_same::value) + { + this->body += ColumnType::name + "=$"s + + std::to_string(this->current_param); + this->current_param++; - this->insert_col_name_and_value(columns); - } - template - typename std::enable_if::type - insert_col_name_and_value(const std::tuple&) - {} + if (N < (sizeof...(T) - 1)) + this->body += ", "; + } + this->insert_col_name_and_value(columns); + } + } template void execute(DatabaseEngine& db, const std::tuple& columns) @@ -76,23 +74,20 @@ struct UpdateQuery: public Query } template - typename std::enable_if::type - bind_param(const std::tuple& columns, Statement& statement, int index=1) + void bind_param(const std::tuple& columns, Statement& statement, int index=1) { - auto&& column = std::get(columns); - using ColumnType = std::decay_t; + if constexpr(N < sizeof...(T)) + { + auto&& column = std::get(columns); + using ColumnType = std::decay_t; - if (!std::is_same::value) - actual_bind(statement, column.value, index++); + if (!std::is_same::value) + actual_bind(statement, column.value, index++); - this->bind_param(columns, statement, index); + this->bind_param(columns, statement, index); + } } - template - typename std::enable_if::type - bind_param(const std::tuple&, Statement&, int) - {} - template void bind_id(const std::tuple& columns, Statement& statement) { -- cgit v1.2.3 From d0e3c71b91f1a1c1780158789fd42b8ac7209495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 17 Mar 2018 17:28:41 +0100 Subject: Revert "Use if constexpr to make things a lot more readable" This reverts commit d62ca9f87906be6f046fe9d07afb8bfb69c166e3. --- src/database/index.hpp | 21 +++++----- src/database/insert_query.hpp | 91 ++++++++++++++++++++++++------------------- src/database/query.hpp | 41 ++++++++++++------- src/database/row.hpp | 52 +++++++++++++------------ src/database/select_query.hpp | 77 +++++++++++++++++++++--------------- src/database/table.hpp | 44 +++++++++++---------- src/database/update_query.hpp | 51 +++++++++++++----------- 7 files changed, 213 insertions(+), 164 deletions(-) (limited to 'src') diff --git a/src/database/index.hpp b/src/database/index.hpp index 094a36a..30766ab 100644 --- a/src/database/index.hpp +++ b/src/database/index.hpp @@ -8,16 +8,19 @@ namespace { template -void add_column_name(std::string& out) +typename std::enable_if::type +add_column_name(std::string&) +{ } + +template +typename std::enable_if::type +add_column_name(std::string& out) { - if constexpr(N < sizeof...(T)) - { - using ColumnType = typename std::remove_reference(std::declval>()))>::type; - out += ColumnType::name; - if (N != sizeof...(T) - 1) - out += ","; - add_column_name(out); - } + using ColumnType = typename std::remove_reference(std::declval>()))>::type; + out += ColumnType::name; + if (N != sizeof...(T) - 1) + out += ","; + add_column_name(out); } } diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index ed1944f..04c098c 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -11,17 +11,20 @@ #include template -void update_autoincrement_id(std::tuple& columns, Statement& statement) +typename std::enable_if::type +update_autoincrement_id(std::tuple& columns, Statement& statement) { - if constexpr(N < sizeof...(T)) - { - using ColumnType = typename std::decay(columns))>::type; - if (std::is_same::value) - auto&& column = std::get(columns); - update_autoincrement_id(columns, statement); - } + using ColumnType = typename std::decay(columns))>::type; + if (std::is_same::value) + auto&& column = std::get(columns); + update_autoincrement_id(columns, statement); } +template +typename std::enable_if::type +update_autoincrement_id(std::tuple&, Statement&) +{} + struct InsertQuery: public Query { template @@ -50,20 +53,23 @@ struct InsertQuery: public Query } template - void bind_param(const std::tuple& columns, Statement& statement, int index=1) + typename std::enable_if::type + bind_param(const std::tuple& columns, Statement& statement, int index=1) { - if constexpr(N < sizeof...(T)) - { - auto&& column = std::get(columns); - using ColumnType = std::decay_t; + auto&& column = std::get(columns); + using ColumnType = std::decay_t; - if constexpr(!std::is_same::value) - actual_bind(statement, column.value, index++); + if (!std::is_same::value) + actual_bind(statement, column.value, index++); - this->bind_param(columns, statement, index); - } + this->bind_param(columns, statement, index); } + template + typename std::enable_if::type + bind_param(const std::tuple&, Statement&, int) + {} + template void insert_values(const std::tuple& columns) { @@ -73,21 +79,23 @@ struct InsertQuery: public Query } template - void insert_value(const std::tuple& columns, int index=1) + typename std::enable_if::type + insert_value(const std::tuple& columns, int index=1) { - if constexpr(N < sizeof...(T)) + using ColumnType = std::decay_t(columns))>; + + if (!std::is_same::value) { - using ColumnType = std::decay_t(columns))>; - - if (!std::is_same::value) - { - this->body += "$" + std::to_string(index++); - if (N != sizeof...(T) - 1) - this->body += ", "; - } - this->insert_value(columns, index); + this->body += "$" + std::to_string(index++); + if (N != sizeof...(T) - 1) + this->body += ", "; } + this->insert_value(columns, index); } + template + typename std::enable_if::type + insert_value(const std::tuple&, const int) + { } template void insert_col_names(const std::tuple& columns) @@ -98,21 +106,24 @@ struct InsertQuery: public Query } template - void insert_col_name(const std::tuple& columns) + typename std::enable_if::type + insert_col_name(const std::tuple& columns) { - if constexpr(N < sizeof...(T)) - { - using ColumnType = std::decay_t(columns))>; + using ColumnType = std::decay_t(columns))>; - if (!std::is_same::value) - { - this->body += ColumnType::name; - - if (N < (sizeof...(T) - 1)) - this->body += ", "; - } + if (!std::is_same::value) + { + this->body += ColumnType::name; - this->insert_col_name(columns); + if (N < (sizeof...(T) - 1)) + this->body += ", "; } + + this->insert_col_name(columns); } + + template + typename std::enable_if::type + insert_col_name(const std::tuple&) + {} }; diff --git a/src/database/query.hpp b/src/database/query.hpp index 2a2d2d4..1c4a5ff 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -13,12 +13,12 @@ void actual_bind(Statement& statement, const std::string& value, int index); void actual_bind(Statement& statement, const std::int64_t& value, int index); -void actual_bind(Statement& statement, const std::optional& value, int index); -template +template ::value>* = 0> void actual_bind(Statement& statement, const T& value, int index) { actual_bind(statement, static_cast(value), index); } +void actual_bind(Statement& statement, const std::optional& value, int index); #ifdef DEBUG_SQL_QUERIES #include @@ -57,27 +57,38 @@ struct Query #endif }; -void actual_add_param(Query& query, const std::string& val); -void actual_add_param(Query& query, const std::optional& val); +template +void add_param(Query& query, const ColumnType& column) +{ + std::cout << "add_param" << std::endl; + actual_add_param(query, column.value); +} + template void actual_add_param(Query& query, const T& val) { query.params.push_back(std::to_string(val)); } +void actual_add_param(Query& query, const std::string& val); + +template +typename std::enable_if::value, Query&>::type +operator<<(Query& query, const T&) +{ + query.body += T::name; + return query; +} +void actual_add_param(Query& query, const std::optional& val); + Query& operator<<(Query& query, const char* str); Query& operator<<(Query& query, const std::string& str); -template -Query& operator<<(Query& query, const T& i) +template +typename std::enable_if::value, Query&>::type +operator<<(Query& query, const Integer& i) { - if constexpr(std::is_integral::value) - { - query.body += "$" + std::to_string(query.current_param++); - actual_add_param(query, i); - } - else - { - query.body += T::name; - } + query.body += "$" + std::to_string(query.current_param++); + actual_add_param(query, i); return query; } + diff --git a/src/database/row.hpp b/src/database/row.hpp index 194a9c5..3703ff7 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -29,39 +29,41 @@ struct Row return col.value; } - void save(std::unique_ptr& db) + template + void save(std::unique_ptr& db, typename std::enable_if && Coucou>::type* = nullptr) { - if constexpr(is_one_of) + this->insert(*db); + } + + template + void save(std::unique_ptr& db, typename std::enable_if && Coucou>::type* = nullptr) + { + const Id& id = std::get(this->columns); + if (id.value == Id::unset_value) { - const Id& id = std::get(this->columns); - if (id.value == Id::unset_value) - { - this->insert(*db); - if (db->last_inserted_rowid >= 0) - std::get(this->columns).value = static_cast(db->last_inserted_rowid); - } - else - this->update(*db); + this->insert(*db); + if (db->last_inserted_rowid >= 0) + std::get(this->columns).value = static_cast(db->last_inserted_rowid); } else - this->insert(*db); + this->update(*db); } private: - void insert(DatabaseEngine& db) + template + void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) { - if constexpr(is_one_of) - { - InsertQuery query(this->table_name, this->columns); - // Ugly workaround for non portable stuff - query.body += db.get_returning_id_sql_string(Id::name); - query.execute(db, this->columns); - } - else - { - InsertQuery query(this->table_name, this->columns); - query.execute(db, this->columns); - } + InsertQuery query(this->table_name, this->columns); + // Ugly workaround for non portable stuff + query.body += db.get_returning_id_sql_string(Id::name); + query.execute(db, this->columns); + } + + template + void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) + { + InsertQuery query(this->table_name, this->columns); + query.execute(db, this->columns); } void update(DatabaseEngine& db) diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index f7496a4..cd9943c 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -15,37 +15,48 @@ using namespace std::string_literals; template -auto extract_row_value(Statement& statement, const int i) +typename std::enable_if::value, std::int64_t>::type +extract_row_value(Statement& statement, const int i) { - if constexpr(std::is_integral::value) - return statement.get_column_int64(i); - else if constexpr (std::is_same::value) - return statement.get_column_text(i); - else if (std::is_same, T>::value) - { - const auto integer = statement.get_column_int(i); - if (integer > 0) - return std::optional{true}; - else if (integer < 0) - return std::optional{false}; - return std::optional{}; - } + return statement.get_column_int64(i); +} + +template +typename std::enable_if::value, T>::type +extract_row_value(Statement& statement, const int i) +{ + return statement.get_column_text(i); +} + +template +typename std::enable_if, T>::value, T>::type +extract_row_value(Statement& statement, const int i) +{ + const auto integer = statement.get_column_int(i); + if (integer > 0) + return true; + else if (integer < 0) + return false; + return std::nullopt; } template -void extract_row_values(Row& row, Statement& statement) +typename std::enable_if::type +extract_row_values(Row& row, Statement& statement) { - if constexpr(N < sizeof...(T)) - { - using ColumnType = typename std::remove_reference(row.columns))>::type; + using ColumnType = typename std::remove_reference(row.columns))>::type; - auto&& column = std::get(row.columns); - column.value = static_cast(extract_row_value(statement, N)); + auto&& column = std::get(row.columns); + column.value = static_cast(extract_row_value(statement, N)); - extract_row_values(row, statement); - } + extract_row_values(row, statement); } +template +typename std::enable_if::type +extract_row_values(Row&, Statement&) +{} + template struct SelectQuery: public Query { @@ -58,21 +69,23 @@ struct SelectQuery: public Query } template - void insert_col_name() + typename std::enable_if::type + insert_col_name() { - if constexpr(N < sizeof...(T)) - { - using ColumnsType = std::tuple; - using ColumnType = typename std::remove_reference(std::declval()))>::type; + using ColumnsType = std::tuple; + using ColumnType = typename std::remove_reference(std::declval()))>::type; - this->body += " " + std::string{ColumnType::name}; + this->body += " " + std::string{ColumnType::name}; - if (N < (sizeof...(T) - 1)) - this->body += ", "; + if (N < (sizeof...(T) - 1)) + this->body += ", "; - this->insert_col_name(); - } + this->insert_col_name(); } + template + typename std::enable_if::type + insert_col_name() + {} SelectQuery& where() { diff --git a/src/database/table.hpp b/src/database/table.hpp index eb68418..680e7cc 100644 --- a/src/database/table.hpp +++ b/src/database/table.hpp @@ -93,32 +93,36 @@ class Table private: template - void add_column_if_not_exists(DatabaseEngine& db, const std::set& existing_columns) + typename std::enable_if::type + add_column_if_not_exists(DatabaseEngine& db, const std::set& existing_columns) { - if constexpr(N < sizeof...(T)) - { - using ColumnType = typename std::remove_reference(std::declval()))>::type; - if (existing_columns.count(ColumnType::name) == 0) - add_column_to_table(db, this->name); - add_column_if_not_exists(db, existing_columns); - } + using ColumnType = typename std::remove_reference(std::declval()))>::type; + if (existing_columns.count(ColumnType::name) == 0) + add_column_to_table(db, this->name); + add_column_if_not_exists(db, existing_columns); } + template + typename std::enable_if::type + add_column_if_not_exists(DatabaseEngine&, const std::set&) + {} template - void add_column_create(DatabaseEngine& db, std::string& str) + typename std::enable_if::type + add_column_create(DatabaseEngine& db, std::string& str) { - if constexpr(N < sizeof...(T)) - { - using ColumnType = typename std::remove_reference(std::declval()))>::type; - str += ColumnType::name; - str += " "; - str += ToSQLType(db); - if (N != sizeof...(T) - 1) - str += ","; - - add_column_create(db, str); - } + using ColumnType = typename std::remove_reference(std::declval()))>::type; + str += ColumnType::name; + str += " "; + str += ToSQLType(db); + if (N != sizeof...(T) - 1) + str += ","; + + add_column_create(db, str); } + template + typename std::enable_if::type + add_column_create(DatabaseEngine&, std::string&) + { } const std::string name; }; diff --git a/src/database/update_query.hpp b/src/database/update_query.hpp index 0ee2bd9..a29ac3f 100644 --- a/src/database/update_query.hpp +++ b/src/database/update_query.hpp @@ -39,25 +39,27 @@ struct UpdateQuery: public Query } template - void insert_col_name_and_value(const std::tuple& columns) + typename std::enable_if::type + insert_col_name_and_value(const std::tuple& columns) { - if constexpr(N < sizeof...(T)) - { - using ColumnType = std::decay_t(columns))>; - - if (!std::is_same::value) - { - this->body += ColumnType::name + "=$"s - + std::to_string(this->current_param); - this->current_param++; + using ColumnType = std::decay_t(columns))>; - if (N < (sizeof...(T) - 1)) - this->body += ", "; - } + if (!std::is_same::value) + { + this->body += ColumnType::name + "=$"s + std::to_string(this->current_param); + this->current_param++; - this->insert_col_name_and_value(columns); + if (N < (sizeof...(T) - 1)) + this->body += ", "; } + + this->insert_col_name_and_value(columns); } + template + typename std::enable_if::type + insert_col_name_and_value(const std::tuple&) + {} + template void execute(DatabaseEngine& db, const std::tuple& columns) @@ -74,20 +76,23 @@ struct UpdateQuery: public Query } template - void bind_param(const std::tuple& columns, Statement& statement, int index=1) + typename std::enable_if::type + bind_param(const std::tuple& columns, Statement& statement, int index=1) { - if constexpr(N < sizeof...(T)) - { - auto&& column = std::get(columns); - using ColumnType = std::decay_t; + auto&& column = std::get(columns); + using ColumnType = std::decay_t; - if (!std::is_same::value) - actual_bind(statement, column.value, index++); + if (!std::is_same::value) + actual_bind(statement, column.value, index++); - this->bind_param(columns, statement, index); - } + this->bind_param(columns, statement, index); } + template + typename std::enable_if::type + bind_param(const std::tuple&, Statement&, int) + {} + template void bind_id(const std::tuple& columns, Statement& statement) { -- cgit v1.2.3 From 03714c6cebf90dc7db8e3997a18cdd19e039c667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 17 Mar 2018 17:28:47 +0100 Subject: Revert "Use std::optional instead of OptionalBool" This reverts commit ba879a882e031d7b8503f78fe41d1210000c96ca. --- src/database/database.hpp | 2 +- src/database/query.cpp | 12 +++++----- src/database/query.hpp | 4 ++-- src/database/select_query.hpp | 9 +++---- src/utils/optional_bool.cpp | 4 ++-- src/utils/optional_bool.hpp | 48 ++++++++++++++++++++++++------------- src/xmpp/biboumi_adhoc_commands.cpp | 14 +++++------ 7 files changed, 55 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index 03d82ae..8a967d8 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -69,7 +69,7 @@ class Database struct RecordHistory: Column { static constexpr auto name = "recordhistory_"; RecordHistory(): Column(true) {}}; - struct RecordHistoryOptional: Column> { static constexpr auto name = "recordhistory_"; }; + struct RecordHistoryOptional: Column { static constexpr auto name = "recordhistory_"; }; struct VerifyCert: Column { static constexpr auto name = "verifycert_"; VerifyCert(): Column(true) {} }; diff --git a/src/database/query.cpp b/src/database/query.cpp index 13c881b..d72066e 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -11,11 +11,11 @@ void actual_bind(Statement& statement, const std::int64_t& value, int index) statement.bind_int64(index, value); } -void actual_bind(Statement& statement, const std::optional& value, int index) +void actual_bind(Statement& statement, const OptionalBool& value, int index) { - if (!value) + if (!value.is_set) statement.bind_int64(index, 0); - else if (*value) + else if (value.value) statement.bind_int64(index, 1); else statement.bind_int64(index, -1); @@ -26,11 +26,11 @@ void actual_add_param(Query& query, const std::string& val) query.params.push_back(val); } -void actual_add_param(Query& query, const std::optional& val) +void actual_add_param(Query& query, const OptionalBool& val) { - if (!val) + if (!val.is_set) query.params.push_back("0"); - else if (*val) + else if (val.value) query.params.push_back("1"); else query.params.push_back("-1"); diff --git a/src/database/query.hpp b/src/database/query.hpp index 1c4a5ff..ba28b1a 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -18,7 +18,7 @@ void actual_bind(Statement& statement, const T& value, int index) { actual_bind(statement, static_cast(value), index); } -void actual_bind(Statement& statement, const std::optional& value, int index); +void actual_bind(Statement& statement, const OptionalBool& value, int index); #ifdef DEBUG_SQL_QUERIES #include @@ -71,6 +71,7 @@ void actual_add_param(Query& query, const T& val) } void actual_add_param(Query& query, const std::string& val); +void actual_add_param(Query& query, const OptionalBool& val); template typename std::enable_if::value, Query&>::type @@ -79,7 +80,6 @@ operator<<(Query& query, const T&) query.body += T::name; return query; } -void actual_add_param(Query& query, const std::optional& val); Query& operator<<(Query& query, const char* str); Query& operator<<(Query& query, const std::string& str); diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index cd9943c..5a17f38 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -29,15 +29,16 @@ extract_row_value(Statement& statement, const int i) } template -typename std::enable_if, T>::value, T>::type +typename std::enable_if::value, T>::type extract_row_value(Statement& statement, const int i) { const auto integer = statement.get_column_int(i); + OptionalBool result; if (integer > 0) - return true; + result.set_value(true); else if (integer < 0) - return false; - return std::nullopt; + result.set_value(false); + return result; } template diff --git a/src/utils/optional_bool.cpp b/src/utils/optional_bool.cpp index 1d1c375..56fdca2 100644 --- a/src/utils/optional_bool.cpp +++ b/src/utils/optional_bool.cpp @@ -1,8 +1,8 @@ #include -std::ostream& operator<<(std::ostream& os, const std::optional& o) +std::ostream& operator<<(std::ostream& os, const OptionalBool& o) { - os << std::to_string(o); + os << o.to_string(); return os; } diff --git a/src/utils/optional_bool.hpp b/src/utils/optional_bool.hpp index c652ed3..867aca2 100644 --- a/src/utils/optional_bool.hpp +++ b/src/utils/optional_bool.hpp @@ -1,21 +1,37 @@ #pragma once -#include - #include -namespace std -{ -inline -std::string to_string(const std::optional b) +struct OptionalBool { - if (!b) - return "unset"; - else if (*b) - return "true"; - else - return "false"; -} -} - -std::ostream& operator<<(std::ostream& os, const std::optional& o); + OptionalBool() = default; + + OptionalBool(bool value): + is_set(true), value(value) {} + + void set_value(bool value) + { + this->is_set = true; + this->value = value; + } + + void unset() + { + this->is_set = false; + } + + std::string to_string() const + { + if (this->is_set == false) + return "unset"; + else if (this->value) + return "true"; + else + return "false"; + } + + bool is_set{false}; + bool value{false}; +}; + +std::ostream& operator<<(std::ostream& os, const OptionalBool& o); diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 53ec98b..38b6165 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -493,7 +493,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, { // Value selected by default XmlSubNode value(record_history, "value"); - value.set_inner(std::to_string(options.col())); + value.set_inner(options.col().to_string()); } // All three possible values for (const auto& val: {"unset", "true", "false"}) @@ -594,19 +594,19 @@ bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const else if (field->get_tag("var") == "record_history" && value && !value->get_inner().empty()) { - std::optional& database_value = options.col(); + OptionalBool& database_value = options.col(); if (value->get_inner() == "true") - database_value = true; + database_value.set_value(true); else if (value->get_inner() == "false") - database_value = false; + database_value.set_value(false); else - database_value.reset(); + database_value.unset(); auto& biboumi_component = dynamic_cast(xmpp_component); Bridge* bridge = biboumi_component.find_user_bridge(requester.bare()); if (bridge) { - if (database_value) - bridge->set_record_history(*database_value); + 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 -- cgit v1.2.3 From 577984faf2befaa7f11a1e4a115dc8d80805fec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 18 Mar 2018 02:31:18 +0100 Subject: Allow the execution of multiple commands after the IRC connection fix #3275 --- src/database/column.hpp | 4 ++++ src/database/database.cpp | 29 +++++++++++++++++++++++++++++ src/database/database.hpp | 10 +++++++++- src/database/delete_query.hpp | 33 +++++++++++++++++++++++++++++++++ src/database/table.hpp | 7 +++++++ src/irc/irc_client.cpp | 5 +++-- src/xmpp/biboumi_adhoc_commands.cpp | 28 ++++++++++++++++++++-------- 7 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 src/database/delete_query.hpp (limited to 'src') diff --git a/src/database/column.hpp b/src/database/column.hpp index 9367701..50c9c14 100644 --- a/src/database/column.hpp +++ b/src/database/column.hpp @@ -13,6 +13,10 @@ struct Column T value{}; }; +struct ForeignKey: Column { + static constexpr auto name = "fk_"; +}; + struct Id: Column { static constexpr std::size_t unset_value = static_cast(-1); static constexpr auto name = "id_"; diff --git a/src/database/database.cpp b/src/database/database.cpp index d19ed7a..812d27c 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -21,6 +21,7 @@ Database::GlobalOptionsTable Database::global_options("globaloptions_"); Database::IrcServerOptionsTable Database::irc_server_options("ircserveroptions_"); Database::IrcChannelOptionsTable Database::irc_channel_options("ircchanneloptions_"); Database::RosterTable Database::roster("roster"); +Database::AfterConnectionCommandsTable Database::after_connection_commands("after_connection_commands_"); std::map Database::encoding_in_cache{}; Database::GlobalPersistent::GlobalPersistent(): @@ -53,6 +54,8 @@ void Database::open(const std::string& filename) Database::irc_channel_options.upgrade(*Database::db); Database::roster.create(*Database::db); Database::roster.upgrade(*Database::db); + Database::after_connection_commands.create(*Database::db); + Database::after_connection_commands.upgrade(*Database::db); create_index(*Database::db, "archive_index", Database::muc_log_lines.get_name()); } @@ -88,6 +91,32 @@ Database::IrcServerOptions Database::get_irc_server_options(const std::string& o return options; } +Database::AfterConnectionCommands Database::get_after_connection_commands(const IrcServerOptions& server_options) +{ + const auto id = server_options.col(); + if (id == Id::unset_value) + return {}; + auto request = Database::after_connection_commands.select(); + request.where() << ForeignKey{} << "=" << id; + return request.execute(*Database::db); +} + +void Database::set_after_connection_commands(const Database::IrcServerOptions& server_options, Database::AfterConnectionCommands& commands) +{ + const auto id = server_options.col(); + if (id == Id::unset_value) + return ; + auto query = Database::after_connection_commands.del(); + query.where() << ForeignKey{} << "=" << id; + query.execute(*Database::db); + + for (auto& command: commands) + { + command.col() = server_options.col(); + command.save(Database::db); + } +} + Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel) { auto request = Database::irc_channel_options.select(); diff --git a/src/database/database.hpp b/src/database/database.hpp index 8a967d8..0e88be8 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -92,7 +92,7 @@ class Database using GlobalOptionsTable = Table; using GlobalOptions = GlobalOptionsTable::RowType; - using IrcServerOptionsTable = Table; + using IrcServerOptionsTable = Table; using IrcServerOptions = IrcServerOptionsTable::RowType; using IrcChannelOptionsTable = Table; @@ -101,6 +101,9 @@ class Database using RosterTable = Table; using RosterItem = RosterTable::RowType; + using AfterConnectionCommandsTable = Table; + using AfterConnectionCommands = std::vector; + Database() = default; ~Database() = default; @@ -121,6 +124,9 @@ class Database static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner, const std::string& server, const std::string& channel); + static AfterConnectionCommands get_after_connection_commands(const IrcServerOptions& server_options); + static void set_after_connection_commands(const IrcServerOptions& server_options, AfterConnectionCommands& commands); + /** * Get all the lines between (optional) start and end dates, with a (optional) limit. * If after_id is set, only the records after it will be returned. @@ -158,6 +164,8 @@ class Database static IrcServerOptionsTable irc_server_options; static IrcChannelOptionsTable irc_channel_options; static RosterTable roster; + static AfterConnectionCommandsTable after_connection_commands; + static std::unique_ptr db; /** diff --git a/src/database/delete_query.hpp b/src/database/delete_query.hpp new file mode 100644 index 0000000..dce705b --- /dev/null +++ b/src/database/delete_query.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +class DeleteQuery: public Query +{ +public: + DeleteQuery(const std::string& name): + Query("DELETE") + { + this->body += " from " + name; + } + + DeleteQuery& where() + { + this->body += " WHERE "; + return *this; + }; + + void execute(DatabaseEngine& db) + { + auto statement = db.prepare(this->body); + if (!statement) + return; +#ifdef DEBUG_SQL_QUERIES + const auto timer = this->log_and_time(); +#endif + statement->bind(std::move(this->params)); + if (statement->step() != StepResult::Done) + log_error("Failed to execute DELETE command"); + } +}; diff --git a/src/database/table.hpp b/src/database/table.hpp index 680e7cc..c8c1bdd 100644 --- a/src/database/table.hpp +++ b/src/database/table.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -85,6 +86,12 @@ class Table return select; } + auto del() + { + DeleteQuery query(this->name); + return query; + } + const std::string& get_name() const { return this->name; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 764f37b..5f93ea6 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -889,8 +889,9 @@ void IrcClient::on_welcome_message(const IrcMessage& message) #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), this->get_hostname()); - if (!options.col().empty()) - this->send_raw(options.col()); + const auto commands = Database::get_after_connection_commands(options); + for (const auto& command: commands) + this->send_raw(command.col()); #endif // Install a repeated events to regularly send a PING TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this), diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 38b6165..d773ec3 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -219,6 +219,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com server_domain = target.local; auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain, server_domain); + auto commands = Database::get_after_connection_commands(options); XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; @@ -307,14 +308,14 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com { 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().empty()) + after_cnt_cmd["var"] = "after_connect_commands"; + after_cnt_cmd["type"] = "text-multi"; + after_cnt_cmd["desc"] = "Custom IRC commands sent after the connection is established with the server."; + after_cnt_cmd["label"] = "After-connection IRC commands"; + for (const auto& command: commands) { XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value"); - after_cnt_cmd_value.set_inner(options.col()); + after_cnt_cmd_value.set_inner(command.col()); } } @@ -384,6 +385,8 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com server_domain = target.local; auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain, server_domain); + auto commands = Database::get_after_connection_commands(options); + for (const XmlNode* field: x->get_children("field", "jabber:x:data")) { const XmlNode* value = field->get_child("value", "jabber:x:data"); @@ -427,8 +430,16 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com else if (field->get_tag("var") == "pass" && value) options.col() = value->get_inner(); - else if (field->get_tag("var") == "after_connect_command" && value) - options.col() = value->get_inner(); + else if (field->get_tag("var") == "after_connect_commands") + { + commands.clear(); + for (const auto& val: values) + { + auto command = Database::after_connection_commands.row(); + command.col() = val->get_inner(); + commands.push_back(std::move(command)); + } + } else if (field->get_tag("var") == "username" && value) { @@ -450,6 +461,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com } Database::invalidate_encoding_in_cache(); options.save(Database::db); + Database::set_after_connection_commands(options, commands); command_node.delete_all_children(); XmlSubNode note(command_node, "note"); -- cgit v1.2.3 From 5af0a8040c33d07dacf78343eb9ed0a03437a65a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 18 Mar 2018 02:50:33 +0100 Subject: Use a transaction around the DELETE + INSERT of the after_connection_commands Otherwise we can imagine that two clients changing this value at the same time would mix things up. ref #3275 --- src/database/database.cpp | 21 +++++++++++++++++++++ src/database/database.hpp | 11 ++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/database/database.cpp b/src/database/database.cpp index 812d27c..b1525d5 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -106,6 +106,8 @@ void Database::set_after_connection_commands(const Database::IrcServerOptions& s const auto id = server_options.col(); if (id == Id::unset_value) return ; + + Transaction transaction; auto query = Database::after_connection_commands.del(); query.where() << ForeignKey{} << "=" << id; query.execute(*Database::db); @@ -330,4 +332,23 @@ std::string Database::gen_uuid() return uuid_str; } +Transaction::Transaction() +{ + const auto result = Database::raw_exec("BEGIN"); + if (std::get(result) == false) + log_error("Failed to create SQL transaction: ", std::get(result)); + else + this->success = true; + +} + +Transaction::~Transaction() +{ + if (this->success) + { + const auto result = Database::raw_exec("END"); + if (std::get(result) == false) + log_error("Failed to end SQL transaction: ", std::get(result)); + } +} #endif diff --git a/src/database/database.hpp b/src/database/database.hpp index 0e88be8..5dde447 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -203,11 +203,20 @@ class Database static auto raw_exec(const std::string& query) { - Database::db->raw_exec(query); + return Database::db->raw_exec(query); } private: static std::string gen_uuid(); static std::map encoding_in_cache; }; + +class Transaction +{ +public: + Transaction(); + ~Transaction(); + bool success{false}; +}; + #endif /* USE_DATABASE */ -- cgit v1.2.3 From 9500bfd4ccb21b261fd8204180d78553704f7acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 18 Mar 2018 19:33:07 +0100 Subject: Reflect message IDs in channel MUCs fix #3283 --- src/bridge/bridge.cpp | 11 ++++++++--- src/bridge/bridge.hpp | 2 +- src/database/database.cpp | 8 ++------ src/utils/uuid.cpp | 14 ++++++++++++++ src/utils/uuid.hpp | 8 ++++++++ src/xmpp/biboumi_component.cpp | 2 +- src/xmpp/xmpp_component.cpp | 12 ++++-------- src/xmpp/xmpp_component.hpp | 2 +- 8 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 src/utils/uuid.cpp create mode 100644 src/utils/uuid.hpp (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 9269bb7..9a0358c 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -185,7 +186,7 @@ bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const return false; } -void Bridge::send_channel_message(const Iid& iid, const std::string& body) +void Bridge::send_channel_message(const Iid& iid, const std::string& body, std::string id) { if (iid.get_server().empty()) { @@ -210,6 +211,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) std::vector lines = utils::split(body, '\n', true); if (lines.empty()) return ; + bool first = true; for (const std::string& line: lines) { if (line.substr(0, 5) == "/mode") @@ -231,9 +233,12 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body) uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), std::get<0>(xmpp_body), irc->get_own_nick()); #endif + if (!first) + id = utils::gen_uuid(); for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), this->make_xmpp_body(line), - this->user_jid + "/" + resource, uuid); + this->user_jid + "/" + resource, uuid, id); + first = false; } } @@ -816,7 +821,7 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) { this->xmpp.send_muc_message(std::to_string(iid), nick, this->make_xmpp_body(body, encoding), - this->user_jid + "/" + resource, {}); + this->user_jid + "/" + resource, {}, utils::gen_uuid()); } } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 44df4c2..3798465 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -77,7 +77,7 @@ public: */ bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, const std::string& resource, HistoryLimit history_limit); - void send_channel_message(const Iid& iid, const std::string& body); + void send_channel_message(const Iid& iid, const std::string& body, std::string id); void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); void send_raw_message(const std::string& hostname, const std::string& body); void leave_irc_channel(Iid&& iid, const std::string& status_message, const std::string& resource); diff --git a/src/database/database.cpp b/src/database/database.cpp index b1525d5..02c5b4f 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -2,9 +2,9 @@ #ifdef USE_DATABASE #include -#include #include #include +#include #include #include @@ -325,11 +325,7 @@ void Database::close() std::string Database::gen_uuid() { - char uuid_str[37]; - uuid_t uuid; - uuid_generate(uuid); - uuid_unparse(uuid, uuid_str); - return uuid_str; + return utils::gen_uuid(); } Transaction::Transaction() diff --git a/src/utils/uuid.cpp b/src/utils/uuid.cpp new file mode 100644 index 0000000..23b71fe --- /dev/null +++ b/src/utils/uuid.cpp @@ -0,0 +1,14 @@ +#include +#include + +namespace utils +{ +std::string gen_uuid() +{ + char uuid_str[37]; + uuid_t uuid; + uuid_generate(uuid); + uuid_unparse(uuid, uuid_str); + return uuid_str; +} +} diff --git a/src/utils/uuid.hpp b/src/utils/uuid.hpp new file mode 100644 index 0000000..d550475 --- /dev/null +++ b/src/utils/uuid.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace utils +{ +std::string gen_uuid(); +} diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 891b715..f35c7f4 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -279,7 +279,7 @@ void BiboumiComponent::handle_message(const Stanza& stanza) { if (body && !body->get_inner().empty()) { - bridge->send_channel_message(iid, body->get_inner()); + bridge->send_channel_message(iid, body->get_inner(), id); } const XmlNode* subject = stanza.get_child("subject", COMPONENT_NS); if (subject) diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index a71d810..b3d925e 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -14,8 +15,6 @@ #include #include -#include - #include #include @@ -364,10 +363,11 @@ void XmppComponent::send_topic(const std::string& from, Xmpp::body&& topic, cons this->send_stanza(message); } -void XmppComponent::send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& xmpp_body, const std::string& jid_to, std::string uuid) +void XmppComponent::send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& xmpp_body, const std::string& jid_to, std::string uuid, std::string id) { Stanza message("message"); message["to"] = jid_to; + message["id"] = std::move(id); if (!nick.empty()) message["from"] = muc_name + "@" + this->served_hostname + "/" + nick; else // Message from the room itself @@ -673,9 +673,5 @@ void XmppComponent::send_iq_result(const std::string& id, const std::string& to_ std::string XmppComponent::next_id() { - char uuid_str[37]; - uuid_t uuid; - uuid_generate(uuid); - uuid_unparse(uuid, uuid_str); - return uuid_str; + return utils::gen_uuid(); } diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index 06cc6ff..b11e56c 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -134,7 +134,7 @@ public: * Send a (non-private) message to the MUC */ void send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& body, const std::string& jid_to, - std::string uuid); + std::string uuid, std::string id); #ifdef USE_DATABASE /** * Send a message, with a element, part of a MUC history -- cgit v1.2.3 From 0de282a177baa0ed2d38a68715e78344172894ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 18 Mar 2018 19:37:41 +0100 Subject: Advertise the muc#stable_id feature on disco#info results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From XEP 0045: “Note: the requirement to reflect the 'id' attribute was added in version 1.31 of this XEP. Servers following the new specification SHOULD advertise that with a disco info feature of 'http://jabber.org/protocol/muc#stable_id' on both the service domain and on individual MUCs, so that clients can check for support.” --- src/xmpp/biboumi_component.cpp | 6 +++--- src/xmpp/xmpp_component.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index f35c7f4..f25aeea 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -915,7 +915,7 @@ void BiboumiComponent::send_self_disco_info(const std::string& id, const std::st identity["category"] = "conference"; identity["type"] = "irc"; identity["name"] = "Biboumi XMPP-IRC gateway"; - for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS}) + for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS, STABLE_MUC_ID_NS}) { XmlSubNode feature(query, "feature"); feature["var"] = ns; @@ -939,7 +939,7 @@ void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const s identity["category"] = "conference"; identity["type"] = "irc"; 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}) + for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS, STABLE_MUC_ID_NS}) { XmlSubNode feature(query, "feature"); feature["var"] = ns; @@ -982,7 +982,7 @@ void BiboumiComponent::send_irc_channel_disco_info(const std::string& id, const identity["category"] = "conference"; identity["type"] = "irc"; 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}) + for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS, STABLE_MUC_ID_NS}) { XmlSubNode feature(query, "feature"); feature["var"] = ns; diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index b11e56c..e18da40 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -37,6 +37,7 @@ #define RSM_NS "http://jabber.org/protocol/rsm" #define MUC_TRAFFIC_NS "http://jabber.org/protocol/muc#traffic" #define STABLE_ID_NS "urn:xmpp:sid:0" +#define STABLE_MUC_ID_NS "http://jabber.org/protocol/muc#stable_id" /** * An XMPP component, communicating with an XMPP server using the protocole -- cgit v1.2.3 From 1320dc6db48ebde28f5c0791cfc87cfe392d106e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 18 Mar 2018 19:41:52 +0100 Subject: =?UTF-8?q?Don=E2=80=99t=20reflect=20an=20empty=20id=20if=20it=20w?= =?UTF-8?q?as=20not=20included?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead, generate a uuid for that message --- src/bridge/bridge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 9a0358c..aba2f05 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -233,7 +233,7 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body, std:: uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), std::get<0>(xmpp_body), irc->get_own_nick()); #endif - if (!first) + if (!first || id.empty()) id = utils::gen_uuid(); for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), this->make_xmpp_body(line), -- cgit v1.2.3 From d7427fc9ca4c06fda458e4951559f57163d90b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 19 Mar 2018 00:16:16 +0100 Subject: Re-connect to postgresql when the connection is lost fix #3336 --- src/database/postgresql_statement.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/database/postgresql_statement.hpp b/src/database/postgresql_statement.hpp index 5665aed..37e8ea0 100644 --- a/src/database/postgresql_statement.hpp +++ b/src/database/postgresql_statement.hpp @@ -92,7 +92,7 @@ class PostgresqlStatement: public Statement private: private: - bool execute() + bool execute(const bool second_attempt=false) { std::vector params; params.reserve(this->params.size()); @@ -113,7 +113,17 @@ private: const char* original = PQerrorMessage(this->conn); if (original && std::strlen(original) > 0) log_error("Failed to execute command: ", std::string{original, std::strlen(original) - 1}); - return false; + if (PQstatus(this->conn) != CONNECTION_OK && !second_attempt) + { + log_info("Trying to reconnect to PostgreSQL server and execute the query again."); + PQreset(this->conn); + return this->execute(true); + } + else + { + log_error("Givin up."); + return false; + } } return true; } -- cgit v1.2.3 From 619c991a691a455efee2baa4e1fe96e64d27ff64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 19 Mar 2018 20:08:35 +0100 Subject: Add a nick field in the IRC server configuration form fix #3317 --- src/bridge/bridge.cpp | 7 ++++++- src/bridge/bridge.hpp | 2 +- src/database/database.hpp | 2 +- src/xmpp/biboumi_adhoc_commands.cpp | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index aba2f05..bff86b9 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -166,10 +166,15 @@ IrcClient* Bridge::find_irc_client(const std::string& hostname) const } } -bool Bridge::join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, +bool Bridge::join_irc_channel(const Iid& iid, std::string nickname, const std::string& password, const std::string& resource, HistoryLimit history_limit) { const auto& hostname = iid.get_server(); +#ifdef USE_DATABASE + auto soptions = Database::get_irc_server_options(this->get_bare_jid(), hostname); + if (!soptions.col().empty()) + nickname = soptions.col(); +#endif IrcClient* irc = this->make_irc_client(hostname, nickname); irc->history_limit = history_limit; this->add_resource_to_server(hostname, resource); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 3798465..a4ee693 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -75,7 +75,7 @@ public: * Try to join an irc_channel, does nothing and return true if the channel * was already joined. */ - bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password, const std::string& resource, HistoryLimit history_limit); + bool join_irc_channel(const Iid& iid, std::string nickname, const std::string& password, const std::string& resource, HistoryLimit history_limit); void send_channel_message(const Iid& iid, const std::string& body, std::string id); void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); diff --git a/src/database/database.hpp b/src/database/database.hpp index 5dde447..d986ecc 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -92,7 +92,7 @@ class Database using GlobalOptionsTable = Table; using GlobalOptions = GlobalOptionsTable::RowType; - using IrcServerOptionsTable = Table; + using IrcServerOptionsTable = Table; using IrcServerOptions = IrcServerOptionsTable::RowType; using IrcChannelOptionsTable = Table; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index d773ec3..66298d4 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -293,6 +293,20 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com } } #endif + + { + XmlSubNode field(x, "field"); + field["var"] = "nick"; + field["type"] = "text-single"; + field["label"] = "Nickname"; + field["desc"] = "If set, will override the nickname provided in the initial presence sent to join the first server channel"; + if (!options.col().empty()) + { + XmlSubNode value(field, "value"); + value.set_inner(options.col()); + } + } + { XmlSubNode pass(x, "field"); pass["var"] = "pass"; @@ -427,6 +441,8 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com #endif // BOTAN_FOUND + else if (field->get_tag("var") == "nick" && value) + options.col() = value->get_inner(); else if (field->get_tag("var") == "pass" && value) options.col() = value->get_inner(); -- cgit v1.2.3 From 9ce0166777fae8482da4bc22b0fe3fe43febd169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 19 Mar 2018 20:16:01 +0100 Subject: Add a missing pointer check --- src/xmpp/biboumi_adhoc_commands.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 66298d4..93732ba 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -406,10 +406,9 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com const XmlNode* value = field->get_child("value", "jabber:x:data"); const std::vector values = field->get_children("value", "jabber:x:data"); - if (field->get_tag("var") == "address") - { - options.col() = value->get_inner(); - } + if (field->get_tag("var") == "address" && value) + options.col() = value->get_inner(); + if (field->get_tag("var") == "ports") { std::string ports; @@ -443,6 +442,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com else if (field->get_tag("var") == "nick" && value) options.col() = value->get_inner(); + else if (field->get_tag("var") == "pass" && value) options.col() = value->get_inner(); -- cgit v1.2.3 From faa33c1a712f98de4bafee821bde7eb270bbb7f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 22 Mar 2018 20:44:30 +0100 Subject: Pass an IrcClient* to send_muc_leave instead of doing an other search --- src/bridge/bridge.cpp | 13 ++++--------- src/bridge/bridge.hpp | 3 ++- src/irc/irc_client.cpp | 6 +++--- 3 files changed, 9 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index bff86b9..f32ad31 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -429,7 +429,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con } else if (channel->joined) { - this->send_muc_leave(iid, *channel->get_self(), "", true, true, resource); + this->send_muc_leave(iid, *channel->get_self(), "", true, true, resource, irc); } if (persistent) this->remove_resource_from_chan(key, resource); @@ -442,7 +442,7 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con if (channel && channel->joined) this->send_muc_leave(iid, *channel->get_self(), "Biboumi note: " + std::to_string(resources - 1) + " resources are still in this channel.", - true, true, resource); + true, true, resource, irc); this->remove_resource_from_chan(key, resource); } if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0) @@ -860,14 +860,9 @@ void Bridge::send_presence_error(const Iid& iid, const std::string& nick, void Bridge::send_muc_leave(const Iid& iid, const IrcUser& user, const std::string& message, const bool self, const bool user_requested, - const std::string& resource) + const std::string& resource, + const IrcClient* client) { - const IrcClient* client = this->find_irc_client(iid.get_server()); - if (!client) - { - log_error("Tried to send an unavailable presence for non existant client: ", std::to_string(iid)); - return; - } std::string affiliation; std::string role; std::tie(role, affiliation) = get_role_affiliation_from_irc_mode(user.get_most_significant_mode(client->get_sorted_user_modes())); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index a4ee693..a190739 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -173,7 +173,8 @@ public: void send_muc_leave(const Iid& iid, const IrcUser& nick, const std::string& message, const bool self, const bool user_requested, - const std::string& resource=""); + const std::string& resource, + const IrcClient* client); /** * Send presences to indicate that an user old_nick (ourself if self == * true) changed his nick to new_nick. The user_mode is needed because diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 5f93ea6..8f77e0d 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -965,7 +965,7 @@ void IrcClient::on_part(const IrcMessage& message) iid.set_local(chan_name); iid.set_server(this->hostname); iid.type = Iid::Type::Channel; - this->bridge.send_muc_leave(iid, *user_ptr, txt, self, true); + this->bridge.send_muc_leave(iid, *user_ptr, txt, self, true, {}, this); } } @@ -982,7 +982,7 @@ void IrcClient::on_error(const IrcMessage& message) IrcChannel* channel = pair.second.get(); if (!channel->joined) continue; - this->bridge.send_muc_leave(iid, *channel->get_self(), leave_message, true, false); + this->bridge.send_muc_leave(iid, *channel->get_self(), leave_message, true, false, {}, this); } this->channels.clear(); this->send_gateway_message("ERROR: " + leave_message); @@ -1007,7 +1007,7 @@ void IrcClient::on_quit(const IrcMessage& message) iid.set_local(chan_name); iid.set_server(this->hostname); iid.type = Iid::Type::Channel; - this->bridge.send_muc_leave(iid, *user, txt, self, false); + this->bridge.send_muc_leave(iid, *user, txt, self, false, {}, this); channel->remove_user(user); } } -- cgit v1.2.3 From cdace80758e2ee41f33824ad7f52a369c42a4a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 23 Mar 2018 15:54:36 +0100 Subject: Check that db.prepare worked before using the returned statement --- src/database/select_query.hpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 5a17f38..743a011 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -115,6 +115,8 @@ struct SelectQuery: public Query #endif auto statement = db.prepare(this->body); + if (!statement) + return rows; statement->bind(std::move(this->params)); while (statement->step() == StepResult::Row) -- cgit v1.2.3 From e2fc3cf68e1dc145e75fe67f2543765ff00ba839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 23 Mar 2018 16:16:30 +0100 Subject: Properly handle force-join presences by sending everything in return fix #3305 --- src/bridge/bridge.cpp | 10 +++++++--- src/bridge/bridge.hpp | 6 +++++- src/xmpp/biboumi_component.cpp | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index f32ad31..90caac1 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -166,8 +166,11 @@ IrcClient* Bridge::find_irc_client(const std::string& hostname) const } } -bool Bridge::join_irc_channel(const Iid& iid, std::string nickname, const std::string& password, - const std::string& resource, HistoryLimit history_limit) +bool Bridge::join_irc_channel(const Iid& iid, std::string nickname, + const std::string& password, + const std::string& resource, + HistoryLimit history_limit, + const bool force_join) { const auto& hostname = iid.get_server(); #ifdef USE_DATABASE @@ -185,7 +188,8 @@ bool Bridge::join_irc_channel(const Iid& iid, std::string nickname, const std::s { irc->send_join_command(iid.get_local(), password); return true; - } else if (!res_in_chan) { + } else if (!res_in_chan || force_join) { + // See https://github.com/xsf/xeps/pull/499 for the force_join argument this->generate_channel_join_for_resource(iid, resource); } return false; diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index a190739..8e7d9d7 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -75,7 +75,11 @@ public: * Try to join an irc_channel, does nothing and return true if the channel * was already joined. */ - bool join_irc_channel(const Iid& iid, std::string nickname, const std::string& password, const std::string& resource, HistoryLimit history_limit); + bool join_irc_channel(const Iid& iid, std::string nickname, + const std::string& password, + const std::string& resource, + HistoryLimit history_limit, + const bool force_join); void send_channel_message(const Iid& iid, const std::string& body, std::string id); void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG"); diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index f25aeea..02383f6 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -181,7 +181,7 @@ void BiboumiComponent::handle_presence(const Stanza& stanza) history_limit.stanzas = 0; } bridge->join_irc_channel(iid, to.resource, password ? password->get_inner(): "", - from.resource, history_limit); + from.resource, history_limit, x != nullptr); } else if (type == "unavailable") { -- cgit v1.2.3 From d81a9456ac33d7be8e494a6e7af01b45b8fa2478 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 23 Mar 2018 21:17:44 +0100 Subject: Change the nick of the joining user AFTER sending all the join stuff fix #3305 --- src/xmpp/biboumi_component.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 02383f6..26e8035 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -152,8 +152,6 @@ void BiboumiComponent::handle_presence(const Stanza& stanza) if (type.empty()) { const std::string own_nick = bridge->get_own_nick(iid); - if (!own_nick.empty() && own_nick != to.resource) - bridge->send_irc_nick_change(iid, to.resource, from.resource); const XmlNode* x = stanza.get_child("x", MUC_NS); const XmlNode* password = x ? x->get_child("password", MUC_NS): nullptr; const XmlNode* history = x ? x->get_child("history", MUC_NS): nullptr; @@ -182,6 +180,8 @@ void BiboumiComponent::handle_presence(const Stanza& stanza) } bridge->join_irc_channel(iid, to.resource, password ? password->get_inner(): "", from.resource, history_limit, x != nullptr); + if (!own_nick.empty() && own_nick != to.resource) + bridge->send_irc_nick_change(iid, to.resource, from.resource); } else if (type == "unavailable") { -- cgit v1.2.3 From 49bb383080fab1a88c343d84825dd40892ee085d Mon Sep 17 00:00:00 2001 From: Georg Lukas Date: Mon, 26 Mar 2018 16:55:42 +0200 Subject: Channel disco-info: use shorter string --- src/xmpp/biboumi_component.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 26e8035..12dd520 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -981,7 +981,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 " + iid.get_local() + " from server " + iid.get_server() + " over biboumi"; + identity["name"] = ""s + iid.get_local() + " on " + iid.get_server(); for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS, STABLE_MUC_ID_NS}) { XmlSubNode feature(query, "feature"); -- cgit v1.2.3 From 0cd848e532c8c60ed4f3a5d1e6a3850929f2765b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 31 Mar 2018 02:10:39 +0200 Subject: Send the stanza-id for messages received by other users fix #3347 --- src/bridge/bridge.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 90caac1..569574a 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -819,19 +819,19 @@ void Bridge::send_irc_version_request(const std::string& irc_hostname, const std void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) { const auto encoding = in_encoding_for(*this, iid); + std::string uuid{}; if (muc) { #ifdef USE_DATABASE const auto xmpp_body = this->make_xmpp_body(body, encoding); if (!nick.empty() && this->record_history) - Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), - std::get<0>(xmpp_body), nick); + uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), + std::get<0>(xmpp_body), nick); #endif for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) { this->xmpp.send_muc_message(std::to_string(iid), nick, this->make_xmpp_body(body, encoding), - this->user_jid + "/" + resource, {}, utils::gen_uuid()); - + this->user_jid + "/" + resource, uuid, utils::gen_uuid()); } } else -- cgit v1.2.3 From 857c7d3972a03cbeebf730d99b924d3710dee6a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 10 Apr 2018 23:33:59 +0200 Subject: Use a different Date data type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PLEASE backup your database before testing this commit, and report any migration issue. In postgresql, we use timestamp with timezone. In sqlite3 we use REAL (the date is expressed as julianday) This requires a migration of the muclogline_ table: In postgresql it’s pretty simple, we convert all the integer into timestamps With sqlite3, we actually rename the table, create the new one with the correct type, then copy everything to the new table, with a conversion function for the Date_ column, and then we delete the old table. fix #3343 --- src/bridge/bridge.cpp | 4 +-- src/database/column_escape.cpp | 46 ++++++++++++++++++++++++++ src/database/database.cpp | 43 +++++++++++++++++++----- src/database/database.hpp | 30 ++++++++++++++--- src/database/datetime_writer.hpp | 32 ++++++++++++++++++ src/database/engine.hpp | 18 ++++++++-- src/database/insert_query.hpp | 16 ++++++++- src/database/postgresql_engine.cpp | 44 +++++++++++++++++++++--- src/database/postgresql_engine.hpp | 13 ++++++-- src/database/query.cpp | 16 +++++++++ src/database/query.hpp | 10 ++++-- src/database/select_query.hpp | 25 ++++++++++++-- src/database/sqlite3_engine.cpp | 66 ++++++++++++++++++++++++++++++++---- src/database/sqlite3_engine.hpp | 11 ++++-- src/database/table.hpp | 8 +++-- src/utils/datetime.hpp | 68 ++++++++++++++++++++++++++++++++++++++ src/xmpp/biboumi_component.cpp | 2 +- src/xmpp/xmpp_component.cpp | 4 +-- src/xmpp/xmpp_component.hpp | 3 +- 19 files changed, 414 insertions(+), 45 deletions(-) create mode 100644 src/database/column_escape.cpp create mode 100644 src/database/datetime_writer.hpp create mode 100644 src/utils/datetime.hpp (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 569574a..2598f51 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1009,9 +1009,9 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { - const auto seconds = line.col(); + const DateTime& datetime = line.col(); this->xmpp.send_history_message(chan_name, line.col(), line.col(), - this->user_jid + "/" + resource, seconds); + this->user_jid + "/" + resource, datetime); } #else (void)hostname; diff --git a/src/database/column_escape.cpp b/src/database/column_escape.cpp new file mode 100644 index 0000000..0f1f611 --- /dev/null +++ b/src/database/column_escape.cpp @@ -0,0 +1,46 @@ +#include + +#include +#include + +template <> +std::string before_column() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return "strftime(\"%Y-%m-%dT%H:%M:%SZ\", "; + else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return "to_char("; + return {}; +} + +template <> +std::string after_column() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return ")"; + else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return R"(, 'YYYY-MM-DD"T"HH24:MM:SS"Z"'))"; + return {}; +} + +#include + +template <> +std::string before_value() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return "julianday("; + if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return "to_timestamp("; + return {}; +} + +template <> +std::string after_value() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return ", \"unixepoch\")"; + if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return ")"; + return {}; +} diff --git a/src/database/database.cpp b/src/database/database.cpp index 02c5b4f..7cb0a45 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -46,6 +46,7 @@ void Database::open(const std::string& filename) Database::db = std::move(new_db); Database::muc_log_lines.create(*Database::db); Database::muc_log_lines.upgrade(*Database::db); + convert_date_format(*Database::db, Database::muc_log_lines); Database::global_options.create(*Database::db); Database::global_options.upgrade(*Database::db); Database::irc_server_options.create(*Database::db); @@ -57,9 +58,9 @@ void Database::open(const std::string& filename) Database::after_connection_commands.create(*Database::db); Database::after_connection_commands.upgrade(*Database::db); create_index(*Database::db, "archive_index", Database::muc_log_lines.get_name()); + Database::db->init_session(); } - Database::GlobalOptions Database::get_global_options(const std::string& owner) { auto request = Database::global_options.select(); @@ -175,7 +176,7 @@ Database::IrcChannelOptions Database::get_irc_channel_options_with_server_and_gl } std::string Database::store_muc_message(const std::string& owner, const std::string& chan_name, - const std::string& server_name, Database::time_point date, + const std::string& server_name, DateTime::time_point date, const std::string& body, const std::string& nick) { auto line = Database::muc_log_lines.row(); @@ -186,7 +187,7 @@ std::string Database::store_muc_message(const std::string& owner, const std::str line.col() = owner; line.col() = chan_name; line.col() = server_name; - line.col() = std::chrono::duration_cast(date.time_since_epoch()).count(); + line.col() = date; line.col() = body; line.col() = nick; @@ -210,13 +211,21 @@ std::vector Database::get_muc_logs(const std::string& owne { const auto start_time = utils::parse_datetime(start); if (start_time != -1) - request << " and " << Database::Date{} << ">=" << start_time; + { + DateTime datetime(start_time); + DatetimeWriter writer(datetime, *Database::db); + request << " and " << Database::Date{} << ">=" << writer; + } } if (!end.empty()) { const auto end_time = utils::parse_datetime(end); if (end_time != -1) - request << " and " << Database::Date{} << "<=" << end_time; + { + DateTime datetime(end_time); + DatetimeWriter writer(datetime, *Database::db); + request << " and " << Database::Date{} << "<=" << writer; + } } if (reference_record_id != Id::unset_value) { @@ -229,9 +238,9 @@ std::vector Database::get_muc_logs(const std::string& owne } if (paging == Database::Paging::first) - request.order_by() << Database::Date{} << " ASC, " << Id{} << " ASC "; + request.order_by() << Database::Date{} << " ASC"; else - request.order_by() << Database::Date{} << " DESC, " << Id{} << " DESC "; + request.order_by() << Database::Date{} << " DESC"; if (limit >= 0) request.limit() << limit; @@ -257,13 +266,21 @@ Database::MucLogLine Database::get_muc_log(const std::string& owner, const std:: { const auto start_time = utils::parse_datetime(start); if (start_time != -1) - request << " and " << Database::Date{} << ">=" << start_time; + { + DateTime datetime(start_time); + DatetimeWriter writer(datetime, *Database::db); + request << " and " << Database::Date{} << ">=" << writer; + } } if (!end.empty()) { const auto end_time = utils::parse_datetime(end); if (end_time != -1) - request << " and " << Database::Date{} << "<=" << end_time; + { + DateTime datetime(end_time); + DatetimeWriter writer(datetime, *Database::db); + request << " and " << Database::Date{} << "<=" << writer; + } } auto result = request.execute(*Database::db); @@ -347,4 +364,12 @@ Transaction::~Transaction() log_error("Failed to end SQL transaction: ", std::get(result)); } } + +void Transaction::rollback() +{ + this->success = false; + const auto result = Database::raw_exec("ROLLBACK"); + if (std::get(result) == false) + log_error("Failed to rollback SQL transaction: ", std::get(result)); +} #endif diff --git a/src/database/database.hpp b/src/database/database.hpp index d986ecc..75ff8f3 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -17,11 +18,9 @@ #include #include - class Database { public: - using time_point = std::chrono::system_clock::time_point; struct RecordNotFound: public std::exception {}; enum class Paging { first, last }; @@ -37,7 +36,8 @@ class Database struct Server: Column { static constexpr auto name = "server_"; }; - struct Date: Column { static constexpr auto name = "date_"; }; + struct OldDate: Column { static constexpr auto name = "date_"; }; + struct Date: Column { static constexpr auto name = "date_"; }; struct Body: Column { static constexpr auto name = "body_"; }; @@ -88,6 +88,8 @@ class Database using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; + using OldMucLogLineTable = Table; + using OldMucLogLine = OldMucLogLineTable::RowType; using GlobalOptionsTable = Table; using GlobalOptions = GlobalOptionsTable::RowType; @@ -141,7 +143,7 @@ class Database */ static MucLogLine get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, const std::string& uuid, const std::string& start="", const std::string& end=""); static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, - time_point date, const std::string& body, const std::string& nick); + DateTime::time_point date, const std::string& body, const std::string& nick); static void add_roster_item(const std::string& local, const std::string& remote); static bool has_roster_item(const std::string& local, const std::string& remote); @@ -168,6 +170,13 @@ class Database static std::unique_ptr db; + static DatabaseEngine::EngineType engine_type() + { + if (Database::db) + return Database::db->engine_type(); + return DatabaseEngine::EngineType::None; + } + /** * Some caches, to avoid doing very frequent query requests for a few options. */ @@ -216,7 +225,20 @@ class Transaction public: Transaction(); ~Transaction(); + void rollback(); bool success{false}; }; +template +void convert_date_format(DatabaseEngine& db, Table table) +{ + const auto existing_columns = db.get_all_columns_from_table(table.get_name()); + const auto date_pair = existing_columns.find(Database::Date::name); + if (date_pair != existing_columns.end() && date_pair->second == "integer") + { + log_info("Converting Date_ format to the new one."); + db.convert_date_format(db); + } +} + #endif /* USE_DATABASE */ diff --git a/src/database/datetime_writer.hpp b/src/database/datetime_writer.hpp new file mode 100644 index 0000000..b104911 --- /dev/null +++ b/src/database/datetime_writer.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include +#include +#include + +class DatetimeWriter +{ +public: + DatetimeWriter(DateTime datetime, const DatabaseEngine& engine): + datetime(datetime), + engine(engine) + {} + + long double get_value() const + { + const long double epoch_duration = this->datetime.epoch().count(); + const long double epoch_seconds = epoch_duration / std::chrono::system_clock::period::den; + return this->engine.epoch_to_floating_value(epoch_seconds); + } + std::string escape_param_number(int value) const + { + return this->engine.escape_param_number(value); + } + +private: + const DateTime datetime; + const DatabaseEngine& engine; +}; diff --git a/src/database/engine.hpp b/src/database/engine.hpp index 41dccf5..ecf047f 100644 --- a/src/database/engine.hpp +++ b/src/database/engine.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include class DatabaseEngine @@ -27,7 +28,10 @@ class DatabaseEngine DatabaseEngine(DatabaseEngine&&) = delete; DatabaseEngine& operator=(DatabaseEngine&&) = delete; - virtual std::set get_all_columns_from_table(const std::string& table_name) = 0; + enum class EngineType { None, Postgresql, Sqlite3, }; + virtual EngineType engine_type() const = 0; + + virtual std::map get_all_columns_from_table(const std::string& table_name) = 0; virtual std::tuple raw_exec(const std::string& query) = 0; virtual std::unique_ptr prepare(const std::string& query) = 0; virtual void extract_last_insert_rowid(Statement& statement) = 0; @@ -35,7 +39,17 @@ class DatabaseEngine { return {}; } - virtual std::string id_column_type() = 0; + virtual void convert_date_format(DatabaseEngine&) = 0; + virtual std::string id_column_type() const = 0; + virtual std::string datetime_column_type() const = 0; + virtual long double epoch_to_floating_value(long double seconds) const = 0; + virtual std::string escape_param_number(int nb) const + { + return "$" + std::to_string(nb); + } + virtual void init_session() + { + } int64_t last_inserted_rowid{-1}; }; diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index 04c098c..e3a7e83 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -25,6 +25,18 @@ typename std::enable_if::type update_autoincrement_id(std::tuple&, Statement&) {} +template +std::string before_value() +{ + return {}; +} + +template +std::string after_value() +{ + return {}; +} + struct InsertQuery: public Query { template @@ -73,7 +85,7 @@ struct InsertQuery: public Query template void insert_values(const std::tuple& columns) { - this->body += "VALUES ("; + this->body += " VALUES ("; this->insert_value(columns); this->body += ")"; } @@ -86,7 +98,9 @@ struct InsertQuery: public Query if (!std::is_same::value) { + this->body += before_value(); this->body += "$" + std::to_string(index++); + this->body += after_value(); if (N != sizeof...(T) - 1) this->body += ", "; } diff --git a/src/database/postgresql_engine.cpp b/src/database/postgresql_engine.cpp index 59bc885..abeb779 100644 --- a/src/database/postgresql_engine.cpp +++ b/src/database/postgresql_engine.cpp @@ -2,6 +2,7 @@ #ifdef PQ_FOUND #include +#include #include @@ -12,6 +13,7 @@ #include #include +#include PostgresqlEngine::PostgresqlEngine(PGconn*const conn): conn(conn) @@ -52,14 +54,14 @@ std::unique_ptr PostgresqlEngine::open(const std::string& connin return std::make_unique(con); } -std::set PostgresqlEngine::get_all_columns_from_table(const std::string& table_name) +std::map PostgresqlEngine::get_all_columns_from_table(const std::string& table_name) { - const auto query = "SELECT column_name from information_schema.columns where table_name='" + table_name + "'"; + const auto query = "SELECT column_name, data_type from information_schema.columns where table_name='" + table_name + "'"; auto statement = this->prepare(query); - std::set columns; + std::map columns; while (statement->step() == StepResult::Row) - columns.insert(statement->get_column_text(0)); + columns[utils::tolower(statement->get_column_text(0))] = utils::tolower(statement->get_column_text(1)); return columns; } @@ -96,9 +98,41 @@ std::string PostgresqlEngine::get_returning_id_sql_string(const std::string& col return " RETURNING " + col_name; } -std::string PostgresqlEngine::id_column_type() +std::string PostgresqlEngine::id_column_type() const { return "SERIAL"; } +std::string PostgresqlEngine::datetime_column_type() const +{ + return "TIMESTAMP"; +} + +void PostgresqlEngine::convert_date_format(DatabaseEngine& db) +{ + const auto table_name = Database::muc_log_lines.get_name(); + const std::string column_name = Database::Date::name; + const std::string query = "ALTER TABLE " + table_name + " ALTER COLMUN " + column_name + " SET DATA TYPE timestamp USING to_timestamp(" + column_name + ")"; + + auto result = db.raw_exec(query); + if (!std::get(result)) + log_error("Failed to execute query: ", std::get(result)); +} + +std::string PostgresqlEngine::escape_param_number(int nb) const +{ + return "to_timestamp(" + DatabaseEngine::escape_param_number(nb) + ")"; +} + +void PostgresqlEngine::init_session() +{ + const auto res = this->raw_exec("SET SESSION TIME ZONE 'UTC'"); + if (!std::get(res)) + log_debug("Failed to set UTC timezone: ", std::get(res)); +} +long double PostgresqlEngine::epoch_to_floating_value(long double seconds) const +{ + return seconds; +} + #endif diff --git a/src/database/postgresql_engine.hpp b/src/database/postgresql_engine.hpp index fe4fb53..f2dcec3 100644 --- a/src/database/postgresql_engine.hpp +++ b/src/database/postgresql_engine.hpp @@ -23,13 +23,22 @@ class PostgresqlEngine: public DatabaseEngine ~PostgresqlEngine(); static std::unique_ptr open(const std::string& string); + EngineType engine_type() const override + { + return EngineType::Postgresql; + } - std::set get_all_columns_from_table(const std::string& table_name) override final; + std::map get_all_columns_from_table(const std::string& table_name) override final; std::tuple raw_exec(const std::string& query) override final; std::unique_ptr prepare(const std::string& query) override; void extract_last_insert_rowid(Statement& statement) override; std::string get_returning_id_sql_string(const std::string& col_name) override; - std::string id_column_type() override; + std::string id_column_type() const override; + std::string datetime_column_type() const override; + void convert_date_format(DatabaseEngine& engine) override; + long double epoch_to_floating_value(long double seconds) const override; + void init_session() override; + std::string escape_param_number(int nb) const override; private: PGconn* const conn; }; diff --git a/src/database/query.cpp b/src/database/query.cpp index d72066e..6d20302 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -21,6 +21,13 @@ void actual_bind(Statement& statement, const OptionalBool& value, int index) statement.bind_int64(index, -1); } +void actual_bind(Statement& statement, const DateTime& value, int index) +{ + const auto epoch = value.epoch().count(); + const auto result = std::to_string(static_cast(epoch) / std::chrono::system_clock::period::den); + statement.bind_text(index, result); +} + void actual_add_param(Query& query, const std::string& val) { query.params.push_back(val); @@ -49,3 +56,12 @@ Query& operator<<(Query& query, const std::string& str) actual_add_param(query, str); return query; } + +Query& operator<<(Query& query, const DatetimeWriter& datetime_writer) +{ + query.body += datetime_writer.escape_param_number(query.current_param++); + actual_add_param(query, datetime_writer.get_value()); + return query; +} + + diff --git a/src/database/query.hpp b/src/database/query.hpp index ba28b1a..910271a 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -10,6 +11,7 @@ #include #include +#include void actual_bind(Statement& statement, const std::string& value, int index); void actual_bind(Statement& statement, const std::int64_t& value, int index); @@ -19,6 +21,7 @@ void actual_bind(Statement& statement, const T& value, int index) actual_bind(statement, static_cast(value), index); } void actual_bind(Statement& statement, const OptionalBool& value, int index); +void actual_bind(Statement& statement, const DateTime& value, int index); #ifdef DEBUG_SQL_QUERIES #include @@ -74,15 +77,13 @@ void actual_add_param(Query& query, const std::string& val); void actual_add_param(Query& query, const OptionalBool& val); template -typename std::enable_if::value, Query&>::type +typename std::enable_if::value, Query&>::type operator<<(Query& query, const T&) { query.body += T::name; return query; } -Query& operator<<(Query& query, const char* str); -Query& operator<<(Query& query, const std::string& str); template typename std::enable_if::value, Query&>::type operator<<(Query& query, const Integer& i) @@ -92,3 +93,6 @@ operator<<(Query& query, const Integer& i) return query; } +Query& operator<<(Query& query, const char* str); +Query& operator<<(Query& query, const std::string& str); +Query& operator<<(Query& query, const DatetimeWriter& datetime); diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 743a011..3013dd8 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -3,8 +3,8 @@ #include #include +#include #include -#include #include #include @@ -41,6 +41,14 @@ extract_row_value(Statement& statement, const int i) return result; } +template +typename std::enable_if::value, T>::type +extract_row_value(Statement& statement, const int i) +{ + const std::string timestamp = statement.get_column_text(i); + return {timestamp}; +} + template typename std::enable_if::type extract_row_values(Row& row, Statement& statement) @@ -58,6 +66,18 @@ typename std::enable_if::type extract_row_values(Row&, Statement&) {} +template +std::string before_column() +{ + return {}; +} + +template +std::string after_column() +{ + return {}; +} + template struct SelectQuery: public Query { @@ -76,7 +96,8 @@ struct SelectQuery: public Query using ColumnsType = std::tuple; using ColumnType = typename std::remove_reference(std::declval()))>::type; - this->body += " " + std::string{ColumnType::name}; + this->body += " "; + this->body += before_column() + ColumnType::name + after_column(); if (N < (sizeof...(T) - 1)) this->body += ", "; diff --git a/src/database/sqlite3_engine.cpp b/src/database/sqlite3_engine.cpp index ae4a146..1fa6316 100644 --- a/src/database/sqlite3_engine.cpp +++ b/src/database/sqlite3_engine.cpp @@ -2,6 +2,7 @@ #ifdef SQLITE3_FOUND +#include #include #include @@ -22,16 +23,17 @@ Sqlite3Engine::~Sqlite3Engine() sqlite3_close(this->db); } -std::set Sqlite3Engine::get_all_columns_from_table(const std::string& table_name) +std::map Sqlite3Engine::get_all_columns_from_table(const std::string& table_name) { - std::set result; + std::map result; char* errmsg; std::string query{"PRAGMA table_info(" + table_name + ")"}; int res = sqlite3_exec(this->db, query.data(), [](void* param, int columns_nb, char** columns, char**) -> int { constexpr int name_column = 1; - std::set* result = static_cast*>(param); - if (name_column < columns_nb) - result->insert(utils::tolower(columns[name_column])); + constexpr int data_type_column = 2; + auto* result = static_cast*>(param); + if (name_column < columns_nb && data_type_column < columns_nb) + (*result)[utils::tolower(columns[name_column])] = utils::tolower(columns[data_type_column]); return 0; }, &result, &errmsg); @@ -44,6 +46,48 @@ std::set Sqlite3Engine::get_all_columns_from_table(const std::strin return result; } +template +static auto make_select_query(const Row&, const std::string& name) +{ + return SelectQuery{name}; +} + +void Sqlite3Engine::convert_date_format(DatabaseEngine& db) +{ + Transaction transaction{}; + auto rollback = [&transaction] (const std::string& error_msg) + { + log_error("Failed to execute query: ", error_msg); + transaction.rollback(); + }; + + const auto real_name = Database::muc_log_lines.get_name(); + const auto tmp_name = real_name + "tmp_"; + const std::string date_name = Database::Date::name; + + auto result = db.raw_exec("ALTER TABLE " + real_name + " RENAME TO " + tmp_name); + if (!std::get(result)) + return rollback(std::get(result)); + + Database::muc_log_lines.create(db); + + Database::OldMucLogLineTable old_muc_log_line(tmp_name); + auto select_query = make_select_query(old_muc_log_line.row(), old_muc_log_line.get_name()); + + auto& select_body = select_query.body; + auto begin = select_body.find(date_name); + select_body.replace(begin, date_name.size(), "julianday("+date_name+", 'unixepoch')"); + select_body = "INSERT INTO " + real_name + " " + select_body; + + result = db.raw_exec(select_body); + if (!std::get(result)) + return rollback(std::get(result)); + + result = db.raw_exec("DROP TABLE " + tmp_name); + if (!std::get(result)) + return rollback(std::get(result)); +} + std::unique_ptr Sqlite3Engine::open(const std::string& filename) { sqlite3* new_db; @@ -93,9 +137,19 @@ void Sqlite3Engine::extract_last_insert_rowid(Statement&) this->last_inserted_rowid = sqlite3_last_insert_rowid(this->db); } -std::string Sqlite3Engine::id_column_type() +std::string Sqlite3Engine::id_column_type() const { return "INTEGER PRIMARY KEY AUTOINCREMENT"; } +std::string Sqlite3Engine::datetime_column_type() const +{ + return "REAL"; +} + +long double Sqlite3Engine::epoch_to_floating_value(long double d) const +{ + return (d / 86400.0) + 2440587.5; +} + #endif diff --git a/src/database/sqlite3_engine.hpp b/src/database/sqlite3_engine.hpp index 5b8176c..82d01c9 100644 --- a/src/database/sqlite3_engine.hpp +++ b/src/database/sqlite3_engine.hpp @@ -23,12 +23,19 @@ class Sqlite3Engine: public DatabaseEngine ~Sqlite3Engine(); static std::unique_ptr open(const std::string& string); + EngineType engine_type() const override + { + return EngineType::Sqlite3; + } - std::set get_all_columns_from_table(const std::string& table_name) override final; + std::map get_all_columns_from_table(const std::string& table_name) override final; std::tuple raw_exec(const std::string& query) override final; std::unique_ptr prepare(const std::string& query) override; void extract_last_insert_rowid(Statement& statement) override; - std::string id_column_type() override; + std::string id_column_type() const override; + std::string datetime_column_type() const override; + void convert_date_format(DatabaseEngine&) override; + long double epoch_to_floating_value(long double d) const override; private: sqlite3* const db; }; diff --git a/src/database/table.hpp b/src/database/table.hpp index c8c1bdd..31b92a7 100644 --- a/src/database/table.hpp +++ b/src/database/table.hpp @@ -19,6 +19,8 @@ std::string ToSQLType(DatabaseEngine& db) return db.id_column_type(); else if (std::is_same::value) return "TEXT"; + else if (std::is_same::value) + return db.datetime_column_type(); else return "INTEGER"; } @@ -101,16 +103,16 @@ class Table template typename std::enable_if::type - add_column_if_not_exists(DatabaseEngine& db, const std::set& existing_columns) + add_column_if_not_exists(DatabaseEngine& db, const std::map& existing_columns) { using ColumnType = typename std::remove_reference(std::declval()))>::type; - if (existing_columns.count(ColumnType::name) == 0) + if (existing_columns.find(ColumnType::name) == existing_columns.end()) add_column_to_table(db, this->name); add_column_if_not_exists(db, existing_columns); } template typename std::enable_if::type - add_column_if_not_exists(DatabaseEngine&, const std::set&) + add_column_if_not_exists(DatabaseEngine&, const std::map&) {} template diff --git a/src/utils/datetime.hpp b/src/utils/datetime.hpp new file mode 100644 index 0000000..27511f7 --- /dev/null +++ b/src/utils/datetime.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +#include + +class DateTime +{ +public: + enum class Engine { + Postgresql, + Sqlite3, + } engine{Engine::Sqlite3}; + + using time_point = std::chrono::system_clock::time_point; + + DateTime(): + s{}, + t{} + { } + + DateTime(std::time_t t): + t(std::chrono::seconds(t)) + {} + + DateTime(std::string s): + s(std::move(s)) + {} + + DateTime& operator=(const std::string& s) + { + this->s = s; + return *this; + } + + DateTime& operator=(const time_point t) + { + this->t = t; + return *this; + } + + const std::string& to_string() const + { + return this->s; + } + + time_point::duration epoch() const + { + return this->t.time_since_epoch(); + } + + long double julianday() const + { + log_debug("ici?"); + auto res = ((static_cast(this->epoch().count()) / std::chrono::system_clock::period::den) / 86400) + 2440587.5; + return res; + } + +private: + std::string s; + time_point t; +}; + +inline long double to_julianday(std::time_t t) +{ + return static_cast(t) / 86400.0 + 2440587.5; +} diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 12dd520..9748258 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -808,7 +808,7 @@ void BiboumiComponent::send_archived_message(const Database::MucLogLine& log_lin XmlSubNode delay(forwarded, "delay"); delay["xmlns"] = DELAY_NS; - delay["stamp"] = utils::to_string(log_line.col()); + delay["stamp"] = log_line.col().to_string(); XmlSubNode submessage(forwarded, "message"); submessage["xmlns"] = CLIENT_NS; diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index b3d925e..bec88ea 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -399,7 +399,7 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str } #ifdef USE_DATABASE -void XmppComponent::send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body_txt, const std::string& jid_to, Database::time_point::rep timestamp) +void XmppComponent::send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body_txt, const std::string& jid_to, const DateTime& timestamp) { Stanza message("message"); message["to"] = jid_to; @@ -417,7 +417,7 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std: XmlSubNode delay(message, "delay"); delay["xmlns"] = DELAY_NS; delay["from"] = muc_name + "@" + this->served_hostname; - delay["stamp"] = utils::to_string(timestamp); + delay["stamp"] = timestamp.to_string(); } this->send_stanza(message); diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index e18da40..960c801 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -141,7 +142,7 @@ public: * Send a message, with a element, part of a MUC history */ void send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body, - const std::string& jid_to, Database::time_point::rep timestamp); + const std::string& jid_to, const DateTime& timestamp); #endif /** * Send an unavailable presence for this nick -- cgit v1.2.3 From de8267fa3f4f4e1d61bcf35fb36c6664f520a385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 11 Apr 2018 00:45:29 +0200 Subject: Fix a build warning when compiling without postgres or sqlite --- src/database/postgresql_engine.hpp | 3 +++ src/database/sqlite3_engine.hpp | 3 +++ 2 files changed, 6 insertions(+) (limited to 'src') diff --git a/src/database/postgresql_engine.hpp b/src/database/postgresql_engine.hpp index f2dcec3..70215d4 100644 --- a/src/database/postgresql_engine.hpp +++ b/src/database/postgresql_engine.hpp @@ -45,12 +45,15 @@ private: #else +using namespace std::string_literals; + class PostgresqlEngine { public: static std::unique_ptr open(const std::string& string) { throw std::runtime_error("Cannot open postgresql database "s + string + ": biboumi is not compiled with libpq."); + return {}; } }; diff --git a/src/database/sqlite3_engine.hpp b/src/database/sqlite3_engine.hpp index 82d01c9..1b37e8c 100644 --- a/src/database/sqlite3_engine.hpp +++ b/src/database/sqlite3_engine.hpp @@ -42,12 +42,15 @@ private: #else +using namespace std::string_literals; + class Sqlite3Engine { public: static std::unique_ptr open(const std::string& string) { throw std::runtime_error("Cannot open sqlite3 database "s + string + ": biboumi is not compiled with sqlite3 lib."); + return {}; } }; -- cgit v1.2.3 From 4bd7b6981bb49dd4111c908aaa34c34f677171f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 13 Apr 2018 23:35:06 +0200 Subject: Refactor that fixes a compilation issue in Release mode Some template specialization were not found, because they were not declared at the point they were used. We moved things around, things are less inter-dependant, and also now it works. --- src/database/column_escape.cpp | 46 ------------------------------ src/database/database.cpp | 57 +++++++++++++++++-------------------- src/database/insert_query.cpp | 21 ++++++++++++++ src/database/insert_query.hpp | 21 ++++++++++++++ src/database/row.hpp | 49 ------------------------------- src/database/save.hpp | 31 ++++++++++++++++++++ src/database/select_query.cpp | 21 ++++++++++++++ src/database/select_query.hpp | 14 +++++++++ src/database/sqlite3_engine.cpp | 1 + src/database/table.hpp | 10 ++----- src/database/update_query.hpp | 11 ++++++- src/xmpp/biboumi_adhoc_commands.cpp | 7 +++-- 12 files changed, 151 insertions(+), 138 deletions(-) delete mode 100644 src/database/column_escape.cpp create mode 100644 src/database/insert_query.cpp create mode 100644 src/database/save.hpp create mode 100644 src/database/select_query.cpp (limited to 'src') diff --git a/src/database/column_escape.cpp b/src/database/column_escape.cpp deleted file mode 100644 index 0f1f611..0000000 --- a/src/database/column_escape.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include - -#include -#include - -template <> -std::string before_column() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return "strftime(\"%Y-%m-%dT%H:%M:%SZ\", "; - else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return "to_char("; - return {}; -} - -template <> -std::string after_column() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return ")"; - else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return R"(, 'YYYY-MM-DD"T"HH24:MM:SS"Z"'))"; - return {}; -} - -#include - -template <> -std::string before_value() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return "julianday("; - if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return "to_timestamp("; - return {}; -} - -template <> -std::string after_value() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return ", \"unixepoch\")"; - if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return ")"; - return {}; -} diff --git a/src/database/database.cpp b/src/database/database.cpp index 7cb0a45..c935139 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -1,6 +1,8 @@ #include "biboumi.h" #ifdef USE_DATABASE +#include +#include #include #include #include @@ -63,32 +65,28 @@ void Database::open(const std::string& filename) Database::GlobalOptions Database::get_global_options(const std::string& owner) { - auto request = Database::global_options.select(); + auto request = select(Database::global_options); request.where() << Owner{} << "=" << owner; - Database::GlobalOptions options{Database::global_options.get_name()}; auto result = request.execute(*Database::db); if (result.size() == 1) - options = result.front(); - else - options.col() = owner; + return result.front(); + Database::GlobalOptions options{Database::global_options.get_name()}; + options.col() = owner; return options; } Database::IrcServerOptions Database::get_irc_server_options(const std::string& owner, const std::string& server) { - auto request = Database::irc_server_options.select(); + auto request = select(Database::irc_server_options); request.where() << Owner{} << "=" << owner << " and " << Server{} << "=" << server; - Database::IrcServerOptions options{Database::irc_server_options.get_name()}; auto result = request.execute(*Database::db); if (result.size() == 1) - options = result.front(); - else - { - options.col() = owner; - options.col() = server; - } + return result.front(); + Database::IrcServerOptions options{Database::irc_server_options.get_name()}; + options.col() = owner; + options.col() = server; return options; } @@ -97,7 +95,7 @@ Database::AfterConnectionCommands Database::get_after_connection_commands(const const auto id = server_options.col(); if (id == Id::unset_value) return {}; - auto request = Database::after_connection_commands.select(); + auto request = select(Database::after_connection_commands); request.where() << ForeignKey{} << "=" << id; return request.execute(*Database::db); } @@ -116,26 +114,23 @@ void Database::set_after_connection_commands(const Database::IrcServerOptions& s for (auto& command: commands) { command.col() = server_options.col(); - command.save(Database::db); + save(command, *Database::db); } } Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel) { - auto request = Database::irc_channel_options.select(); + auto request = select(Database::irc_channel_options); request.where() << Owner{} << "=" << owner <<\ " and " << Server{} << "=" << server <<\ " and " << Channel{} << "=" << channel; - Database::IrcChannelOptions options{Database::irc_channel_options.get_name()}; auto result = request.execute(*Database::db); if (result.size() == 1) - options = result.front(); - else - { - options.col() = owner; - options.col() = server; - options.col() = channel; - } + return result.front(); + Database::IrcChannelOptions options{Database::irc_channel_options.get_name()}; + options.col() = owner; + options.col() = server; + options.col() = channel; return options; } @@ -191,7 +186,7 @@ std::string Database::store_muc_message(const std::string& owner, const std::str line.col() = body; line.col() = nick; - line.save(Database::db); + save(line, *Database::db); return uuid; } @@ -202,7 +197,7 @@ std::vector Database::get_muc_logs(const std::string& owne if (limit == 0) return {}; - auto request = Database::muc_log_lines.select(); + auto request = select(Database::muc_log_lines); request.where() << Database::Owner{} << "=" << owner << \ " and " << Database::IrcChanName{} << "=" << chan_name << \ " and " << Database::IrcServerName{} << "=" << server; @@ -256,7 +251,7 @@ std::vector Database::get_muc_logs(const std::string& owne Database::MucLogLine Database::get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, const std::string& uuid, const std::string& start, const std::string& end) { - auto request = Database::muc_log_lines.select(); + auto request = select(Database::muc_log_lines); request.where() << Database::Owner{} << "=" << owner << \ " and " << Database::IrcChanName{} << "=" << chan_name << \ " and " << Database::IrcServerName{} << "=" << server << \ @@ -297,7 +292,7 @@ void Database::add_roster_item(const std::string& local, const std::string& remo roster_item.col() = local; roster_item.col() = remote; - roster_item.save(Database::db); + save(roster_item, *Database::db); } void Database::delete_roster_item(const std::string& local, const std::string& remote) @@ -311,7 +306,7 @@ void Database::delete_roster_item(const std::string& local, const std::string& r bool Database::has_roster_item(const std::string& local, const std::string& remote) { - auto query = Database::roster.select(); + auto query = select(Database::roster); query.where() << Database::LocalJid{} << "=" << local << \ " and " << Database::RemoteJid{} << "=" << remote; @@ -322,7 +317,7 @@ bool Database::has_roster_item(const std::string& local, const std::string& remo std::vector Database::get_contact_list(const std::string& local) { - auto query = Database::roster.select(); + auto query = select(Database::roster); query.where() << Database::LocalJid{} << "=" << local; return query.execute(*Database::db); @@ -330,7 +325,7 @@ std::vector Database::get_contact_list(const std::string& std::vector Database::get_full_roster() { - auto query = Database::roster.select(); + auto query = select(Database::roster); return query.execute(*Database::db); } diff --git a/src/database/insert_query.cpp b/src/database/insert_query.cpp new file mode 100644 index 0000000..f72d67f --- /dev/null +++ b/src/database/insert_query.cpp @@ -0,0 +1,21 @@ +#include + +template <> +std::string before_value() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return "julianday("; + if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return "to_timestamp("; + return {}; +} + +template <> +std::string after_value() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return ", \"unixepoch\")"; + if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return ")"; + return {}; +} diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index e3a7e83..cd1942f 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -1,10 +1,15 @@ #pragma once #include +#include #include #include +#include + #include +#include + #include #include #include @@ -37,6 +42,12 @@ std::string after_value() return {}; } +template <> +std::string before_value(); + +template <> +std::string after_value(); + struct InsertQuery: public Query { template @@ -141,3 +152,13 @@ struct InsertQuery: public Query insert_col_name(const std::tuple&) {} }; + +template +void insert(Row& row, DatabaseEngine& db) +{ + InsertQuery query(row.table_name, row.columns); + // Ugly workaround for non portable stuff + if (is_one_of) + query.body += db.get_returning_id_sql_string(Id::name); + query.execute(db, row.columns); +} diff --git a/src/database/row.hpp b/src/database/row.hpp index 3703ff7..27caf43 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -1,9 +1,5 @@ #pragma once -#include -#include -#include - #include #include @@ -29,52 +25,7 @@ struct Row return col.value; } - template - void save(std::unique_ptr& db, typename std::enable_if && Coucou>::type* = nullptr) - { - this->insert(*db); - } - - template - void save(std::unique_ptr& db, typename std::enable_if && Coucou>::type* = nullptr) - { - const Id& id = std::get(this->columns); - if (id.value == Id::unset_value) - { - this->insert(*db); - if (db->last_inserted_rowid >= 0) - std::get(this->columns).value = static_cast(db->last_inserted_rowid); - } - else - this->update(*db); - } - - private: - template - void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) - { - InsertQuery query(this->table_name, this->columns); - // Ugly workaround for non portable stuff - query.body += db.get_returning_id_sql_string(Id::name); - query.execute(db, this->columns); - } - - template - void insert(DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) - { - InsertQuery query(this->table_name, this->columns); - query.execute(db, this->columns); - } - - void update(DatabaseEngine& db) - { - UpdateQuery query(this->table_name, this->columns); - - query.execute(db, this->columns); - } - public: std::tuple columns; std::string table_name; - }; diff --git a/src/database/save.hpp b/src/database/save.hpp new file mode 100644 index 0000000..4362110 --- /dev/null +++ b/src/database/save.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + +#include + +#include + +template +void save(Row& row, DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) +{ + insert(row, db); +} + +template +void save(Row& row, DatabaseEngine& db, typename std::enable_if && Coucou>::type* = nullptr) +{ + const Id& id = std::get(row.columns); + if (id.value == Id::unset_value) + { + insert(row, db); + if (db.last_inserted_rowid >= 0) + std::get(row.columns).value = static_cast(db.last_inserted_rowid); + } + else + update(row, db); +} + diff --git a/src/database/select_query.cpp b/src/database/select_query.cpp new file mode 100644 index 0000000..970b06c --- /dev/null +++ b/src/database/select_query.cpp @@ -0,0 +1,21 @@ +#include + +template <> +std::string before_column() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return "strftime(\"%Y-%m-%dT%H:%M:%SZ\", "; + else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return "to_char("; + return {}; +} + +template <> +std::string after_column() +{ + if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) + return ")"; + else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) + return R"(, 'YYYY-MM-DD"T"HH24:MM:SS"Z"'))"; + return {}; +} diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 3013dd8..0de4fe5 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -2,6 +2,8 @@ #include +#include +#include #include #include #include @@ -78,6 +80,12 @@ std::string after_column() return {}; } +template <> +std::string before_column(); + +template <> +std::string after_column(); + template struct SelectQuery: public Query { @@ -153,3 +161,9 @@ struct SelectQuery: public Query const std::string table_name; }; +template +auto select(const Table table) +{ + SelectQuery query(table.name); + return query; +} diff --git a/src/database/sqlite3_engine.cpp b/src/database/sqlite3_engine.cpp index 1fa6316..b6ac1a1 100644 --- a/src/database/sqlite3_engine.cpp +++ b/src/database/sqlite3_engine.cpp @@ -3,6 +3,7 @@ #ifdef SQLITE3_FOUND #include +#include #include #include diff --git a/src/database/table.hpp b/src/database/table.hpp index 31b92a7..4c96151 100644 --- a/src/database/table.hpp +++ b/src/database/table.hpp @@ -2,7 +2,6 @@ #include -#include #include #include @@ -82,12 +81,6 @@ class Table return {this->name}; } - auto select() - { - SelectQuery select(this->name); - return select; - } - auto del() { DeleteQuery query(this->name); @@ -99,6 +92,8 @@ class Table return this->name; } + const std::string name; + private: template @@ -133,5 +128,4 @@ class Table add_column_create(DatabaseEngine&, std::string&) { } - const std::string name; }; diff --git a/src/database/update_query.hpp b/src/database/update_query.hpp index a29ac3f..c2b819d 100644 --- a/src/database/update_query.hpp +++ b/src/database/update_query.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include using namespace std::string_literals; @@ -102,3 +103,11 @@ struct UpdateQuery: public Query actual_bind(statement, value.value, sizeof...(T)); } }; + +template +void update(Row& row, DatabaseEngine& db) +{ + UpdateQuery query(row.table_name, row.columns); + + query.execute(db, row.columns); +} diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 93732ba..82a1cbf 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -14,6 +14,7 @@ #ifdef USE_DATABASE #include +#include #endif #ifndef HAS_PUT_TIME @@ -196,7 +197,7 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session, options.col() = to_bool(value->get_inner()); } - options.save(Database::db); + save(options, *Database::db); command_node.delete_all_children(); XmlSubNode note(command_node, "note"); @@ -476,7 +477,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com } Database::invalidate_encoding_in_cache(); - options.save(Database::db); + save(options, *Database::db); Database::set_after_connection_commands(options, commands); command_node.delete_all_children(); @@ -646,7 +647,7 @@ bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const } Database::invalidate_encoding_in_cache(requester.bare(), iid.get_server(), iid.get_local()); - options.save(Database::db); + save(options, *Database::db); } return true; } -- cgit v1.2.3 From e4f111accb8395dc8caf1dda92b8d903d3d78151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 13 Apr 2018 23:37:29 +0200 Subject: Remove two unused (julianday) functions --- src/utils/datetime.hpp | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src') diff --git a/src/utils/datetime.hpp b/src/utils/datetime.hpp index 27511f7..656b318 100644 --- a/src/utils/datetime.hpp +++ b/src/utils/datetime.hpp @@ -50,19 +50,7 @@ public: return this->t.time_since_epoch(); } - long double julianday() const - { - log_debug("ici?"); - auto res = ((static_cast(this->epoch().count()) / std::chrono::system_clock::period::den) / 86400) + 2440587.5; - return res; - } - private: std::string s; time_point t; }; - -inline long double to_julianday(std::time_t t) -{ - return static_cast(t) / 86400.0 + 2440587.5; -} -- cgit v1.2.3 From d375a9edeb7a2aa21497a2cbc1db0d3f703283a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 13 Apr 2018 23:37:46 +0200 Subject: one log_debug -> log_error, also some trivial indent --- src/database/postgresql_engine.cpp | 2 +- src/xmpp/biboumi_component.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/database/postgresql_engine.cpp b/src/database/postgresql_engine.cpp index abeb779..d97f2ff 100644 --- a/src/database/postgresql_engine.cpp +++ b/src/database/postgresql_engine.cpp @@ -128,7 +128,7 @@ void PostgresqlEngine::init_session() { const auto res = this->raw_exec("SET SESSION TIME ZONE 'UTC'"); if (!std::get(res)) - log_debug("Failed to set UTC timezone: ", std::get(res)); + log_error("Failed to set UTC timezone: ", std::get(res)); } long double PostgresqlEngine::epoch_to_floating_value(long double seconds) const { diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 9748258..acaac34 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -760,10 +760,10 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) lines.erase(lines.begin(), std::prev(lines.end(), 100)); } for (const Database::MucLogLine& line: lines) - { - if (!line.col().empty()) - this->send_archived_message(line, to.full(), from.full(), query_id); - } + { + if (!line.col().empty()) + this->send_archived_message(line, to.full(), from.full(), query_id); + } { auto fin_ptr = std::make_unique("fin"); { -- cgit v1.2.3 From 5ef7ba08028065b03d51d1dc70bb35aeb41ae19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 14 Apr 2018 19:48:45 +0200 Subject: Use the Date to find a next page in RSM, not the id This way, it works, whatever the order of insertion in the database was. fix #3343 --- src/bridge/bridge.cpp | 2 +- src/database/database.cpp | 9 +++++---- src/database/database.hpp | 2 +- src/xmpp/biboumi_component.cpp | 14 ++++++++------ 4 files changed, 15 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 2598f51..afc8ad3 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1005,7 +1005,7 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam auto limit = coptions.col(); if (history_limit.stanzas >= 0 && history_limit.stanzas < limit) limit = history_limit.stanzas; - const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, Id::unset_value, Database::Paging::last); + const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, {}, Database::Paging::last); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { diff --git a/src/database/database.cpp b/src/database/database.cpp index c935139..fb24ad3 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -192,7 +192,7 @@ std::string Database::store_muc_message(const std::string& owner, const std::str } std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start, const std::string& end, const Id::real_type reference_record_id, Database::Paging paging) + int limit, const std::string& start, const std::string& end, const std::string& reference_uuid, Database::Paging paging) { if (limit == 0) return {}; @@ -222,14 +222,15 @@ std::vector Database::get_muc_logs(const std::string& owne request << " and " << Database::Date{} << "<=" << writer; } } - if (reference_record_id != Id::unset_value) + if (!reference_uuid.empty()) { - request << " and " << Id{}; + request << " and " << Database::Date{}; if (paging == Database::Paging::first) request << ">"; else request << "<"; - request << reference_record_id; + request << "(SELECT " << Database::Date{} << " FROM " << Database::muc_log_lines.get_name().data() + << " WHERE " << Database::Uuid{} << " = " << reference_uuid << ")"; } if (paging == Database::Paging::first) diff --git a/src/database/database.hpp b/src/database/database.hpp index 75ff8f3..b4c4fa0 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -135,7 +135,7 @@ class Database */ static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit=-1, const std::string& start="", const std::string& end="", - const Id::real_type reference_record_id=Id::unset_value, Paging=Paging::first); + const std::string& reference_record_id={}, Paging=Paging::first); /** * Get just one single record matching the given uuid, between (optional) end and start. diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index acaac34..f82a923 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -719,7 +719,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) } const XmlNode* set = query->get_child("set", RSM_NS); int limit = -1; - Id::real_type reference_record_id{Id::unset_value}; + std::string reference_uuid{}; Database::Paging paging_order{Database::Paging::first}; if (set) { @@ -729,9 +729,10 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) const XmlNode* after = set->get_child("after", RSM_NS); if (after) { - auto after_record = Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), + // Will throw if the uuid does not exist, that’s all. + Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), after->get_inner(), start, end); - reference_record_id = after_record.col(); + reference_uuid = after->get_inner(); } const XmlNode* before = set->get_child("before", RSM_NS); if (before) @@ -739,8 +740,9 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) paging_order = Database::Paging::last; if (!before->get_inner().empty()) { - auto before_record = Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), before->get_inner(), start, end); - reference_record_id = before_record.col(); + // Will throw if the uuid does not exist + Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), before->get_inner(), start, end); + reference_uuid = before->get_inner(); } } } @@ -752,7 +754,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) if ((limit == -1 && start.empty() && end.empty()) || limit > 100) limit = 101; - auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, reference_record_id, paging_order); + auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, reference_uuid, paging_order); bool complete = true; if (lines.size() > 100) { -- cgit v1.2.3 From 39a32d55248808637cee78b9218053306964f7aa Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 31 Mar 2018 16:36:57 +0200 Subject: Use jid.bare() instead of manual concatenation --- src/bridge/bridge.cpp | 2 +- src/xmpp/adhoc_commands_handler.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index afc8ad3..7f21254 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -103,7 +103,7 @@ const std::string& Bridge::get_jid() const std::string Bridge::get_bare_jid() const { Jid jid(this->user_jid); - return jid.local + "@" + jid.domain; + return jid.bare(); } Xmpp::body Bridge::make_xmpp_body(const std::string& str, const std::string& encoding) diff --git a/src/xmpp/adhoc_commands_handler.cpp b/src/xmpp/adhoc_commands_handler.cpp index bb48781..60c85ae 100644 --- a/src/xmpp/adhoc_commands_handler.cpp +++ b/src/xmpp/adhoc_commands_handler.cpp @@ -41,7 +41,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co XmlSubNode condition(error, STANZA_NS":item-not-found"); } else if (command_it->second.is_admin_only() && - Config::get("admin", "") != jid.local + "@" + jid.domain) + Config::get("admin", "") != jid.bare()) { XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "cancel"; -- cgit v1.2.3 From a429b2ea271158fcda8a2f7a5b0179686bab3aa2 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 31 Mar 2018 16:55:15 +0200 Subject: Add a Config::is_in_list() method --- src/config/config.cpp | 17 ++++++++++++++--- src/config/config.hpp | 5 +++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/config/config.cpp b/src/config/config.cpp index 412b170..2f64b9e 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -1,10 +1,12 @@ #include #include +#include -#include -#include - +#include #include +#include +#include +#include using namespace std::string_literals; @@ -40,6 +42,15 @@ int Config::get_int(const std::string& option, const int& def) return def; } +bool Config::is_in_list(const std::string& option, const std::string& value) +{ + std::string res = Config::get(option, ""); + if (res.empty()) + return false; + std::vector list = utils::split(res, ':'); + return std::find(list.cbegin(), list.cend(), value) != list.cend(); +} + void Config::set(const std::string& option, const std::string& value, bool save) { Config::values[option] = value; diff --git a/src/config/config.hpp b/src/config/config.hpp index c5ef15d..9c28e8c 100644 --- a/src/config/config.hpp +++ b/src/config/config.hpp @@ -45,6 +45,11 @@ public: */ static int get_int(const std::string&, const int&); static bool get_bool(const std::string&, const bool); + /** + * Returns true if value is present in a colon-separated list, otherwise + * false. + */ + static bool is_in_list(const std::string& option, const std::string& value); /** * Set a value for the given option. And write all the config * in the file from which it was read if save is true. -- cgit v1.2.3 From 0d487f40c51463a15013255990f374fa9c41e590 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 31 Mar 2018 16:55:30 +0200 Subject: Use Config::is_in_list() to allow for multiple admins --- src/xmpp/adhoc_commands_handler.cpp | 2 +- src/xmpp/biboumi_adhoc_commands.cpp | 2 +- src/xmpp/biboumi_component.cpp | 9 +++------ 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/xmpp/adhoc_commands_handler.cpp b/src/xmpp/adhoc_commands_handler.cpp index 60c85ae..bc4c108 100644 --- a/src/xmpp/adhoc_commands_handler.cpp +++ b/src/xmpp/adhoc_commands_handler.cpp @@ -41,7 +41,7 @@ XmlNode AdhocCommandsHandler::handle_request(const std::string& executor_jid, co XmlSubNode condition(error, STANZA_NS":item-not-found"); } else if (command_it->second.is_admin_only() && - Config::get("admin", "") != jid.bare()) + !Config::is_in_list("admin", jid.bare())) { XmlSubNode error(command_node, ADHOC_NS":error"); error["type"] = "cancel"; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 82a1cbf..53806d6 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -658,7 +658,7 @@ bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const void DisconnectUserFromServerStep1(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node) { const Jid owner(session.get_owner_jid()); - if (owner.bare() != Config::get("admin", "")) + if (!Config::is_in_list("admin", owner.bare())) { // A non-admin is not allowed to disconnect other users, only // him/herself, so we just skip this step auto next_step = session.get_next_step(); diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index f82a923..9bcfa8a 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -551,24 +551,21 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) if (to.local.empty()) { // Get biboumi's adhoc commands this->send_adhoc_commands_list(id, from, this->served_hostname, - (Config::get("admin", "") == - from_jid.bare()), + Config::is_in_list("admin", from_jid.bare()), this->adhoc_commands_handler); stanza_error.disable(); } else if (iid.type == Iid::Type::Server) { // Get the server's adhoc commands this->send_adhoc_commands_list(id, from, to_str, - (Config::get("admin", "") == - from_jid.bare()), + Config::is_in_list("admin", from_jid.bare()), this->irc_server_adhoc_commands_handler); stanza_error.disable(); } else if (iid.type == Iid::Type::Channel && to.resource.empty()) { // Get the channel's adhoc commands this->send_adhoc_commands_list(id, from, to_str, - (Config::get("admin", "") == - from_jid.bare()), + Config::is_in_list("admin", from_jid.bare()), this->irc_channel_adhoc_commands_handler); stanza_error.disable(); } -- cgit v1.2.3 From a90f196a1ce779d502baf0aadff6e6917fec8a02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 24 Apr 2018 19:13:10 +0200 Subject: Revert "Use the Date to find a next page in RSM, not the id" This reverts commit 5ef7ba08028065b03d51d1dc70bb35aeb41ae19d. --- src/bridge/bridge.cpp | 2 +- src/database/database.cpp | 9 ++++----- src/database/database.hpp | 2 +- src/xmpp/biboumi_component.cpp | 14 ++++++-------- 4 files changed, 12 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 7f21254..defb9a5 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1005,7 +1005,7 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam auto limit = coptions.col(); if (history_limit.stanzas >= 0 && history_limit.stanzas < limit) limit = history_limit.stanzas; - const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, {}, Database::Paging::last); + const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, Id::unset_value, Database::Paging::last); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { diff --git a/src/database/database.cpp b/src/database/database.cpp index fb24ad3..c935139 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -192,7 +192,7 @@ std::string Database::store_muc_message(const std::string& owner, const std::str } std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start, const std::string& end, const std::string& reference_uuid, Database::Paging paging) + int limit, const std::string& start, const std::string& end, const Id::real_type reference_record_id, Database::Paging paging) { if (limit == 0) return {}; @@ -222,15 +222,14 @@ std::vector Database::get_muc_logs(const std::string& owne request << " and " << Database::Date{} << "<=" << writer; } } - if (!reference_uuid.empty()) + if (reference_record_id != Id::unset_value) { - request << " and " << Database::Date{}; + request << " and " << Id{}; if (paging == Database::Paging::first) request << ">"; else request << "<"; - request << "(SELECT " << Database::Date{} << " FROM " << Database::muc_log_lines.get_name().data() - << " WHERE " << Database::Uuid{} << " = " << reference_uuid << ")"; + request << reference_record_id; } if (paging == Database::Paging::first) diff --git a/src/database/database.hpp b/src/database/database.hpp index b4c4fa0..75ff8f3 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -135,7 +135,7 @@ class Database */ static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, int limit=-1, const std::string& start="", const std::string& end="", - const std::string& reference_record_id={}, Paging=Paging::first); + const Id::real_type reference_record_id=Id::unset_value, Paging=Paging::first); /** * Get just one single record matching the given uuid, between (optional) end and start. diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 9bcfa8a..95b38f0 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -716,7 +716,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) } const XmlNode* set = query->get_child("set", RSM_NS); int limit = -1; - std::string reference_uuid{}; + Id::real_type reference_record_id{Id::unset_value}; Database::Paging paging_order{Database::Paging::first}; if (set) { @@ -726,10 +726,9 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) const XmlNode* after = set->get_child("after", RSM_NS); if (after) { - // Will throw if the uuid does not exist, that’s all. - Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), + auto after_record = Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), after->get_inner(), start, end); - reference_uuid = after->get_inner(); + reference_record_id = after_record.col(); } const XmlNode* before = set->get_child("before", RSM_NS); if (before) @@ -737,9 +736,8 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) paging_order = Database::Paging::last; if (!before->get_inner().empty()) { - // Will throw if the uuid does not exist - Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), before->get_inner(), start, end); - reference_uuid = before->get_inner(); + auto before_record = Database::get_muc_log(from.bare(), iid.get_local(), iid.get_server(), before->get_inner(), start, end); + reference_record_id = before_record.col(); } } } @@ -751,7 +749,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) if ((limit == -1 && start.empty() && end.empty()) || limit > 100) limit = 101; - auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, reference_uuid, paging_order); + auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, reference_record_id, paging_order); bool complete = true; if (lines.size() > 100) { -- cgit v1.2.3 From 61de6b1dac4ef29627f3bdb9ce11b6c0d06f4a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 24 Apr 2018 19:19:06 +0200 Subject: Revert "Use a different Date data type" This reverts commit 857c7d3972a03cbeebf730d99b924d3710dee6a0. --- src/bridge/bridge.cpp | 4 +-- src/database/database.cpp | 43 +++++------------------- src/database/database.hpp | 30 +++-------------- src/database/datetime_writer.hpp | 32 ------------------ src/database/engine.hpp | 18 ++-------- src/database/insert_query.cpp | 21 ------------ src/database/insert_query.hpp | 22 +----------- src/database/postgresql_engine.cpp | 44 +++--------------------- src/database/postgresql_engine.hpp | 13 ++------ src/database/query.cpp | 16 --------- src/database/query.hpp | 10 ++---- src/database/select_query.cpp | 21 ------------ src/database/select_query.hpp | 31 ++--------------- src/database/sqlite3_engine.cpp | 68 ++++---------------------------------- src/database/sqlite3_engine.hpp | 11 ++---- src/database/table.hpp | 8 ++--- src/utils/datetime.hpp | 56 ------------------------------- src/xmpp/biboumi_component.cpp | 2 +- src/xmpp/xmpp_component.cpp | 4 +-- src/xmpp/xmpp_component.hpp | 3 +- 20 files changed, 45 insertions(+), 412 deletions(-) delete mode 100644 src/database/datetime_writer.hpp delete mode 100644 src/database/insert_query.cpp delete mode 100644 src/database/select_query.cpp delete mode 100644 src/utils/datetime.hpp (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index defb9a5..1c646fe 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1009,9 +1009,9 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { - const DateTime& datetime = line.col(); + const auto seconds = line.col(); this->xmpp.send_history_message(chan_name, line.col(), line.col(), - this->user_jid + "/" + resource, datetime); + this->user_jid + "/" + resource, seconds); } #else (void)hostname; diff --git a/src/database/database.cpp b/src/database/database.cpp index c935139..a09dfe3 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -48,7 +48,6 @@ void Database::open(const std::string& filename) Database::db = std::move(new_db); Database::muc_log_lines.create(*Database::db); Database::muc_log_lines.upgrade(*Database::db); - convert_date_format(*Database::db, Database::muc_log_lines); Database::global_options.create(*Database::db); Database::global_options.upgrade(*Database::db); Database::irc_server_options.create(*Database::db); @@ -60,9 +59,9 @@ void Database::open(const std::string& filename) Database::after_connection_commands.create(*Database::db); Database::after_connection_commands.upgrade(*Database::db); create_index(*Database::db, "archive_index", Database::muc_log_lines.get_name()); - Database::db->init_session(); } + Database::GlobalOptions Database::get_global_options(const std::string& owner) { auto request = select(Database::global_options); @@ -171,7 +170,7 @@ Database::IrcChannelOptions Database::get_irc_channel_options_with_server_and_gl } std::string Database::store_muc_message(const std::string& owner, const std::string& chan_name, - const std::string& server_name, DateTime::time_point date, + const std::string& server_name, Database::time_point date, const std::string& body, const std::string& nick) { auto line = Database::muc_log_lines.row(); @@ -182,7 +181,7 @@ std::string Database::store_muc_message(const std::string& owner, const std::str line.col() = owner; line.col() = chan_name; line.col() = server_name; - line.col() = date; + line.col() = std::chrono::duration_cast(date.time_since_epoch()).count(); line.col() = body; line.col() = nick; @@ -206,21 +205,13 @@ std::vector Database::get_muc_logs(const std::string& owne { const auto start_time = utils::parse_datetime(start); if (start_time != -1) - { - DateTime datetime(start_time); - DatetimeWriter writer(datetime, *Database::db); - request << " and " << Database::Date{} << ">=" << writer; - } + request << " and " << Database::Date{} << ">=" << start_time; } if (!end.empty()) { const auto end_time = utils::parse_datetime(end); if (end_time != -1) - { - DateTime datetime(end_time); - DatetimeWriter writer(datetime, *Database::db); - request << " and " << Database::Date{} << "<=" << writer; - } + request << " and " << Database::Date{} << "<=" << end_time; } if (reference_record_id != Id::unset_value) { @@ -233,9 +224,9 @@ std::vector Database::get_muc_logs(const std::string& owne } if (paging == Database::Paging::first) - request.order_by() << Database::Date{} << " ASC"; + request.order_by() << Database::Date{} << " ASC, " << Id{} << " ASC "; else - request.order_by() << Database::Date{} << " DESC"; + request.order_by() << Database::Date{} << " DESC, " << Id{} << " DESC "; if (limit >= 0) request.limit() << limit; @@ -261,21 +252,13 @@ Database::MucLogLine Database::get_muc_log(const std::string& owner, const std:: { const auto start_time = utils::parse_datetime(start); if (start_time != -1) - { - DateTime datetime(start_time); - DatetimeWriter writer(datetime, *Database::db); - request << " and " << Database::Date{} << ">=" << writer; - } + request << " and " << Database::Date{} << ">=" << start_time; } if (!end.empty()) { const auto end_time = utils::parse_datetime(end); if (end_time != -1) - { - DateTime datetime(end_time); - DatetimeWriter writer(datetime, *Database::db); - request << " and " << Database::Date{} << "<=" << writer; - } + request << " and " << Database::Date{} << "<=" << end_time; } auto result = request.execute(*Database::db); @@ -359,12 +342,4 @@ Transaction::~Transaction() log_error("Failed to end SQL transaction: ", std::get(result)); } } - -void Transaction::rollback() -{ - this->success = false; - const auto result = Database::raw_exec("ROLLBACK"); - if (std::get(result) == false) - log_error("Failed to rollback SQL transaction: ", std::get(result)); -} #endif diff --git a/src/database/database.hpp b/src/database/database.hpp index 75ff8f3..d986ecc 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -18,9 +17,11 @@ #include #include + class Database { public: + using time_point = std::chrono::system_clock::time_point; struct RecordNotFound: public std::exception {}; enum class Paging { first, last }; @@ -36,8 +37,7 @@ class Database struct Server: Column { static constexpr auto name = "server_"; }; - struct OldDate: Column { static constexpr auto name = "date_"; }; - struct Date: Column { static constexpr auto name = "date_"; }; + struct Date: Column { static constexpr auto name = "date_"; }; struct Body: Column { static constexpr auto name = "body_"; }; @@ -88,8 +88,6 @@ class Database using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; - using OldMucLogLineTable = Table; - using OldMucLogLine = OldMucLogLineTable::RowType; using GlobalOptionsTable = Table; using GlobalOptions = GlobalOptionsTable::RowType; @@ -143,7 +141,7 @@ class Database */ static MucLogLine get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, const std::string& uuid, const std::string& start="", const std::string& end=""); static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name, - DateTime::time_point date, const std::string& body, const std::string& nick); + time_point date, const std::string& body, const std::string& nick); static void add_roster_item(const std::string& local, const std::string& remote); static bool has_roster_item(const std::string& local, const std::string& remote); @@ -170,13 +168,6 @@ class Database static std::unique_ptr db; - static DatabaseEngine::EngineType engine_type() - { - if (Database::db) - return Database::db->engine_type(); - return DatabaseEngine::EngineType::None; - } - /** * Some caches, to avoid doing very frequent query requests for a few options. */ @@ -225,20 +216,7 @@ class Transaction public: Transaction(); ~Transaction(); - void rollback(); bool success{false}; }; -template -void convert_date_format(DatabaseEngine& db, Table table) -{ - const auto existing_columns = db.get_all_columns_from_table(table.get_name()); - const auto date_pair = existing_columns.find(Database::Date::name); - if (date_pair != existing_columns.end() && date_pair->second == "integer") - { - log_info("Converting Date_ format to the new one."); - db.convert_date_format(db); - } -} - #endif /* USE_DATABASE */ diff --git a/src/database/datetime_writer.hpp b/src/database/datetime_writer.hpp deleted file mode 100644 index b104911..0000000 --- a/src/database/datetime_writer.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -class DatetimeWriter -{ -public: - DatetimeWriter(DateTime datetime, const DatabaseEngine& engine): - datetime(datetime), - engine(engine) - {} - - long double get_value() const - { - const long double epoch_duration = this->datetime.epoch().count(); - const long double epoch_seconds = epoch_duration / std::chrono::system_clock::period::den; - return this->engine.epoch_to_floating_value(epoch_seconds); - } - std::string escape_param_number(int value) const - { - return this->engine.escape_param_number(value); - } - -private: - const DateTime datetime; - const DatabaseEngine& engine; -}; diff --git a/src/database/engine.hpp b/src/database/engine.hpp index ecf047f..41dccf5 100644 --- a/src/database/engine.hpp +++ b/src/database/engine.hpp @@ -13,7 +13,6 @@ #include #include #include -#include #include class DatabaseEngine @@ -28,10 +27,7 @@ class DatabaseEngine DatabaseEngine(DatabaseEngine&&) = delete; DatabaseEngine& operator=(DatabaseEngine&&) = delete; - enum class EngineType { None, Postgresql, Sqlite3, }; - virtual EngineType engine_type() const = 0; - - virtual std::map get_all_columns_from_table(const std::string& table_name) = 0; + virtual std::set get_all_columns_from_table(const std::string& table_name) = 0; virtual std::tuple raw_exec(const std::string& query) = 0; virtual std::unique_ptr prepare(const std::string& query) = 0; virtual void extract_last_insert_rowid(Statement& statement) = 0; @@ -39,17 +35,7 @@ class DatabaseEngine { return {}; } - virtual void convert_date_format(DatabaseEngine&) = 0; - virtual std::string id_column_type() const = 0; - virtual std::string datetime_column_type() const = 0; - virtual long double epoch_to_floating_value(long double seconds) const = 0; - virtual std::string escape_param_number(int nb) const - { - return "$" + std::to_string(nb); - } - virtual void init_session() - { - } + virtual std::string id_column_type() = 0; int64_t last_inserted_rowid{-1}; }; diff --git a/src/database/insert_query.cpp b/src/database/insert_query.cpp deleted file mode 100644 index f72d67f..0000000 --- a/src/database/insert_query.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -template <> -std::string before_value() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return "julianday("; - if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return "to_timestamp("; - return {}; -} - -template <> -std::string after_value() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return ", \"unixepoch\")"; - if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return ")"; - return {}; -} diff --git a/src/database/insert_query.hpp b/src/database/insert_query.hpp index cd1942f..230e873 100644 --- a/src/database/insert_query.hpp +++ b/src/database/insert_query.hpp @@ -30,24 +30,6 @@ typename std::enable_if::type update_autoincrement_id(std::tuple&, Statement&) {} -template -std::string before_value() -{ - return {}; -} - -template -std::string after_value() -{ - return {}; -} - -template <> -std::string before_value(); - -template <> -std::string after_value(); - struct InsertQuery: public Query { template @@ -96,7 +78,7 @@ struct InsertQuery: public Query template void insert_values(const std::tuple& columns) { - this->body += " VALUES ("; + this->body += "VALUES ("; this->insert_value(columns); this->body += ")"; } @@ -109,9 +91,7 @@ struct InsertQuery: public Query if (!std::is_same::value) { - this->body += before_value(); this->body += "$" + std::to_string(index++); - this->body += after_value(); if (N != sizeof...(T) - 1) this->body += ", "; } diff --git a/src/database/postgresql_engine.cpp b/src/database/postgresql_engine.cpp index d97f2ff..59bc885 100644 --- a/src/database/postgresql_engine.cpp +++ b/src/database/postgresql_engine.cpp @@ -2,7 +2,6 @@ #ifdef PQ_FOUND #include -#include #include @@ -13,7 +12,6 @@ #include #include -#include PostgresqlEngine::PostgresqlEngine(PGconn*const conn): conn(conn) @@ -54,14 +52,14 @@ std::unique_ptr PostgresqlEngine::open(const std::string& connin return std::make_unique(con); } -std::map PostgresqlEngine::get_all_columns_from_table(const std::string& table_name) +std::set PostgresqlEngine::get_all_columns_from_table(const std::string& table_name) { - const auto query = "SELECT column_name, data_type from information_schema.columns where table_name='" + table_name + "'"; + const auto query = "SELECT column_name from information_schema.columns where table_name='" + table_name + "'"; auto statement = this->prepare(query); - std::map columns; + std::set columns; while (statement->step() == StepResult::Row) - columns[utils::tolower(statement->get_column_text(0))] = utils::tolower(statement->get_column_text(1)); + columns.insert(statement->get_column_text(0)); return columns; } @@ -98,41 +96,9 @@ std::string PostgresqlEngine::get_returning_id_sql_string(const std::string& col return " RETURNING " + col_name; } -std::string PostgresqlEngine::id_column_type() const +std::string PostgresqlEngine::id_column_type() { return "SERIAL"; } -std::string PostgresqlEngine::datetime_column_type() const -{ - return "TIMESTAMP"; -} - -void PostgresqlEngine::convert_date_format(DatabaseEngine& db) -{ - const auto table_name = Database::muc_log_lines.get_name(); - const std::string column_name = Database::Date::name; - const std::string query = "ALTER TABLE " + table_name + " ALTER COLMUN " + column_name + " SET DATA TYPE timestamp USING to_timestamp(" + column_name + ")"; - - auto result = db.raw_exec(query); - if (!std::get(result)) - log_error("Failed to execute query: ", std::get(result)); -} - -std::string PostgresqlEngine::escape_param_number(int nb) const -{ - return "to_timestamp(" + DatabaseEngine::escape_param_number(nb) + ")"; -} - -void PostgresqlEngine::init_session() -{ - const auto res = this->raw_exec("SET SESSION TIME ZONE 'UTC'"); - if (!std::get(res)) - log_error("Failed to set UTC timezone: ", std::get(res)); -} -long double PostgresqlEngine::epoch_to_floating_value(long double seconds) const -{ - return seconds; -} - #endif diff --git a/src/database/postgresql_engine.hpp b/src/database/postgresql_engine.hpp index 70215d4..1a9c249 100644 --- a/src/database/postgresql_engine.hpp +++ b/src/database/postgresql_engine.hpp @@ -23,22 +23,13 @@ class PostgresqlEngine: public DatabaseEngine ~PostgresqlEngine(); static std::unique_ptr open(const std::string& string); - EngineType engine_type() const override - { - return EngineType::Postgresql; - } - std::map get_all_columns_from_table(const std::string& table_name) override final; + std::set get_all_columns_from_table(const std::string& table_name) override final; std::tuple raw_exec(const std::string& query) override final; std::unique_ptr prepare(const std::string& query) override; void extract_last_insert_rowid(Statement& statement) override; std::string get_returning_id_sql_string(const std::string& col_name) override; - std::string id_column_type() const override; - std::string datetime_column_type() const override; - void convert_date_format(DatabaseEngine& engine) override; - long double epoch_to_floating_value(long double seconds) const override; - void init_session() override; - std::string escape_param_number(int nb) const override; + std::string id_column_type() override; private: PGconn* const conn; }; diff --git a/src/database/query.cpp b/src/database/query.cpp index 6d20302..d72066e 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -21,13 +21,6 @@ void actual_bind(Statement& statement, const OptionalBool& value, int index) statement.bind_int64(index, -1); } -void actual_bind(Statement& statement, const DateTime& value, int index) -{ - const auto epoch = value.epoch().count(); - const auto result = std::to_string(static_cast(epoch) / std::chrono::system_clock::period::den); - statement.bind_text(index, result); -} - void actual_add_param(Query& query, const std::string& val) { query.params.push_back(val); @@ -56,12 +49,3 @@ Query& operator<<(Query& query, const std::string& str) actual_add_param(query, str); return query; } - -Query& operator<<(Query& query, const DatetimeWriter& datetime_writer) -{ - query.body += datetime_writer.escape_param_number(query.current_param++); - actual_add_param(query, datetime_writer.get_value()); - return query; -} - - diff --git a/src/database/query.hpp b/src/database/query.hpp index 910271a..ba28b1a 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -3,7 +3,6 @@ #include #include -#include #include #include @@ -11,7 +10,6 @@ #include #include -#include void actual_bind(Statement& statement, const std::string& value, int index); void actual_bind(Statement& statement, const std::int64_t& value, int index); @@ -21,7 +19,6 @@ void actual_bind(Statement& statement, const T& value, int index) actual_bind(statement, static_cast(value), index); } void actual_bind(Statement& statement, const OptionalBool& value, int index); -void actual_bind(Statement& statement, const DateTime& value, int index); #ifdef DEBUG_SQL_QUERIES #include @@ -77,13 +74,15 @@ void actual_add_param(Query& query, const std::string& val); void actual_add_param(Query& query, const OptionalBool& val); template -typename std::enable_if::value, Query&>::type +typename std::enable_if::value, Query&>::type operator<<(Query& query, const T&) { query.body += T::name; return query; } +Query& operator<<(Query& query, const char* str); +Query& operator<<(Query& query, const std::string& str); template typename std::enable_if::value, Query&>::type operator<<(Query& query, const Integer& i) @@ -93,6 +92,3 @@ operator<<(Query& query, const Integer& i) return query; } -Query& operator<<(Query& query, const char* str); -Query& operator<<(Query& query, const std::string& str); -Query& operator<<(Query& query, const DatetimeWriter& datetime); diff --git a/src/database/select_query.cpp b/src/database/select_query.cpp deleted file mode 100644 index 970b06c..0000000 --- a/src/database/select_query.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include - -template <> -std::string before_column() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return "strftime(\"%Y-%m-%dT%H:%M:%SZ\", "; - else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return "to_char("; - return {}; -} - -template <> -std::string after_column() -{ - if (Database::engine_type() == DatabaseEngine::EngineType::Sqlite3) - return ")"; - else if (Database::engine_type() == DatabaseEngine::EngineType::Postgresql) - return R"(, 'YYYY-MM-DD"T"HH24:MM:SS"Z"'))"; - return {}; -} diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index 0de4fe5..b9fdc06 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include #include #include @@ -43,14 +43,6 @@ extract_row_value(Statement& statement, const int i) return result; } -template -typename std::enable_if::value, T>::type -extract_row_value(Statement& statement, const int i) -{ - const std::string timestamp = statement.get_column_text(i); - return {timestamp}; -} - template typename std::enable_if::type extract_row_values(Row& row, Statement& statement) @@ -68,24 +60,6 @@ typename std::enable_if::type extract_row_values(Row&, Statement&) {} -template -std::string before_column() -{ - return {}; -} - -template -std::string after_column() -{ - return {}; -} - -template <> -std::string before_column(); - -template <> -std::string after_column(); - template struct SelectQuery: public Query { @@ -104,8 +78,7 @@ struct SelectQuery: public Query using ColumnsType = std::tuple; using ColumnType = typename std::remove_reference(std::declval()))>::type; - this->body += " "; - this->body += before_column() + ColumnType::name + after_column(); + this->body += " " + std::string{ColumnType::name}; if (N < (sizeof...(T) - 1)) this->body += ", "; diff --git a/src/database/sqlite3_engine.cpp b/src/database/sqlite3_engine.cpp index b6ac1a1..5e3bba1 100644 --- a/src/database/sqlite3_engine.cpp +++ b/src/database/sqlite3_engine.cpp @@ -2,10 +2,7 @@ #ifdef SQLITE3_FOUND -#include -#include #include - #include #include @@ -24,17 +21,16 @@ Sqlite3Engine::~Sqlite3Engine() sqlite3_close(this->db); } -std::map Sqlite3Engine::get_all_columns_from_table(const std::string& table_name) +std::set Sqlite3Engine::get_all_columns_from_table(const std::string& table_name) { - std::map result; + std::set result; char* errmsg; std::string query{"PRAGMA table_info(" + table_name + ")"}; int res = sqlite3_exec(this->db, query.data(), [](void* param, int columns_nb, char** columns, char**) -> int { constexpr int name_column = 1; - constexpr int data_type_column = 2; - auto* result = static_cast*>(param); - if (name_column < columns_nb && data_type_column < columns_nb) - (*result)[utils::tolower(columns[name_column])] = utils::tolower(columns[data_type_column]); + std::set* result = static_cast*>(param); + if (name_column < columns_nb) + result->insert(utils::tolower(columns[name_column])); return 0; }, &result, &errmsg); @@ -47,48 +43,6 @@ std::map Sqlite3Engine::get_all_columns_from_table(con return result; } -template -static auto make_select_query(const Row&, const std::string& name) -{ - return SelectQuery{name}; -} - -void Sqlite3Engine::convert_date_format(DatabaseEngine& db) -{ - Transaction transaction{}; - auto rollback = [&transaction] (const std::string& error_msg) - { - log_error("Failed to execute query: ", error_msg); - transaction.rollback(); - }; - - const auto real_name = Database::muc_log_lines.get_name(); - const auto tmp_name = real_name + "tmp_"; - const std::string date_name = Database::Date::name; - - auto result = db.raw_exec("ALTER TABLE " + real_name + " RENAME TO " + tmp_name); - if (!std::get(result)) - return rollback(std::get(result)); - - Database::muc_log_lines.create(db); - - Database::OldMucLogLineTable old_muc_log_line(tmp_name); - auto select_query = make_select_query(old_muc_log_line.row(), old_muc_log_line.get_name()); - - auto& select_body = select_query.body; - auto begin = select_body.find(date_name); - select_body.replace(begin, date_name.size(), "julianday("+date_name+", 'unixepoch')"); - select_body = "INSERT INTO " + real_name + " " + select_body; - - result = db.raw_exec(select_body); - if (!std::get(result)) - return rollback(std::get(result)); - - result = db.raw_exec("DROP TABLE " + tmp_name); - if (!std::get(result)) - return rollback(std::get(result)); -} - std::unique_ptr Sqlite3Engine::open(const std::string& filename) { sqlite3* new_db; @@ -138,19 +92,9 @@ void Sqlite3Engine::extract_last_insert_rowid(Statement&) this->last_inserted_rowid = sqlite3_last_insert_rowid(this->db); } -std::string Sqlite3Engine::id_column_type() const +std::string Sqlite3Engine::id_column_type() { return "INTEGER PRIMARY KEY AUTOINCREMENT"; } -std::string Sqlite3Engine::datetime_column_type() const -{ - return "REAL"; -} - -long double Sqlite3Engine::epoch_to_floating_value(long double d) const -{ - return (d / 86400.0) + 2440587.5; -} - #endif diff --git a/src/database/sqlite3_engine.hpp b/src/database/sqlite3_engine.hpp index 1b37e8c..a7bfcdb 100644 --- a/src/database/sqlite3_engine.hpp +++ b/src/database/sqlite3_engine.hpp @@ -23,19 +23,12 @@ class Sqlite3Engine: public DatabaseEngine ~Sqlite3Engine(); static std::unique_ptr open(const std::string& string); - EngineType engine_type() const override - { - return EngineType::Sqlite3; - } - std::map get_all_columns_from_table(const std::string& table_name) override final; + std::set get_all_columns_from_table(const std::string& table_name) override final; std::tuple raw_exec(const std::string& query) override final; std::unique_ptr prepare(const std::string& query) override; void extract_last_insert_rowid(Statement& statement) override; - std::string id_column_type() const override; - std::string datetime_column_type() const override; - void convert_date_format(DatabaseEngine&) override; - long double epoch_to_floating_value(long double d) const override; + std::string id_column_type() override; private: sqlite3* const db; }; diff --git a/src/database/table.hpp b/src/database/table.hpp index 4c96151..0b8bfc0 100644 --- a/src/database/table.hpp +++ b/src/database/table.hpp @@ -18,8 +18,6 @@ std::string ToSQLType(DatabaseEngine& db) return db.id_column_type(); else if (std::is_same::value) return "TEXT"; - else if (std::is_same::value) - return db.datetime_column_type(); else return "INTEGER"; } @@ -98,16 +96,16 @@ class Table template typename std::enable_if::type - add_column_if_not_exists(DatabaseEngine& db, const std::map& existing_columns) + add_column_if_not_exists(DatabaseEngine& db, const std::set& existing_columns) { using ColumnType = typename std::remove_reference(std::declval()))>::type; - if (existing_columns.find(ColumnType::name) == existing_columns.end()) + if (existing_columns.count(ColumnType::name) == 0) add_column_to_table(db, this->name); add_column_if_not_exists(db, existing_columns); } template typename std::enable_if::type - add_column_if_not_exists(DatabaseEngine&, const std::map&) + add_column_if_not_exists(DatabaseEngine&, const std::set&) {} template diff --git a/src/utils/datetime.hpp b/src/utils/datetime.hpp deleted file mode 100644 index 656b318..0000000 --- a/src/utils/datetime.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include - -#include - -class DateTime -{ -public: - enum class Engine { - Postgresql, - Sqlite3, - } engine{Engine::Sqlite3}; - - using time_point = std::chrono::system_clock::time_point; - - DateTime(): - s{}, - t{} - { } - - DateTime(std::time_t t): - t(std::chrono::seconds(t)) - {} - - DateTime(std::string s): - s(std::move(s)) - {} - - DateTime& operator=(const std::string& s) - { - this->s = s; - return *this; - } - - DateTime& operator=(const time_point t) - { - this->t = t; - return *this; - } - - const std::string& to_string() const - { - return this->s; - } - - time_point::duration epoch() const - { - return this->t.time_since_epoch(); - } - -private: - std::string s; - time_point t; -}; diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 95b38f0..6dc5fc5 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -805,7 +805,7 @@ void BiboumiComponent::send_archived_message(const Database::MucLogLine& log_lin XmlSubNode delay(forwarded, "delay"); delay["xmlns"] = DELAY_NS; - delay["stamp"] = log_line.col().to_string(); + delay["stamp"] = utils::to_string(log_line.col()); XmlSubNode submessage(forwarded, "message"); submessage["xmlns"] = CLIENT_NS; diff --git a/src/xmpp/xmpp_component.cpp b/src/xmpp/xmpp_component.cpp index bec88ea..b3d925e 100644 --- a/src/xmpp/xmpp_component.cpp +++ b/src/xmpp/xmpp_component.cpp @@ -399,7 +399,7 @@ void XmppComponent::send_muc_message(const std::string& muc_name, const std::str } #ifdef USE_DATABASE -void XmppComponent::send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body_txt, const std::string& jid_to, const DateTime& timestamp) +void XmppComponent::send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body_txt, const std::string& jid_to, Database::time_point::rep timestamp) { Stanza message("message"); message["to"] = jid_to; @@ -417,7 +417,7 @@ void XmppComponent::send_history_message(const std::string& muc_name, const std: XmlSubNode delay(message, "delay"); delay["xmlns"] = DELAY_NS; delay["from"] = muc_name + "@" + this->served_hostname; - delay["stamp"] = timestamp.to_string(); + delay["stamp"] = utils::to_string(timestamp); } this->send_stanza(message); diff --git a/src/xmpp/xmpp_component.hpp b/src/xmpp/xmpp_component.hpp index 960c801..e18da40 100644 --- a/src/xmpp/xmpp_component.hpp +++ b/src/xmpp/xmpp_component.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -142,7 +141,7 @@ public: * Send a message, with a element, part of a MUC history */ void send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body, - const std::string& jid_to, const DateTime& timestamp); + const std::string& jid_to, Database::time_point::rep timestamp); #endif /** * Send an unavailable presence for this nick -- cgit v1.2.3 From 1236b8a03bee403fcaa59d882d8e7fb9058b2280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 24 Apr 2018 20:24:58 +0200 Subject: Only use the ID to order archives fix #3343 --- src/database/database.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/database/database.cpp b/src/database/database.cpp index a09dfe3..3b3e890 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -224,9 +224,9 @@ std::vector Database::get_muc_logs(const std::string& owne } if (paging == Database::Paging::first) - request.order_by() << Database::Date{} << " ASC, " << Id{} << " ASC "; + request.order_by() << Id{} << " ASC "; else - request.order_by() << Database::Date{} << " DESC, " << Id{} << " DESC "; + request.order_by() << Id{} << " DESC "; if (limit >= 0) request.limit() << limit; -- cgit v1.2.3 From d887baa064318fdb350fb6c3f7b8e2104a644fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 28 Apr 2018 13:55:35 +0200 Subject: Fix a crash when botan policy does not allow any available ciphersuite --- src/network/tcp_client_socket_handler.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/network/tcp_client_socket_handler.cpp b/src/network/tcp_client_socket_handler.cpp index aac13d0..9dda73d 100644 --- a/src/network/tcp_client_socket_handler.cpp +++ b/src/network/tcp_client_socket_handler.cpp @@ -146,15 +146,22 @@ void TCPClientSocketHandler::connect(const std::string& address, const std::stri || errno == EISCONN) { log_info("Connection success."); +#ifdef BOTAN_FOUND + if (this->use_tls) + try { + this->start_tls(this->address, this->port); + } catch (const Botan::Exception& e) + { + this->on_connection_failed("TLS error: "s + e.what()); + this->close(); + return ; + } +#endif TimedEventsManager::instance().cancel("connection_timeout" + std::to_string(this->socket)); this->poller->add_socket_handler(this); this->connected = true; this->connecting = false; -#ifdef BOTAN_FOUND - if (this->use_tls) - this->start_tls(this->address, this->port); -#endif this->connection_date = std::chrono::system_clock::now(); // Get our local TCP port and store it -- cgit v1.2.3 From 7592d966e684410f603942e34413375c8d98ac9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 29 Apr 2018 01:40:46 +0200 Subject: Missing fields in a data-form response are now interpreted as an empty value --- src/database/column.hpp | 16 ++++++++++++++-- src/database/database.hpp | 10 +++++----- src/database/row.hpp | 21 ++++++++++++++++++--- src/xmpp/biboumi_adhoc_commands.cpp | 5 ++++- 4 files changed, 41 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/database/column.hpp b/src/database/column.hpp index 50c9c14..837aa3f 100644 --- a/src/database/column.hpp +++ b/src/database/column.hpp @@ -9,18 +9,30 @@ struct Column value{default_value} {} Column(): value{} {} + void clear() + { + this->value = {}; + } using real_type = T; T value{}; }; +template +struct UnclearableColumn: public Column +{ + using Column::Column; + void clear() + { } +}; + struct ForeignKey: Column { static constexpr auto name = "fk_"; }; -struct Id: Column { +struct Id: UnclearableColumn { static constexpr std::size_t unset_value = static_cast(-1); static constexpr auto name = "id_"; static constexpr auto options = "PRIMARY KEY"; - Id(): Column(unset_value) {} + Id(): UnclearableColumn(unset_value) {} }; diff --git a/src/database/database.hpp b/src/database/database.hpp index d986ecc..30ffcb4 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -27,15 +27,15 @@ class Database struct Uuid: Column { static constexpr auto name = "uuid_"; }; - struct Owner: Column { static constexpr auto name = "owner_"; }; + struct Owner: UnclearableColumn { static constexpr auto name = "owner_"; }; - struct IrcChanName: Column { static constexpr auto name = "ircchanname_"; }; + struct IrcChanName: UnclearableColumn { static constexpr auto name = "ircchanname_"; }; - struct Channel: Column { static constexpr auto name = "channel_"; }; + struct Channel: UnclearableColumn { static constexpr auto name = "channel_"; }; - struct IrcServerName: Column { static constexpr auto name = "ircservername_"; }; + struct IrcServerName: UnclearableColumn { static constexpr auto name = "ircservername_"; }; - struct Server: Column { static constexpr auto name = "server_"; }; + struct Server: UnclearableColumn { static constexpr auto name = "server_"; }; struct Date: Column { static constexpr auto name = "date_"; }; diff --git a/src/database/row.hpp b/src/database/row.hpp index 27caf43..1253f93 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include template @@ -25,7 +23,24 @@ struct Row return col.value; } -public: + void clear() + { + this->clear_col<0>(); + } + std::tuple columns; std::string table_name; + +private: + template + typename std::enable_if::type + clear_col() + { + std::get(this->columns).clear(); + this->clear_col(); + } + template + typename std::enable_if::type + clear_col() + { } }; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 53806d6..b62dcfc 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -177,6 +177,7 @@ void ConfigureGlobalStep2(XmppComponent& xmpp_component, AdhocSession& session, { const Jid owner(session.get_owner_jid()); auto options = Database::get_global_options(owner.bare()); + options.clear(); for (const XmlNode* field: x->get_children("field", "jabber:x:data")) { const XmlNode* value = field->get_child("value", "jabber:x:data"); @@ -400,7 +401,8 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com server_domain = target.local; auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain, server_domain); - auto commands = Database::get_after_connection_commands(options); + options.clear(); + Database::AfterConnectionCommands commands{}; for (const XmlNode* field: x->get_children("field", "jabber:x:data")) { @@ -608,6 +610,7 @@ bool handle_irc_channel_configuration_form(XmppComponent& xmpp_component, const const Iid iid(target.local, {}); auto options = Database::get_irc_channel_options(requester.bare(), iid.get_server(), iid.get_local()); + options.clear(); for (const XmlNode *field: x->get_children("field", "jabber:x:data")) { const XmlNode *value = field->get_child("value", "jabber:x:data"); -- cgit v1.2.3 From b0168fd45b3683c2d6f61ccae67dcd5b918a363d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 29 Apr 2018 22:18:26 +0200 Subject: =?UTF-8?q?mam:=20Send=20=E2=80=9Cfin=20complete=E2=80=9D=20only?= =?UTF-8?q?=20when=20appropriate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also simplify how we did the whole “limit + 1” And fix one bad interpretation of the XEP for the case where the query has no after or before restriction. fix #3349 --- src/bridge/bridge.cpp | 3 ++- src/database/database.cpp | 26 +++++++++++++++++--------- src/database/database.hpp | 4 ++-- src/xmpp/biboumi_component.cpp | 22 +++++++++------------- 4 files changed, 30 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 1c646fe..7a0157a 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1005,7 +1005,8 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam auto limit = coptions.col(); if (history_limit.stanzas >= 0 && history_limit.stanzas < limit) limit = history_limit.stanzas; - const auto lines = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, Id::unset_value, Database::Paging::last); + const auto result = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, Id::unset_value, Database::Paging::last); + const auto& lines = std::get<1>(result); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) { diff --git a/src/database/database.cpp b/src/database/database.cpp index 3b3e890..6e08ee1 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -190,12 +190,9 @@ std::string Database::store_muc_message(const std::string& owner, const std::str return uuid; } -std::vector Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit, const std::string& start, const std::string& end, const Id::real_type reference_record_id, Database::Paging paging) +std::tuple> Database::get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, + std::size_t limit, const std::string& start, const std::string& end, const Id::real_type reference_record_id, Database::Paging paging) { - if (limit == 0) - return {}; - auto request = select(Database::muc_log_lines); request.where() << Database::Owner{} << "=" << owner << \ " and " << Database::IrcChanName{} << "=" << chan_name << \ @@ -228,15 +225,26 @@ std::vector Database::get_muc_logs(const std::string& owne else request.order_by() << Id{} << " DESC "; - if (limit >= 0) - request.limit() << limit; + // Just a simple trick: to know whether we got the totality of the + // possible results matching this query (except for the limit), we just + // ask one more element. If we get that additional element, this means + // we don’t have everything. And then we just discard it. If we don’t + // have more, this means we have everything. + request.limit() << limit + 1; auto result = request.execute(*Database::db); + bool complete = true; + + if (result.size() == limit + 1) + { + complete = false; + result.erase(std::prev(result.end())); + } if (paging == Database::Paging::first) - return result; + return {complete, result}; else - return {result.crbegin(), result.crend()}; + return {complete, {result.crbegin(), result.crend()}}; } Database::MucLogLine Database::get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, diff --git a/src/database/database.hpp b/src/database/database.hpp index 30ffcb4..3e25b30 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -131,8 +131,8 @@ class Database * Get all the lines between (optional) start and end dates, with a (optional) limit. * If after_id is set, only the records after it will be returned. */ - static std::vector get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, - int limit=-1, const std::string& start="", const std::string& end="", + static std::tuple> get_muc_logs(const std::string& owner, const std::string& chan_name, const std::string& server, + std::size_t limit, const std::string& start="", const std::string& end="", const Id::real_type reference_record_id=Id::unset_value, Paging=Paging::first); /** diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 6dc5fc5..dbaf8a4 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -743,19 +743,15 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) } // Do not send more than 100 messages, even if the client asked for more, // or if it didn’t specify any limit. - // 101 is just a trick to know if there are more available messages. - // If our query returns 101 message, we know it’s incomplete, but we - // still send only 100 - if ((limit == -1 && start.empty() && end.empty()) - || limit > 100) - limit = 101; - auto lines = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), limit, start, end, reference_record_id, paging_order); - bool complete = true; - if (lines.size() > 100) - { - complete = false; - lines.erase(lines.begin(), std::prev(lines.end(), 100)); - } + if (limit < 0 || limit > 100) + limit = 100; + auto result = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), + limit, + start, end, + reference_record_id, paging_order); + bool complete = std::get(result); + auto& lines = std::get<1>(result); + for (const Database::MucLogLine& line: lines) { if (!line.col().empty()) -- cgit v1.2.3 From ed36c26598892c60c6d2c9a096f536cc1f4705cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 6 May 2018 12:11:51 +0200 Subject: Also handle SIGHUP to reload the configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because that’s what is typically done on other deamons, and we don’t want to suprise users. --- src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 59fda4e..09adc5c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -103,6 +103,7 @@ int main(int ac, char** av) sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGUSR1); sigaddset(&mask, SIGUSR2); + sigaddset(&mask, SIGHUP); sigprocmask(SIG_BLOCK, &mask, nullptr); // Install the signals used to exit the process cleanly, or reload the @@ -124,6 +125,7 @@ int main(int ac, char** av) on_sigusr.sa_flags = 0; sigaction(SIGUSR1, &on_sigusr, nullptr); sigaction(SIGUSR2, &on_sigusr, nullptr); + sigaction(SIGHUP, &on_sigusr, nullptr); auto p = std::make_shared(); -- cgit v1.2.3 From ba61d2034058818fe76cef6b23f311259d37b3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 14 May 2018 22:03:26 +0200 Subject: Empty the nodes before reusing them in our responses fix #3356 --- src/xmpp/biboumi_adhoc_commands.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index b62dcfc..5a0aba8 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -116,6 +116,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman auto options = Database::get_global_options(owner.bare()); + command_node.delete_all_children(); XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; XmlSubNode title(x, "title"); @@ -223,6 +224,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com server_domain); auto commands = Database::get_after_connection_commands(options); + command_node.delete_all_children(); XmlSubNode x(command_node, "jabber:x:data:x"); x["type"] = "form"; XmlSubNode title(x, "title"); @@ -508,6 +510,7 @@ 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()); + node.delete_all_children(); XmlSubNode x(node, "jabber:x:data:x"); x["type"] = "form"; XmlSubNode title(x, "title"); -- cgit v1.2.3 From 4f6bf078d2e60cab47f43a09decc12aa4fba08ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 15 May 2018 19:29:37 +0200 Subject: Improve the forward_server_message to concatenate everything --- src/irc/irc_client.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 8f77e0d..fca043c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -536,7 +536,9 @@ void IrcClient::send_ping_command() void IrcClient::forward_server_message(const IrcMessage& message) { const std::string from = message.prefix; - const std::string body = message.arguments[1]; + std::string body; + for (auto it = std::next(message.arguments.begin()); it != message.arguments.end(); ++it) + body += *it + ' '; this->bridge.send_xmpp_message(this->hostname, from, body); } -- cgit v1.2.3 From a8e922fc890a8ef2c1c43b940f0cfc3768ea1cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 15 May 2018 19:31:26 +0200 Subject: Handle the NAMES message for an already-joined or non-existing channel If a user manually does a NAMES query, the result were interpreted as a user list, which is wrong. And with the special * argument, this would even cause a crash. Fix #3357 --- src/irc/irc_client.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index fca043c..d0b2153 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -641,6 +641,11 @@ void IrcClient::set_and_forward_user_list(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[2]); IrcChannel* channel = this->get_channel(chan_name); + if (channel->joined) + { + this->forward_server_message(message); + return; + } std::vector nicks = utils::split(message.arguments[3], ' '); for (const std::string& nick: nicks) { @@ -776,6 +781,16 @@ void IrcClient::on_channel_completely_joined(const IrcMessage& message) { const std::string chan_name = utils::tolower(message.arguments[1]); IrcChannel* channel = this->get_channel(chan_name); + if (chan_name == "*" || channel->joined) + { + this->forward_server_message(message); + return; + } + if (!channel->get_self()) + { + log_error("End of NAMES list but we never received our own nick."); + return; + } channel->joined = true; this->bridge.send_user_join(this->hostname, chan_name, channel->get_self(), channel->get_self()->get_most_significant_mode(this->sorted_user_modes), true); -- cgit v1.2.3 From 7d3c1ed92733a05ab4282993ffe58fb88a1b50e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 23 May 2018 01:09:19 +0200 Subject: Do not use (or present to the user) the Address field in fixed mode fix #3359 --- src/irc/irc_client.cpp | 3 ++- src/xmpp/biboumi_adhoc_commands.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d0b2153..d7fa2cd 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -195,7 +195,8 @@ void IrcClient::start() # ifdef BOTAN_FOUND this->credential_manager.set_trusted_fingerprint(options.col()); # endif - if (!options.col().empty()) + if (Config::get("fixed_irc_server", "").empty() && + !options.col().empty()) address = options.col(); #endif this->bridge.send_xmpp_message(this->hostname, "", "Connecting to " + diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index b62dcfc..3bd2e5a 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -230,6 +230,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com XmlSubNode instructions(x, "instructions"); instructions.set_inner("Edit the form, to configure the settings of the IRC server " + server_domain); + if (Config::get("fixed_irc_server", "").empty()) { XmlSubNode field(x, "field"); field["var"] = "address"; @@ -409,7 +410,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com const XmlNode* value = field->get_child("value", "jabber:x:data"); const std::vector values = field->get_children("value", "jabber:x:data"); - if (field->get_tag("var") == "address" && value) + if (field->get_tag("var") == "address" && value && Config::get("fixed_irc_server", "").empty()) options.col() = value->get_inner(); if (field->get_tag("var") == "ports") -- cgit v1.2.3 From 760076a33aa50c700bc0d825e5cb9d0fa9d5bd17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 1 Jun 2018 12:29:04 +0200 Subject: Make the global ad-hoc configure command available in fixed mode fix #3360 --- src/xmpp/biboumi_component.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index dbaf8a4..be34873 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -72,11 +72,16 @@ BiboumiComponent::BiboumiComponent(std::shared_ptr& poller, const std::s AdhocCommand configure_global_command({&ConfigureGlobalStep1, &ConfigureGlobalStep2}, "Configure a few settings", false); if (!Config::get("fixed_irc_server", "").empty()) - this->adhoc_commands_handler.add_command("configure", configure_server_command); + { + this->adhoc_commands_handler.add_command("server-configure", configure_server_command); + this->adhoc_commands_handler.add_command("global-configure", configure_global_command); + } else - this->adhoc_commands_handler.add_command("configure", configure_global_command); + { + this->adhoc_commands_handler.add_command("configure", configure_global_command); + this->irc_server_adhoc_commands_handler.add_command("configure", configure_server_command); + } - this->irc_server_adhoc_commands_handler.add_command("configure", configure_server_command); this->irc_channel_adhoc_commands_handler.add_command("configure", {{&ConfigureIrcChannelStep1, &ConfigureIrcChannelStep2}, "Configure a few settings for that IRC channel", false}); #endif } -- cgit v1.2.3 From 2f0e26db4cd91037463e5aa45c7538a942a9eee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 17 Jun 2018 15:16:49 +0200 Subject: =?UTF-8?q?Channels=E2=80=99=20disco#info=20includes=20the=20numbe?= =?UTF-8?q?r=20of=20participants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix #3311 --- src/irc/irc_client.cpp | 14 +++++++++++++- src/irc/irc_client.hpp | 4 ++++ src/xmpp/biboumi_component.cpp | 29 +++++++++++++++++++++++++++-- src/xmpp/biboumi_component.hpp | 3 ++- 4 files changed, 46 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d7fa2cd..0f3d43c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -317,9 +317,21 @@ IrcChannel* IrcClient::get_channel(const std::string& n) } catch (const std::out_of_range& exception) { - this->channels.emplace(name, std::make_unique()); + return this->channels.emplace(name, std::make_unique()).first->second.get(); + } +} + +const IrcChannel* IrcClient::find_channel(const std::string& n) const +{ + const std::string name = utils::tolower(n); + try + { return this->channels.at(name).get(); } + catch (const std::out_of_range& exception) + { + return nullptr; + } } bool IrcClient::is_channel_joined(const std::string& name) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index fd97fe6..70046be 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -67,6 +67,10 @@ public: * Return the channel with this name, create it if it does not yet exist */ IrcChannel* get_channel(const std::string& name); + /** + * Return the channel with this name. Nullptr if it is not found + */ + const IrcChannel* find_channel(const std::string& name) const; /** * Returns true if the channel is joined */ diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index be34873..852b13f 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -514,7 +514,11 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) { if (node.empty()) { - this->send_irc_channel_disco_info(id, from, to_str); + const IrcClient* irc_client = bridge->find_irc_client(iid.get_server()); + const IrcChannel* irc_channel{}; + if (irc_client) + irc_channel = irc_client->find_channel(iid.get_local()); + this->send_irc_channel_disco_info(id, from, to_str, irc_channel); stanza_error.disable(); } else if (node == MUC_TRAFFIC_NS) @@ -964,7 +968,8 @@ void BiboumiComponent::send_irc_channel_muc_traffic_info(const std::string& id, this->send_stanza(iq); } -void BiboumiComponent::send_irc_channel_disco_info(const std::string& id, const std::string& jid_to, const std::string& jid_from) +void BiboumiComponent::send_irc_channel_disco_info(const std::string& id, const std::string& jid_to, + const std::string& jid_from, const IrcChannel* irc_channel) { Jid from(jid_from); Iid iid(from.local, {}); @@ -985,6 +990,26 @@ void BiboumiComponent::send_irc_channel_disco_info(const std::string& id, const XmlSubNode feature(query, "feature"); feature["var"] = ns; } + + XmlSubNode x(query, "x"); + x["xmlns"] = DATAFORM_NS; + x["type"] = "result"; + { + XmlSubNode field(x, "field"); + field["var"] = "FORM_TYPE"; + field["type"] = "hidden"; + XmlSubNode value(field, "value"); + value.set_inner("http://jabber.org/protocol/muc#roominfo"); + } + + if (irc_channel && irc_channel->joined) + { + XmlSubNode field(x, "field"); + field["var"] = "muc#roominfo_occupants"; + field["label"] = "Number of occupants"; + XmlSubNode value(field, "value"); + value.set_inner(std::to_string(irc_channel->get_users().size())); + } } this->send_stanza(iq); } diff --git a/src/xmpp/biboumi_component.hpp b/src/xmpp/biboumi_component.hpp index caf990e..f59ed9b 100644 --- a/src/xmpp/biboumi_component.hpp +++ b/src/xmpp/biboumi_component.hpp @@ -73,7 +73,8 @@ public: * http://xmpp.org/extensions/xep-0045.html#impl-service-traffic */ void send_irc_channel_muc_traffic_info(const std::string& id, const std::string& jid_to, const std::string& jid_from); - void send_irc_channel_disco_info(const std::string& id, const std::string& jid_to, const std::string& jid_from); + void send_irc_channel_disco_info(const std::string& id, const std::string& jid_to, const std::string& jid_from, + const IrcChannel* irc_channel); /** * Send a ping request */ -- cgit v1.2.3 From 21a79b7bad51e755cee2890aa6d0bec5dd45f901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 19 Jun 2018 21:31:11 +0200 Subject: Reject messages from unjoined resources, with an error fix #3346 --- src/bridge/bridge.hpp | 2 ++ src/xmpp/biboumi_component.cpp | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 8e7d9d7..04397c6 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -316,7 +316,9 @@ private: */ void add_resource_to_chan(const ChannelKey& channel, const std::string& resource); void remove_resource_from_chan(const ChannelKey& channel, const std::string& resource); +public: bool is_resource_in_chan(const ChannelKey& channel, const std::string& resource) const; +private: void remove_all_resources_from_chan(const ChannelKey& channel); std::size_t number_of_resources_in_chan(const ChannelKey& channel) const; diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 852b13f..8d97d07 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -273,9 +273,10 @@ void BiboumiComponent::handle_message(const Stanza& stanza) std::string error_type("cancel"); std::string error_name("internal-server-error"); - utils::ScopeGuard stanza_error([this, &from_str, &to_str, &id, &error_type, &error_name](){ + std::string error_text{}; + utils::ScopeGuard stanza_error([this, &from_str, &to_str, &id, &error_type, &error_name, &error_text](){ this->send_stanza_error("message", from_str, to_str, id, - error_type, error_name, ""); + error_type, error_name, error_text); }); const XmlNode* body = stanza.get_child("body", COMPONENT_NS); @@ -284,7 +285,15 @@ void BiboumiComponent::handle_message(const Stanza& stanza) { if (body && !body->get_inner().empty()) { - bridge->send_channel_message(iid, body->get_inner(), id); + if (bridge->is_resource_in_chan(iid.to_tuple(), from.resource)) + bridge->send_channel_message(iid, body->get_inner(), id); + else + { + error_type = "modify"; + error_name = "not-acceptable"; + error_text = "You are not a participant in this room."; + return; + } } const XmlNode* subject = stanza.get_child("subject", COMPONENT_NS); if (subject) -- cgit v1.2.3 From 0b8738d87aa101117c7681ade41f8527ad515d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 22 Jun 2018 21:33:58 +0200 Subject: Archive the Mode messages, except if they are received for an unjoined chan fix #3362 --- src/bridge/bridge.cpp | 4 ++-- src/bridge/bridge.hpp | 2 +- src/irc/irc_client.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 7a0157a..b6081d5 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -816,7 +816,7 @@ void Bridge::send_irc_version_request(const std::string& irc_hostname, const std this->add_waiting_irc(std::move(cb)); } -void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) +void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc, const bool log) { const auto encoding = in_encoding_for(*this, iid); std::string uuid{}; @@ -824,7 +824,7 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st { #ifdef USE_DATABASE const auto xmpp_body = this->make_xmpp_body(body, encoding); - if (!nick.empty() && this->record_history) + if (log && this->record_history) uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), std::get<0>(xmpp_body), nick); #endif diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index 04397c6..cb48a96 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -166,7 +166,7 @@ public: /** * Send a MUC message from some participant */ - void send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc); + void send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc, const bool log=true); /** * Send a presence of type error, from a room. */ diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 0f3d43c..96fb4ef 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1154,7 +1154,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) } this->bridge.send_message(iid, "", "Mode " + iid.get_local() + " [" + mode_arguments + "] by " + user.nick, - true); + true, this->is_channel_joined(iid.get_local())); const IrcChannel* channel = this->get_channel(iid.get_local()); if (!channel) return; -- cgit v1.2.3 From ba97c442a8be70da6bacd7ef0461fe95e99fe765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Fri, 22 Jun 2018 21:35:16 +0200 Subject: Remove an outdated TODO comment --- src/irc/irc_client.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 96fb4ef..d5f872b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1135,8 +1135,6 @@ void IrcClient::on_channel_bad_key(const IrcMessage& message) void IrcClient::on_channel_mode(const IrcMessage& message) { - // For now, just transmit the modes so the user can know what happens - // TODO, actually interprete the mode. Iid iid; iid.set_local(message.arguments[0]); iid.set_server(this->hostname); -- cgit v1.2.3 From 09b10cc80146c1ac2a0d5c53c6c8469b934189f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 25 Jun 2018 22:54:32 +0200 Subject: Throttle all commands sent to IRC servers fix #3354 --- src/database/database.hpp | 5 ++- src/irc/irc_client.cpp | 63 ++++++++++++++++++++++++------------- src/irc/irc_client.hpp | 12 +++++-- src/irc/irc_message.hpp | 4 +-- src/utils/tokens_bucket.hpp | 58 ++++++++++++++++++++++++++++++++++ src/xmpp/biboumi_adhoc_commands.cpp | 26 ++++++++++++++- 6 files changed, 141 insertions(+), 27 deletions(-) create mode 100644 src/utils/tokens_bucket.hpp (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index 3e25b30..5f637bd 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -86,13 +86,16 @@ class Database struct Address: Column { static constexpr auto name = "address_"; }; + struct ThrottleLimit: Column { static constexpr auto name = "throttlelimit_"; + ThrottleLimit(): Column(10) {} }; + using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; using GlobalOptionsTable = Table; using GlobalOptions = GlobalOptionsTable::RowType; - using IrcServerOptionsTable = Table; + using IrcServerOptionsTable = Table; using IrcServerOptions = IrcServerOptionsTable::RowType; using IrcChannelOptionsTable = Table; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index d5f872b..5a2f09b 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -135,7 +135,7 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, std::string realname, std::string user_hostname, Bridge& bridge): TCPClientSocketHandler(poller), - hostname(std::move(hostname)), + hostname(hostname), user_hostname(std::move(user_hostname)), username(std::move(username)), realname(std::move(realname)), @@ -143,7 +143,14 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, bridge(bridge), welcomed(false), chanmodes({"", "", "", ""}), - chantypes({'#', '&'}) + chantypes({'#', '&'}), + tokens_bucket(Database::get_irc_server_options(bridge.get_bare_jid(), hostname).col(), 1s, [this]() { + if (message_queue.empty()) + return true; + this->actual_send(std::move(this->message_queue.front())); + this->message_queue.pop_front(); + return false; + }, "TokensBucket" + this->hostname + this->bridge.get_jid()) { #ifdef USE_DATABASE auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(), @@ -171,6 +178,7 @@ IrcClient::~IrcClient() // This event may or may not exist (if we never got connected, it // doesn't), but it's ok TimedEventsManager::instance().cancel("PING" + this->hostname + this->bridge.get_jid()); + TimedEventsManager::instance().cancel("TokensBucket" + this->hostname + this->bridge.get_jid()); } void IrcClient::start() @@ -390,25 +398,33 @@ void IrcClient::parse_in_buffer(const size_t) } } -void IrcClient::send_message(IrcMessage&& message) +void IrcClient::actual_send(const IrcMessage& message) { - log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); - std::string res; - if (!message.prefix.empty()) - res += ":" + std::move(message.prefix) + " "; - res += message.command; - for (const std::string& arg: message.arguments) - { - if (arg.find(' ') != std::string::npos || - (!arg.empty() && arg[0] == ':')) - { - res += " :" + arg; - break; - } - res += " " + arg; - } - res += "\r\n"; - this->send_data(std::move(res)); + log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); + std::string res; + if (!message.prefix.empty()) + res += ":" + message.prefix + " "; + res += message.command; + for (const std::string& arg: message.arguments) + { + if (arg.find(' ') != std::string::npos + || (!arg.empty() && arg[0] == ':')) + { + res += " :" + arg; + break; + } + res += " " + arg; + } + res += "\r\n"; + this->send_data(std::move(res)); + } + +void IrcClient::send_message(IrcMessage message, bool throttle) +{ + if (this->tokens_bucket.use_token() || !throttle) + this->actual_send(message); + else + message_queue.push_back(std::move(message)); } void IrcClient::send_raw(const std::string& txt) @@ -459,7 +475,7 @@ 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})); + this->send_message(IrcMessage("QUIT", {reason}), false); } void IrcClient::send_join_command(const std::string& chan_name, const std::string& password) @@ -1225,6 +1241,11 @@ void IrcClient::on_channel_mode(const IrcMessage& message) } } +void IrcClient::set_throttle_limit(std::size_t limit) +{ + this->tokens_bucket.set_limit(limit); +} + void IrcClient::on_user_mode(const IrcMessage& message) { this->bridge.send_xmpp_message(this->hostname, "", diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 70046be..ac5ccb0 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -16,8 +16,10 @@ #include #include #include +#include #include #include +#include class Bridge; @@ -84,8 +86,9 @@ public: * (actually, into our out_buf and signal the poller that we want to wach * for send events to be ready) */ - void send_message(IrcMessage&& message); + void send_message(IrcMessage message, bool throttle=true); void send_raw(const std::string& txt); + void actual_send(const IrcMessage& message); /** * Send the PONG irc command */ @@ -293,7 +296,7 @@ public: const std::vector& get_sorted_user_modes() const { return this->sorted_user_modes; } std::set get_chantypes() const { return this->chantypes; } - + void set_throttle_limit(std::size_t limit); /** * Store the history limit that the client asked when joining this room. */ @@ -330,6 +333,10 @@ private: * To communicate back with the bridge */ Bridge& bridge; + /** + * Where messaged are stored when they are throttled. + */ + std::deque message_queue{}; /** * The list of joined channels, indexed by name */ @@ -389,6 +396,7 @@ private: * the WebIRC protocole. */ Resolver dns_resolver; + TokensBucket tokens_bucket; }; diff --git a/src/irc/irc_message.hpp b/src/irc/irc_message.hpp index fe954e4..269a12a 100644 --- a/src/irc/irc_message.hpp +++ b/src/irc/irc_message.hpp @@ -14,9 +14,9 @@ public: ~IrcMessage() = default; IrcMessage(const IrcMessage&) = delete; - IrcMessage(IrcMessage&&) = delete; + IrcMessage(IrcMessage&&) = default; IrcMessage& operator=(const IrcMessage&) = delete; - IrcMessage& operator=(IrcMessage&&) = delete; + IrcMessage& operator=(IrcMessage&&) = default; std::string prefix; std::string command; diff --git a/src/utils/tokens_bucket.hpp b/src/utils/tokens_bucket.hpp new file mode 100644 index 0000000..d44eb06 --- /dev/null +++ b/src/utils/tokens_bucket.hpp @@ -0,0 +1,58 @@ +/** + * Implementation of the token bucket algorithm. + * + * It uses a repetitive TimedEvent, started at construction, to fill the + * bucket. + * + * Every n seconds, it executes the given callback. If the callback + * returns true, we add a token (if the limit is not yet reached). + * + */ + +#pragma once + +#include +#include + +class TokensBucket +{ +public: + TokensBucket(std::size_t max_size, std::chrono::milliseconds fill_duration, std::function callback, std::string name): + limit(max_size), + tokens(limit), + fill_duration(fill_duration), + callback(std::move(callback)) + { + log_debug("creating TokensBucket with max size: ", max_size); + TimedEvent event(std::move(fill_duration), [this]() { this->add_token(); }, std::move(name)); + TimedEventsManager::instance().add_event(std::move(event)); + } + + bool use_token() + { + if (this->tokens > 0) + { + this->tokens--; + return true; + } + else + return false; + } + + void set_limit(std::size_t limit) + { + this->limit = limit; + } + +private: + std::size_t limit; + std::size_t tokens; + std::chrono::milliseconds fill_duration; + std::function callback; + + void add_token() + { + if (this->callback() && this->tokens != limit) + this->tokens++; + } +}; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 1b5fdcb..47de27e 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -365,6 +365,15 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com } } + { + XmlSubNode throttle_limit(x, "field"); + throttle_limit["var"] = "throttle_limit"; + throttle_limit["type"] = "text-single"; + throttle_limit["label"] = "Throttle limit"; + XmlSubNode value(throttle_limit, "value"); + value.set_inner(std::to_string(options.col())); + } + { XmlSubNode encoding_out(x, "field"); encoding_out["var"] = "encoding_out"; @@ -392,8 +401,10 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com } } -void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& command_node) +void ConfigureIrcServerStep2(XmppComponent& xmpp_component, AdhocSession& session, XmlNode& command_node) { + auto& biboumi_component = dynamic_cast(xmpp_component); + const XmlNode* x = command_node.get_child("x", "jabber:x:data"); if (x) { @@ -474,6 +485,19 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com else if (field->get_tag("var") == "realname" && value) options.col() = value->get_inner(); + else if (field->get_tag("var") == "throttle_limit" && value) + { + options.col() = std::stoull(value->get_inner()); + Bridge* bridge = biboumi_component.find_user_bridge(session.get_owner_jid()); + if (bridge) + { + IrcClient* client = bridge->find_irc_client(server_domain); + if (client) + client->set_throttle_limit(options.col()); + } + + } + else if (field->get_tag("var") == "encoding_out" && value) options.col() = value->get_inner(); -- cgit v1.2.3 From 52166e07acd785b39c0da98be4c35e886b75c3c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 25 Jun 2018 22:57:13 +0200 Subject: Trivial syntax improvements --- src/bridge/bridge.cpp | 3 ++- src/database/row.hpp | 2 +- src/irc/irc_client.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index b6081d5..08d0bab 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -63,7 +63,8 @@ void Bridge::shutdown(const std::string& exit_message) { for (auto& pair: this->irc_clients) { - pair.second->send_quit_command(exit_message); + std::shared_ptr& irc = pair.second; + irc->send_quit_command(exit_message); } } diff --git a/src/database/row.hpp b/src/database/row.hpp index 1253f93..4004b5d 100644 --- a/src/database/row.hpp +++ b/src/database/row.hpp @@ -28,7 +28,7 @@ struct Row this->clear_col<0>(); } - std::tuple columns; + std::tuple columns{}; std::string table_name; private: diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 5a2f09b..b89ab1c 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -480,7 +480,7 @@ void IrcClient::send_quit_command(const std::string& reason) void IrcClient::send_join_command(const std::string& chan_name, const std::string& password) { - if (this->welcomed == false) + if (!this->welcomed) { const auto it = std::find_if(begin(this->channels_to_join), end(this->channels_to_join), [&chan_name](const auto& pair) { return std::get<0>(pair) == chan_name; }); @@ -497,7 +497,7 @@ void IrcClient::send_join_command(const std::string& chan_name, const std::strin bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) { IrcChannel* channel = this->get_channel(chan_name); - if (channel->joined == false) + if (!channel->joined) { log_warning("Cannot send message to channel ", chan_name, ", it is not joined"); return false; -- cgit v1.2.3 From 7f8a612c9881928f722fb41c75ff18b94a133ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 25 Jun 2018 22:57:23 +0200 Subject: Fix a warning (unused variable) in some build config --- src/bridge/bridge.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 08d0bab..c3c2003 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -828,6 +828,8 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st if (log && this->record_history) uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), std::get<0>(xmpp_body), nick); +#else + (void)log; #endif for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) { -- cgit v1.2.3 From 0d886d5f32dda3be5827ed2c84f9bf2806b69601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 26 Jun 2018 20:42:21 +0200 Subject: Default the throttle limit to 10 if not built with database support --- src/irc/irc_client.cpp | 11 ++++++++++- src/irc/irc_client.hpp | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index b89ab1c..fee6517 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -144,7 +144,7 @@ IrcClient::IrcClient(std::shared_ptr& poller, std::string hostname, welcomed(false), chanmodes({"", "", "", ""}), chantypes({'#', '&'}), - tokens_bucket(Database::get_irc_server_options(bridge.get_bare_jid(), hostname).col(), 1s, [this]() { + tokens_bucket(this->get_throttle_limit(), 1s, [this]() { if (message_queue.empty()) return true; this->actual_send(std::move(this->message_queue.front())); @@ -1283,3 +1283,12 @@ bool IrcClient::abort_on_invalid_cert() const return true; } #endif + +std::size_t IrcClient::get_throttle_limit() const +{ +#ifdef USE_DATABASE + return Database::get_irc_server_options(this->bridge.get_bare_jid(), this->hostname).col(); +#else + return 10; +#endif +} diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index ac5ccb0..8c5c0c8 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -397,6 +397,7 @@ private: */ Resolver dns_resolver; TokensBucket tokens_bucket; + std::size_t get_throttle_limit() const; }; -- cgit v1.2.3 From 458ea53db3edc7318e88a2612baa793a1232cc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 3 Jul 2018 20:15:36 +0200 Subject: Fix a compile error with GCC 5.x fix #3366 --- src/database/database.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/database/database.cpp b/src/database/database.cpp index 6e08ee1..4867f52 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -242,9 +242,9 @@ std::tuple> Database::get_muc_logs(const } if (paging == Database::Paging::first) - return {complete, result}; + return std::make_tuple(complete, result); else - return {complete, {result.crbegin(), result.crend()}}; + return std::make_tuple(complete, std::vector(result.crbegin(), result.crend())); } Database::MucLogLine Database::get_muc_log(const std::string& owner, const std::string& chan_name, const std::string& server, -- cgit v1.2.3 From 85288fd0b31027e7948180e0e057242e13f15da4 Mon Sep 17 00:00:00 2001 From: Romain DEP Date: Sat, 21 Jul 2018 20:27:49 +0200 Subject: add 'verify_certificate' as possible configuration token for policy files This lets the user configure a per-domain certificate validation policy --- src/network/tcp_socket_handler.cpp | 5 +++++ src/network/tls_policy.cpp | 7 +++++++ src/network/tls_policy.hpp | 2 ++ 3 files changed, 14 insertions(+) (limited to 'src') diff --git a/src/network/tcp_socket_handler.cpp b/src/network/tcp_socket_handler.cpp index 642cf03..c6e173d 100644 --- a/src/network/tcp_socket_handler.cpp +++ b/src/network/tcp_socket_handler.cpp @@ -332,6 +332,11 @@ void TCPSocketHandler::tls_verify_cert_chain(const std::vectorpolicy.verify_certificate_info()) + { + log_debug("Not verifying certificate due to domain policy "); + return; + } log_debug("Checking remote certificate for hostname ", hostname); try { diff --git a/src/network/tls_policy.cpp b/src/network/tls_policy.cpp index b88eb88..8aa8b72 100644 --- a/src/network/tls_policy.cpp +++ b/src/network/tls_policy.cpp @@ -37,6 +37,8 @@ void BiboumiTLSPolicy::load(std::istream& is) // Workaround for options that are not overridden in Botan::TLS::Text_Policy if (pair.first == "require_cert_revocation_info") this->req_cert_revocation_info = !(pair.second == "0" || utils::tolower(pair.second) == "false"); + else if (pair.first == "verify_certificate") + this->verify_certificate = !(pair.second == "0" || utils::tolower(pair.second) == "false"); else this->set(pair.first, pair.second); } @@ -47,4 +49,9 @@ bool BiboumiTLSPolicy::require_cert_revocation_info() const return this->req_cert_revocation_info; } +bool BiboumiTLSPolicy::verify_certificate_info() const +{ + return this->verify_certificate; +} + #endif diff --git a/src/network/tls_policy.hpp b/src/network/tls_policy.hpp index 29fd2b3..a0790a3 100644 --- a/src/network/tls_policy.hpp +++ b/src/network/tls_policy.hpp @@ -21,8 +21,10 @@ public: BiboumiTLSPolicy &operator=(BiboumiTLSPolicy &&) = delete; bool require_cert_revocation_info() const override; + bool verify_certificate_info() const; protected: bool req_cert_revocation_info{true}; + bool verify_certificate{true}; }; #endif -- cgit v1.2.3 From 709fa0e5e984789113d8e4d795e52839d0cf5f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 22 Jul 2018 14:40:59 +0200 Subject: Remove a useless getter --- src/network/tcp_socket_handler.cpp | 2 +- src/network/tls_policy.cpp | 5 ----- src/network/tls_policy.hpp | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/network/tcp_socket_handler.cpp b/src/network/tcp_socket_handler.cpp index c6e173d..29c5d6a 100644 --- a/src/network/tcp_socket_handler.cpp +++ b/src/network/tcp_socket_handler.cpp @@ -332,7 +332,7 @@ void TCPSocketHandler::tls_verify_cert_chain(const std::vectorpolicy.verify_certificate_info()) + if (!this->policy.verify_certificate) { log_debug("Not verifying certificate due to domain policy "); return; diff --git a/src/network/tls_policy.cpp b/src/network/tls_policy.cpp index 8aa8b72..f32557e 100644 --- a/src/network/tls_policy.cpp +++ b/src/network/tls_policy.cpp @@ -49,9 +49,4 @@ bool BiboumiTLSPolicy::require_cert_revocation_info() const return this->req_cert_revocation_info; } -bool BiboumiTLSPolicy::verify_certificate_info() const -{ - return this->verify_certificate; -} - #endif diff --git a/src/network/tls_policy.hpp b/src/network/tls_policy.hpp index a0790a3..e915646 100644 --- a/src/network/tls_policy.hpp +++ b/src/network/tls_policy.hpp @@ -21,10 +21,9 @@ public: BiboumiTLSPolicy &operator=(BiboumiTLSPolicy &&) = delete; bool require_cert_revocation_info() const override; - bool verify_certificate_info() const; + bool verify_certificate{true}; protected: bool req_cert_revocation_info{true}; - bool verify_certificate{true}; }; #endif -- cgit v1.2.3 From 7a4cea426d0a07d577753ee008416e19eca6260d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 24 Jul 2018 23:14:35 +0200 Subject: Reflect messages to XMPP only when they are actually sent --- src/bridge/bridge.cpp | 34 ++++++++++++++++++++-------------- src/irc/irc_client.cpp | 21 ++++++++++++++------- src/irc/irc_client.hpp | 13 +++++++++---- 3 files changed, 43 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index c3c2003..39ee158 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -224,6 +224,23 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body, std:: bool first = true; for (const std::string& line: lines) { + std::string uuid; +#ifdef USE_DATABASE + const auto xmpp_body = this->make_xmpp_body(line); + if (this->record_history) + uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), + std::get<0>(xmpp_body), irc->get_own_nick()); +#endif + if (!first || id.empty()) + id = utils::gen_uuid(); + + MessageCallback mirror_to_all_resources = [this, iid, uuid, id](const IrcClient* irc, const IrcMessage& message) { + const std::string& line = message.arguments[1]; + for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) + this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), this->make_xmpp_body(line), + this->user_jid + "/" + resource, uuid, id); + }; + if (line.substr(0, 5) == "/mode") { std::vector args = utils::split(line.substr(5), ' ', false); @@ -232,22 +249,11 @@ void Bridge::send_channel_message(const Iid& iid, const std::string& body, std:: // XMPP user, that’s not a textual message. } else if (line.substr(0, 4) == "/me ") - irc->send_channel_message(iid.get_local(), action_prefix + line.substr(4) + "\01"); + irc->send_channel_message(iid.get_local(), action_prefix + line.substr(4) + "\01", + std::move(mirror_to_all_resources)); else - irc->send_channel_message(iid.get_local(), line); + irc->send_channel_message(iid.get_local(), line, std::move(mirror_to_all_resources)); - std::string uuid; -#ifdef USE_DATABASE - const auto xmpp_body = this->make_xmpp_body(line); - if (this->record_history) - uuid = Database::store_muc_message(this->get_bare_jid(), iid.get_local(), iid.get_server(), std::chrono::system_clock::now(), - std::get<0>(xmpp_body), irc->get_own_nick()); -#endif - if (!first || id.empty()) - id = utils::gen_uuid(); - for (const auto& resource: this->resources_in_chan[iid.to_tuple()]) - this->xmpp.send_muc_message(std::to_string(iid), irc->get_own_nick(), this->make_xmpp_body(line), - this->user_jid + "/" + resource, uuid, id); first = false; } } diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index fee6517..78d0fbf 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -398,8 +398,10 @@ void IrcClient::parse_in_buffer(const size_t) } } -void IrcClient::actual_send(const IrcMessage& message) +void IrcClient::actual_send(std::pair message_pair) { + const IrcMessage& message = message_pair.first; + const MessageCallback& callback = message_pair.second; log_debug("IRC SENDING: (", this->get_hostname(), ") ", message); std::string res; if (!message.prefix.empty()) @@ -417,14 +419,18 @@ void IrcClient::actual_send(const IrcMessage& message) } res += "\r\n"; this->send_data(std::move(res)); + + if (callback) + callback(this, message); } -void IrcClient::send_message(IrcMessage message, bool throttle) +void IrcClient::send_message(IrcMessage message, MessageCallback callback, bool throttle) { + auto message_pair = std::make_pair(std::move(message), std::move(callback)); if (this->tokens_bucket.use_token() || !throttle) - this->actual_send(message); + this->actual_send(std::move(message_pair)); else - message_queue.push_back(std::move(message)); + message_queue.push_back(std::move(message_pair)); } void IrcClient::send_raw(const std::string& txt) @@ -475,7 +481,7 @@ 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); + this->send_message(IrcMessage("QUIT", {reason}), {}, false); } void IrcClient::send_join_command(const std::string& chan_name, const std::string& password) @@ -494,7 +500,8 @@ void IrcClient::send_join_command(const std::string& chan_name, const std::strin this->start(); } -bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) +bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body, + MessageCallback callback) { IrcChannel* channel = this->get_channel(chan_name); if (!channel->joined) @@ -517,7 +524,7 @@ bool IrcClient::send_channel_message(const std::string& chan_name, const std::st ::strlen(":!@ PRIVMSG ") - chan_name.length() - ::strlen(" :\r\n"); const auto lines = cut(body, line_size); for (const auto& line: lines) - this->send_message(IrcMessage("PRIVMSG", {chan_name, line})); + this->send_message(IrcMessage("PRIVMSG", {chan_name, line}), callback); return true; } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 8c5c0c8..aa314f8 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -21,6 +21,10 @@ #include #include +class IrcClient; + +using MessageCallback = std::function; + class Bridge; /** @@ -86,9 +90,9 @@ public: * (actually, into our out_buf and signal the poller that we want to wach * for send events to be ready) */ - void send_message(IrcMessage message, bool throttle=true); + void send_message(IrcMessage message, MessageCallback callback={}, bool throttle=true); void send_raw(const std::string& txt); - void actual_send(const IrcMessage& message); + void actual_send(std::pair message_pair); /** * Send the PONG irc command */ @@ -117,7 +121,8 @@ public: * Send a PRIVMSG command for a channel * Return true if the message was actually sent */ - bool send_channel_message(const std::string& chan_name, const std::string& body); + bool send_channel_message(const std::string& chan_name, const std::string& body, + MessageCallback callback); /** * Send a PRIVMSG command for an user */ @@ -336,7 +341,7 @@ private: /** * Where messaged are stored when they are throttled. */ - std::deque message_queue{}; + std::deque> message_queue{}; /** * The list of joined channels, indexed by name */ -- cgit v1.2.3 From 4953f7baa51dedf85f03e529e99255fe01794538 Mon Sep 17 00:00:00 2001 From: Jonas Wielicki Date: Mon, 23 Jul 2018 21:28:46 +0200 Subject: Fix incorrect setting of field description in Ad-Hoc config forms The description has to be a child element of the field, not an attribute. --- src/xmpp/biboumi_adhoc_commands.cpp | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 47de27e..29781e6 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -23,6 +23,12 @@ using namespace std::string_literals; +void SetDesc(XmlSubNode &field, const char *text) +{ + XmlSubNode desc(field, "desc"); + desc.set_inner(text); +} + void DisconnectUserStep1(XmppComponent& xmpp_component, AdhocSession&, XmlNode& command_node) { auto& biboumi_component = dynamic_cast(xmpp_component); @@ -129,7 +135,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman 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"; + SetDesc(max_histo_length, "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())); @@ -141,7 +147,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman 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"; + SetDesc(record_history, "Whether to save the messages into the database, or not"); { XmlSubNode value(record_history, "value"); value.set_name("value"); @@ -157,7 +163,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman persistent["var"] = "persistent"; persistent["type"] = "boolean"; persistent["label"] = "Make all channels persistent"; - persistent["desc"] = "If true, all channels will be persistent"; + SetDesc(persistent, "If true, all channels will be persistent"); { XmlSubNode value(persistent, "value"); value.set_name("value"); @@ -238,7 +244,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com field["var"] = "address"; field["type"] = "text-single"; field["label"] = "Address"; - field["desc"] = "The address (hostname or IP) to connect to."; + SetDesc(field, "The address (hostname or IP) to connect to."); XmlSubNode value(field, "value"); if (options.col().empty()) value.set_inner(server_domain); @@ -251,7 +257,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com ports["var"] = "ports"; ports["type"] = "text-multi"; ports["label"] = "Ports"; - ports["desc"] = "List of ports to try, without TLS. Defaults: 6667."; + SetDesc(ports, "List of ports to try, without TLS. Defaults: 6667."); for (const auto& val: utils::split(options.col(), ';', false)) { XmlSubNode ports_value(ports, "value"); @@ -265,7 +271,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com 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."; + SetDesc(tls_ports, "List of ports to try, with TLS. Defaults: 6697, 6670."); for (const auto& val: utils::split(options.col(), ';', false)) { XmlSubNode tls_ports_value(tls_ports, "value"); @@ -278,7 +284,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com 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"; + SetDesc(verify_cert, "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()) verify_cert_value.set_inner("true"); @@ -304,7 +310,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com field["var"] = "nick"; field["type"] = "text-single"; field["label"] = "Nickname"; - field["desc"] = "If set, will override the nickname provided in the initial presence sent to join the first server channel"; + SetDesc(field, "If set, will override the nickname provided in the initial presence sent to join the first server channel"); if (!options.col().empty()) { XmlSubNode value(field, "value"); @@ -317,7 +323,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com pass["var"] = "pass"; pass["type"] = "text-private"; pass["label"] = "Server password"; - pass["desc"] = "Will be used in a PASS command when connecting"; + SetDesc(pass, "Will be used in a PASS command when connecting"); if (!options.col().empty()) { XmlSubNode pass_value(pass, "value"); @@ -329,7 +335,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com XmlSubNode after_cnt_cmd(x, "field"); after_cnt_cmd["var"] = "after_connect_commands"; after_cnt_cmd["type"] = "text-multi"; - after_cnt_cmd["desc"] = "Custom IRC commands sent after the connection is established with the server."; + SetDesc(after_cnt_cmd, "Custom IRC commands sent after the connection is established with the server."); after_cnt_cmd["label"] = "After-connection IRC commands"; for (const auto& command: commands) { @@ -378,7 +384,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com 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."; + SetDesc(encoding_out, "The encoding used when sending messages to the IRC server."); encoding_out["label"] = "Out encoding"; if (!options.col().empty()) { @@ -391,7 +397,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com 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."; + SetDesc(encoding_in, "The encoding used to decode message received from the IRC server."); encoding_in["label"] = "In encoding"; if (!options.col().empty()) { @@ -548,7 +554,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, 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"; + SetDesc(record_history, "If unset, the value is the one configured globally"); { // Value selected by default XmlSubNode value(record_history, "value"); @@ -568,7 +574,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, 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"; + SetDesc(encoding_out, "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().empty()) { @@ -581,7 +587,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, 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"; + SetDesc(encoding_in, "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().empty()) { @@ -594,7 +600,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, 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."; + SetDesc(persistent, "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"); -- cgit v1.2.3 From b490ba6e56f48de9720095dda8f7c3d441238b81 Mon Sep 17 00:00:00 2001 From: Jonas Wielicki Date: Mon, 23 Jul 2018 21:44:28 +0200 Subject: Make SetDesc static --- src/xmpp/biboumi_adhoc_commands.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 29781e6..83caf6f 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -23,7 +23,7 @@ using namespace std::string_literals; -void SetDesc(XmlSubNode &field, const char *text) +static void SetDesc(XmlSubNode &field, const char *text) { XmlSubNode desc(field, "desc"); desc.set_inner(text); -- cgit v1.2.3 From 6a86b14d05d9a26905a11e8c6e1957f2fc89d650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Wed, 25 Jul 2018 15:20:41 +0200 Subject: Rename SetDesc to set_desc, and only define it if USE_DATABASE --- src/xmpp/biboumi_adhoc_commands.cpp | 45 +++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 83caf6f..5309bdb 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -15,6 +15,13 @@ #ifdef USE_DATABASE #include #include + +static void set_desc(XmlSubNode& field, const char* text) +{ + XmlSubNode desc(field, "desc"); + desc.set_inner(text); +} + #endif #ifndef HAS_PUT_TIME @@ -23,12 +30,6 @@ using namespace std::string_literals; -static void SetDesc(XmlSubNode &field, const char *text) -{ - XmlSubNode desc(field, "desc"); - desc.set_inner(text); -} - void DisconnectUserStep1(XmppComponent& xmpp_component, AdhocSession&, XmlNode& command_node) { auto& biboumi_component = dynamic_cast(xmpp_component); @@ -135,7 +136,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman max_histo_length["var"] = "max_history_length"; max_histo_length["type"] = "text-single"; max_histo_length["label"] = "Max history length"; - SetDesc(max_histo_length, "The maximum number of lines in the history that the server sends when joining a channel"); + set_desc(max_histo_length, "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())); @@ -147,7 +148,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman record_history["var"] = "record_history"; record_history["type"] = "boolean"; record_history["label"] = "Record history"; - SetDesc(record_history, "Whether to save the messages into the database, or not"); + set_desc(record_history, "Whether to save the messages into the database, or not"); { XmlSubNode value(record_history, "value"); value.set_name("value"); @@ -163,7 +164,7 @@ void ConfigureGlobalStep1(XmppComponent&, AdhocSession& session, XmlNode& comman persistent["var"] = "persistent"; persistent["type"] = "boolean"; persistent["label"] = "Make all channels persistent"; - SetDesc(persistent, "If true, all channels will be persistent"); + set_desc(persistent, "If true, all channels will be persistent"); { XmlSubNode value(persistent, "value"); value.set_name("value"); @@ -244,7 +245,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com field["var"] = "address"; field["type"] = "text-single"; field["label"] = "Address"; - SetDesc(field, "The address (hostname or IP) to connect to."); + set_desc(field, "The address (hostname or IP) to connect to."); XmlSubNode value(field, "value"); if (options.col().empty()) value.set_inner(server_domain); @@ -257,7 +258,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com ports["var"] = "ports"; ports["type"] = "text-multi"; ports["label"] = "Ports"; - SetDesc(ports, "List of ports to try, without TLS. Defaults: 6667."); + set_desc(ports, "List of ports to try, without TLS. Defaults: 6667."); for (const auto& val: utils::split(options.col(), ';', false)) { XmlSubNode ports_value(ports, "value"); @@ -271,7 +272,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com tls_ports["var"] = "tls_ports"; tls_ports["type"] = "text-multi"; tls_ports["label"] = "TLS ports"; - SetDesc(tls_ports, "List of ports to try, with TLS. Defaults: 6697, 6670."); + set_desc(tls_ports, "List of ports to try, with TLS. Defaults: 6697, 6670."); for (const auto& val: utils::split(options.col(), ';', false)) { XmlSubNode tls_ports_value(tls_ports, "value"); @@ -284,7 +285,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com verify_cert["var"] = "verify_cert"; verify_cert["type"] = "boolean"; verify_cert["label"] = "Verify certificate"; - SetDesc(verify_cert, "Whether or not to abort the connection if the server’s TLS certificate is invalid"); + set_desc(verify_cert, "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()) verify_cert_value.set_inner("true"); @@ -310,7 +311,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com field["var"] = "nick"; field["type"] = "text-single"; field["label"] = "Nickname"; - SetDesc(field, "If set, will override the nickname provided in the initial presence sent to join the first server channel"); + set_desc(field, "If set, will override the nickname provided in the initial presence sent to join the first server channel"); if (!options.col().empty()) { XmlSubNode value(field, "value"); @@ -323,7 +324,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com pass["var"] = "pass"; pass["type"] = "text-private"; pass["label"] = "Server password"; - SetDesc(pass, "Will be used in a PASS command when connecting"); + set_desc(pass, "Will be used in a PASS command when connecting"); if (!options.col().empty()) { XmlSubNode pass_value(pass, "value"); @@ -335,7 +336,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com XmlSubNode after_cnt_cmd(x, "field"); after_cnt_cmd["var"] = "after_connect_commands"; after_cnt_cmd["type"] = "text-multi"; - SetDesc(after_cnt_cmd, "Custom IRC commands sent after the connection is established with the server."); + set_desc(after_cnt_cmd, "Custom IRC commands sent after the connection is established with the server."); after_cnt_cmd["label"] = "After-connection IRC commands"; for (const auto& command: commands) { @@ -384,7 +385,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com XmlSubNode encoding_out(x, "field"); encoding_out["var"] = "encoding_out"; encoding_out["type"] = "text-single"; - SetDesc(encoding_out, "The encoding used when sending messages to the IRC server."); + set_desc(encoding_out, "The encoding used when sending messages to the IRC server."); encoding_out["label"] = "Out encoding"; if (!options.col().empty()) { @@ -397,7 +398,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com XmlSubNode encoding_in(x, "field"); encoding_in["var"] = "encoding_in"; encoding_in["type"] = "text-single"; - SetDesc(encoding_in, "The encoding used to decode message received from the IRC server."); + set_desc(encoding_in, "The encoding used to decode message received from the IRC server."); encoding_in["label"] = "In encoding"; if (!options.col().empty()) { @@ -554,7 +555,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, record_history["var"] = "record_history"; record_history["type"] = "list-single"; record_history["label"] = "Record history for this channel"; - SetDesc(record_history, "If unset, the value is the one configured globally"); + set_desc(record_history, "If unset, the value is the one configured globally"); { // Value selected by default XmlSubNode value(record_history, "value"); @@ -574,7 +575,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, XmlSubNode encoding_out(x, "field"); encoding_out["var"] = "encoding_out"; encoding_out["type"] = "text-single"; - SetDesc(encoding_out, "The encoding used when sending messages to the IRC server. Defaults to the server's “out encoding” if unset for the channel"); + set_desc(encoding_out, "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().empty()) { @@ -587,7 +588,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, XmlSubNode encoding_in(x, "field"); encoding_in["var"] = "encoding_in"; encoding_in["type"] = "text-single"; - SetDesc(encoding_in, "The encoding used to decode message received from the IRC server. Defaults to the server's “in encoding” if unset for the channel"); + set_desc(encoding_in, "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().empty()) { @@ -600,7 +601,7 @@ void insert_irc_channel_configuration_form(XmlNode& node, const Jid& requester, XmlSubNode persistent(x, "field"); persistent["var"] = "persistent"; persistent["type"] = "boolean"; - SetDesc(persistent, "If set to true, when all XMPP clients have left this channel, biboumi will stay idle in it, without sending a PART command."); + set_desc(persistent, "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"); -- cgit v1.2.3 From 782732ba167470fa99ab3d0900c02295b4684b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 4 Aug 2018 14:50:33 +0200 Subject: Remove a bunch of useless empty lines --- src/bridge/bridge.cpp | 3 --- src/database/database.cpp | 1 - src/xmpp/biboumi_adhoc_commands.cpp | 1 - src/xmpp/biboumi_component.cpp | 2 -- 4 files changed, 7 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 39ee158..ad03f38 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -458,7 +458,6 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con } if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0) 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) @@ -900,9 +899,7 @@ void Bridge::send_muc_leave(const Iid& iid, const IrcUser& user, for (const auto& r: resources_in_chan) if (this->number_of_channels_the_resource_is_in(iid.get_server(), r) == 0) this->remove_resource_from_server(iid.get_server(), r); - } - } IrcClient* irc = this->find_irc_client(iid.get_server()); if (self && irc && irc->number_of_joined_channels() == 0) diff --git a/src/database/database.cpp b/src/database/database.cpp index 4867f52..3578c04 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -338,7 +338,6 @@ Transaction::Transaction() log_error("Failed to create SQL transaction: ", std::get(result)); else this->success = true; - } Transaction::~Transaction() diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 5309bdb..da37cc0 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -502,7 +502,6 @@ void ConfigureIrcServerStep2(XmppComponent& xmpp_component, AdhocSession& sessio if (client) client->set_throttle_limit(options.col()); } - } else if (field->get_tag("var") == "encoding_out" && value) diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 8d97d07..fa10932 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -359,7 +359,6 @@ void BiboumiComponent::handle_message(const Stanza& stanza) this->send_invitation_from_fulljid(std::to_string(iid), invite_to, from_str); } } - } } catch (const IRCNotConnected& ex) { @@ -605,7 +604,6 @@ void BiboumiComponent::handle_iq(const Stanza& stanza) const XmlNode* max = set_node->get_child("max", RSM_NS); if (max) rs_info.max = std::atoi(max->get_inner().data()); - } if (rs_info.max == -1) rs_info.max = 100; -- cgit v1.2.3 From 89e038bc3a6d1845f2ed450c71cdb3adb29e974a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 4 Aug 2018 15:11:59 +0200 Subject: Fix the real_type of ThrottleLimit --- src/database/database.hpp | 2 +- src/xmpp/biboumi_adhoc_commands.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index 5f637bd..f6b9d52 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -86,7 +86,7 @@ class Database struct Address: Column { static constexpr auto name = "address_"; }; - struct ThrottleLimit: Column { static constexpr auto name = "throttlelimit_"; + struct ThrottleLimit: Column { static constexpr auto name = "throttlelimit_"; ThrottleLimit(): Column(10) {} }; using MucLogLineTable = Table; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index da37cc0..45557aa 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -494,7 +494,7 @@ void ConfigureIrcServerStep2(XmppComponent& xmpp_component, AdhocSession& sessio else if (field->get_tag("var") == "throttle_limit" && value) { - options.col() = std::stoull(value->get_inner()); + options.col() = std::stoul(value->get_inner()); Bridge* bridge = biboumi_component.find_user_bridge(session.get_owner_jid()); if (bridge) { -- cgit v1.2.3 From 89ad479ef40a6a2363ea6aa80861f91cc2eddcd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sat, 4 Aug 2018 16:04:33 +0200 Subject: Remove a useless fill_duration member --- src/utils/tokens_bucket.hpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/utils/tokens_bucket.hpp b/src/utils/tokens_bucket.hpp index d44eb06..03af015 100644 --- a/src/utils/tokens_bucket.hpp +++ b/src/utils/tokens_bucket.hpp @@ -20,7 +20,6 @@ public: TokensBucket(std::size_t max_size, std::chrono::milliseconds fill_duration, std::function callback, std::string name): limit(max_size), tokens(limit), - fill_duration(fill_duration), callback(std::move(callback)) { log_debug("creating TokensBucket with max size: ", max_size); @@ -47,7 +46,6 @@ public: private: std::size_t limit; std::size_t tokens; - std::chrono::milliseconds fill_duration; std::function callback; void add_token() -- cgit v1.2.3 From 9fa7591058f8e4b32f64a2b61fe85c277cf2a9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Mon, 6 Aug 2018 21:14:05 +0200 Subject: Split the main() into smaller functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That’s not really enough, but better --- src/main.cpp | 94 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 09adc5c..04500b7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,45 +55,8 @@ static void sigusr_handler(int, siginfo_t*, void*) reload.store(true); } -int main(int ac, char** av) +static void setup_signals() { - if (ac > 1) - { - const std::string arg = av[1]; - if (arg.size() >= 2 && arg[0] == '-' && arg[1] == '-') - { - if (arg == "--help") - return display_help(); - else - { - std::cerr << "Unknow command line option: " << arg << std::endl; - return 1; - } - } - } - const std::string conf_filename = ac > 1 ? av[1] : xdg_config_path("biboumi.cfg"); - std::cout << "Using configuration file: " << conf_filename << std::endl; - - if (!Config::read_conf(conf_filename)) - return config_help(""); - - const std::string password = Config::get("password", ""); - if (password.empty()) - return config_help("password"); - const std::string hostname = Config::get("hostname", ""); - if (hostname.empty()) - return config_help("hostname"); - - -#ifdef USE_DATABASE - try { - open_database(); - } catch (const std::exception& e) { - log_error(e.what()); - return 1; - } -#endif - // Block the signals we want to manage. They will be unblocked only during // the epoll_pwait or ppoll calls. This avoids some race conditions, // explained in man 2 pselect on linux @@ -126,7 +89,10 @@ int main(int ac, char** av) sigaction(SIGUSR1, &on_sigusr, nullptr); sigaction(SIGUSR2, &on_sigusr, nullptr); sigaction(SIGHUP, &on_sigusr, nullptr); +} +static int main_loop(std::string hostname, std::string password) +{ auto p = std::make_shared(); #ifdef UDNS_FOUND @@ -163,7 +129,7 @@ int main(int ac, char** av) dns_handler.destroy(); #endif if (identd) - identd->shutdown(); + identd->shutdown(); // Cancel the timer for a potential reconnection TimedEventsManager::instance().cancel("XMPP reconnection"); } @@ -206,7 +172,7 @@ int main(int ac, char** av) dns_handler.destroy(); #endif if (identd) - identd->shutdown(); + identd->shutdown(); } } // If the only existing connection is the one to the XMPP component: @@ -225,3 +191,51 @@ int main(int ac, char** av) log_info("All connections cleanly closed, have a nice day."); return 0; } + +int main(int ac, char** av) +{ + if (ac > 1) + { + const std::string arg = av[1]; + if (arg.size() >= 2 && arg[0] == '-' && arg[1] == '-') + { + if (arg == "--help") + return display_help(); + else + { + std::cerr << "Unknow command line option: " << arg + << std::endl; + return 1; + } + } + } + const std::string conf_filename = + ac > 1 ? av[1]: xdg_config_path("biboumi.cfg"); + std::cout << "Using configuration file: " << conf_filename << std::endl; + + if (!Config::read_conf(conf_filename)) + return config_help(""); + + const std::string password = Config::get("password", ""); + if (password.empty()) + return config_help("password"); + const std::string hostname = Config::get("hostname", ""); + if (hostname.empty()) + return config_help("hostname"); + +#ifdef USE_DATABASE + try + { + open_database(); + } + catch (const std::exception& e) + { + log_error(e.what()); + return 1; + } +#endif + + setup_signals(); + + return main_loop(std::move(hostname), std::move(password)); +} -- cgit v1.2.3 From f55b1108cdab5643d2668b3a2b08803889e43e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 21 Aug 2018 19:54:31 +0200 Subject: Add a missing include --- src/bridge/history_limit.hpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/bridge/history_limit.hpp b/src/bridge/history_limit.hpp index 9c75256..93e36e1 100644 --- a/src/bridge/history_limit.hpp +++ b/src/bridge/history_limit.hpp @@ -1,5 +1,7 @@ #pragma once +#include + // Default values means no limit struct HistoryLimit { -- cgit v1.2.3 From d7bc737751aae7bdc77c68e4d2953aa0d6670724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Tue, 21 Aug 2018 19:54:47 +0200 Subject: Add two missing ref --- src/database/select_query.hpp | 2 +- src/utils/dirname.cpp | 2 +- src/utils/dirname.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/database/select_query.hpp b/src/database/select_query.hpp index b9fdc06..e372f2e 100644 --- a/src/database/select_query.hpp +++ b/src/database/select_query.hpp @@ -135,7 +135,7 @@ struct SelectQuery: public Query }; template -auto select(const Table table) +auto select(const Table& table) { SelectQuery query(table.name); return query; diff --git a/src/utils/dirname.cpp b/src/utils/dirname.cpp index 71c9c38..a304117 100644 --- a/src/utils/dirname.cpp +++ b/src/utils/dirname.cpp @@ -2,7 +2,7 @@ namespace utils { - std::string dirname(const std::string filename) + std::string dirname(const std::string& filename) { if (filename.empty()) return "./"; diff --git a/src/utils/dirname.hpp b/src/utils/dirname.hpp index c1df81b..73e1b57 100644 --- a/src/utils/dirname.hpp +++ b/src/utils/dirname.hpp @@ -2,5 +2,5 @@ namespace utils { -std::string dirname(const std::string filename); +std::string dirname(const std::string& filename); } -- cgit v1.2.3 From 0b51e3828116f6847865fae93893eb97a10d1cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 20:30:11 +0200 Subject: MaxHistoryLength now has some sensible default value if the user set a negative one --- src/bridge/bridge.cpp | 9 ++++++--- src/database/database.cpp | 4 ---- src/database/query.cpp | 5 ----- src/database/query.hpp | 9 +++++---- src/utils/optional_bool.hpp | 2 +- 5 files changed, 12 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index ad03f38..a69bdff 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1007,11 +1007,14 @@ void Bridge::send_room_history(const std::string& hostname, const std::string& c void Bridge::send_room_history(const std::string& hostname, std::string chan_name, const std::string& resource, const HistoryLimit& history_limit) { #ifdef USE_DATABASE - const auto coptions = Database::get_irc_channel_options_with_server_and_global_default(this->user_jid, hostname, chan_name); - auto limit = coptions.col(); + const auto goptions = Database::get_global_options(this->user_jid); + log_debug(goptions.col()); + auto limit = goptions.col(); + if (limit < 0) + limit = 20; if (history_limit.stanzas >= 0 && history_limit.stanzas < limit) limit = history_limit.stanzas; - const auto result = Database::get_muc_logs(this->user_jid, chan_name, hostname, limit, history_limit.since, {}, Id::unset_value, Database::Paging::last); + const auto result = Database::get_muc_logs(this->user_jid, chan_name, hostname, static_cast(limit), history_limit.since, {}, Id::unset_value, Database::Paging::last); const auto& lines = std::get<1>(result); chan_name.append(utils::empty_if_fixed_server("%" + hostname)); for (const auto& line: lines) diff --git a/src/database/database.cpp b/src/database/database.cpp index 3578c04..9037ce1 100644 --- a/src/database/database.cpp +++ b/src/database/database.cpp @@ -162,10 +162,6 @@ Database::IrcChannelOptions Database::get_irc_channel_options_with_server_and_gl coptions.col() = get_first_non_empty(coptions.col(), soptions.col()); - coptions.col() = get_first_non_empty(coptions.col(), - soptions.col(), - goptions.col()); - return coptions; } diff --git a/src/database/query.cpp b/src/database/query.cpp index d72066e..5ec8599 100644 --- a/src/database/query.cpp +++ b/src/database/query.cpp @@ -6,11 +6,6 @@ void actual_bind(Statement& statement, const std::string& value, int index) statement.bind_text(index, value); } -void actual_bind(Statement& statement, const std::int64_t& value, int index) -{ - statement.bind_int64(index, value); -} - void actual_bind(Statement& statement, const OptionalBool& value, int index) { if (!value.is_set) diff --git a/src/database/query.hpp b/src/database/query.hpp index ba28b1a..ae6e946 100644 --- a/src/database/query.hpp +++ b/src/database/query.hpp @@ -12,13 +12,14 @@ #include void actual_bind(Statement& statement, const std::string& value, int index); -void actual_bind(Statement& statement, const std::int64_t& value, int index); -template ::value>* = 0> +void actual_bind(Statement& statement, const OptionalBool& value, int index); +template void actual_bind(Statement& statement, const T& value, int index) { - actual_bind(statement, static_cast(value), index); + static_assert(std::is_integral::value, + "Only a string, an optional-bool or an integer can be used."); + statement.bind_int64(index, static_cast(value)); } -void actual_bind(Statement& statement, const OptionalBool& value, int index); #ifdef DEBUG_SQL_QUERIES #include diff --git a/src/utils/optional_bool.hpp b/src/utils/optional_bool.hpp index 867aca2..3d00d23 100644 --- a/src/utils/optional_bool.hpp +++ b/src/utils/optional_bool.hpp @@ -6,7 +6,7 @@ struct OptionalBool { OptionalBool() = default; - OptionalBool(bool value): + explicit OptionalBool(bool value): is_set(true), value(value) {} void set_value(bool value) -- cgit v1.2.3 From b1564e4ddc3e54ad78788a6f5643056d03a41678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 20:31:31 +0200 Subject: Fix a bunch of int to unsigned int conversion warnings --- src/main.cpp | 2 +- src/network/credentials_manager.cpp | 3 +-- src/network/credentials_manager.hpp | 3 +-- src/network/tcp_socket_handler.cpp | 16 +++++++++------- src/utils/encoding.cpp | 26 +++++++++++++------------- src/xmpp/biboumi_component.cpp | 2 +- src/xmpp/jid.cpp | 2 +- src/xmpp/xmpp_parser.cpp | 2 +- 8 files changed, 28 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 04500b7..2448197 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -77,7 +77,7 @@ static void setup_signals() sigfillset(&on_sigint.sa_mask); // we want to catch that signal only once. // Sending SIGINT again will "force" an exit - on_sigint.sa_flags = SA_RESETHAND; + on_sigint.sa_flags = 0 & SA_RESETHAND; sigaction(SIGINT, &on_sigint, nullptr); sigaction(SIGTERM, &on_sigint, nullptr); diff --git a/src/network/credentials_manager.cpp b/src/network/credentials_manager.cpp index b25f442..89c694c 100644 --- a/src/network/credentials_manager.cpp +++ b/src/network/credentials_manager.cpp @@ -21,9 +21,8 @@ static const std::vector default_cert_files = { Botan::Certificate_Store_In_Memory BasicCredentialsManager::certificate_store; bool BasicCredentialsManager::certs_loaded = false; -BasicCredentialsManager::BasicCredentialsManager(const TCPSocketHandler* const socket_handler): +BasicCredentialsManager::BasicCredentialsManager(): Botan::Credentials_Manager(), - socket_handler(socket_handler), trusted_fingerprint{} { BasicCredentialsManager::load_certs(); diff --git a/src/network/credentials_manager.hpp b/src/network/credentials_manager.hpp index 3a37bdc..210a628 100644 --- a/src/network/credentials_manager.hpp +++ b/src/network/credentials_manager.hpp @@ -25,7 +25,7 @@ void check_tls_certificate(const std::vector& certs, class BasicCredentialsManager: public Botan::Credentials_Manager { public: - BasicCredentialsManager(const TCPSocketHandler* const socket_handler); + BasicCredentialsManager(); BasicCredentialsManager(BasicCredentialsManager&&) = delete; BasicCredentialsManager(const BasicCredentialsManager&) = delete; @@ -38,7 +38,6 @@ public: const std::string& get_trusted_fingerprint() const; private: - const TCPSocketHandler* const socket_handler; static bool try_to_open_one_ca_bundle(const std::vector& paths); static void load_certs(); diff --git a/src/network/tcp_socket_handler.cpp b/src/network/tcp_socket_handler.cpp index 29c5d6a..e05caad 100644 --- a/src/network/tcp_socket_handler.cpp +++ b/src/network/tcp_socket_handler.cpp @@ -50,7 +50,7 @@ TCPSocketHandler::TCPSocketHandler(std::shared_ptr& poller): SocketHandler(poller, -1), use_tls(false) #ifdef BOTAN_FOUND - ,credential_manager(this) + ,credential_manager() #endif {} @@ -84,10 +84,11 @@ void TCPSocketHandler::plain_recv() if (recv_buf == nullptr) recv_buf = buf; - const ssize_t size = this->do_recv(recv_buf, buf_size); + const ssize_t ssize = this->do_recv(recv_buf, buf_size); - if (size > 0) + if (ssize > 0) { + auto size = static_cast(ssize); if (buf == recv_buf) { // data needs to be placed in the in_buf string, because no buffer @@ -149,21 +150,22 @@ void TCPSocketHandler::on_send() } else { + auto size = static_cast(res); // remove all the strings that were successfully sent. auto it = this->out_buf.begin(); while (it != this->out_buf.end()) { - if (static_cast(res) >= it->size()) + if (size >= it->size()) { - res -= it->size(); + size -= it->size(); ++it; } else { // If one string has partially been sent, we use substr to // crop it - if (res > 0) - *it = it->substr(res, std::string::npos); + if (size > 0) + *it = it->substr(size, std::string::npos); break; } } diff --git a/src/utils/encoding.cpp b/src/utils/encoding.cpp index cff0039..8532292 100644 --- a/src/utils/encoding.cpp +++ b/src/utils/encoding.cpp @@ -48,16 +48,16 @@ namespace utils if (codepoint_size == 4) { if (!str[1] || !str[2] || !str[3] - || ((str[1] & 0b11000000) != 0b10000000) - || ((str[2] & 0b11000000) != 0b10000000) - || ((str[3] & 0b11000000) != 0b10000000)) + || ((str[1] & 0b11000000u) != 0b10000000u) + || ((str[2] & 0b11000000u) != 0b10000000u) + || ((str[3] & 0b11000000u) != 0b10000000u)) return false; } else if (codepoint_size == 3) { if (!str[1] || !str[2] - || ((str[1] & 0b11000000) != 0b10000000) - || ((str[2] & 0b11000000) != 0b10000000)) + || ((str[1] & 0b11000000u) != 0b10000000u) + || ((str[2] & 0b11000000u) != 0b10000000u)) return false; } else if (codepoint_size == 2) @@ -81,7 +81,7 @@ namespace utils // pointer where we write valid chars char* r = res.data(); - const char* str = original.c_str(); + const unsigned char* str = reinterpret_cast(original.c_str()); std::bitset<20> codepoint; while (*str) @@ -89,10 +89,10 @@ namespace utils // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx if ((str[0] & 0b11111000) == 0b11110000) { - codepoint = ((str[0] & 0b00000111) << 18); - codepoint |= ((str[1] & 0b00111111) << 12); - codepoint |= ((str[2] & 0b00111111) << 6 ); - codepoint |= ((str[3] & 0b00111111) << 0 ); + codepoint = ((str[0] & 0b00000111u) << 18u); + codepoint |= ((str[1] & 0b00111111u) << 12u); + codepoint |= ((str[2] & 0b00111111u) << 6u ); + codepoint |= ((str[3] & 0b00111111u) << 0u ); if (codepoint.to_ulong() <= 0x10FFFF) { ::memcpy(r, str, 4); @@ -103,9 +103,9 @@ namespace utils // 3 bytes: 1110xxx 10xxxxxx 10xxxxxx else if ((str[0] & 0b11110000) == 0b11100000) { - codepoint = ((str[0] & 0b00001111) << 12); - codepoint |= ((str[1] & 0b00111111) << 6); - codepoint |= ((str[2] & 0b00111111) << 0 ); + codepoint = ((str[0] & 0b00001111u) << 12u); + codepoint |= ((str[1] & 0b00111111u) << 6u); + codepoint |= ((str[2] & 0b00111111u) << 0u ); if (codepoint.to_ulong() <= 0xD7FF || (codepoint.to_ulong() >= 0xE000 && codepoint.to_ulong() <= 0xFFFD)) { diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index fa10932..6add068 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -762,7 +762,7 @@ bool BiboumiComponent::handle_mam_request(const Stanza& stanza) if (limit < 0 || limit > 100) limit = 100; auto result = Database::get_muc_logs(from.bare(), iid.get_local(), iid.get_server(), - limit, + static_cast(limit), start, end, reference_record_id, paging_order); bool complete = std::get(result); diff --git a/src/xmpp/jid.cpp b/src/xmpp/jid.cpp index 19d1b55..3c54fd4 100644 --- a/src/xmpp/jid.cpp +++ b/src/xmpp/jid.cpp @@ -106,7 +106,7 @@ std::string jidprep(const std::string& original) --domain_end; if (domain_end != domain && special_chars.count(domain[0])) { - std::memmove(domain, domain + 1, domain_end - domain + 1); + std::memmove(domain, domain + 1, static_cast(domain_end - domain) + 1); --domain_end; } // And if the final result is an empty string, return a dummy hostname diff --git a/src/xmpp/xmpp_parser.cpp b/src/xmpp/xmpp_parser.cpp index 0488be9..781fe4c 100644 --- a/src/xmpp/xmpp_parser.cpp +++ b/src/xmpp/xmpp_parser.cpp @@ -20,7 +20,7 @@ static void end_element_handler(void* user_data, const XML_Char* name) static void character_data_handler(void *user_data, const XML_Char *s, int len) { - static_cast(user_data)->char_data(s, len); + static_cast(user_data)->char_data(s, static_cast(len)); } /** -- cgit v1.2.3 From 8997021b2e43f61b6120ecce80b8097c3c451a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 21:28:06 +0200 Subject: Fix two more warnings --- src/utils/string.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/utils/string.cpp b/src/utils/string.cpp index 635e71a..366ec1f 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -15,11 +15,11 @@ std::vector cut(const std::string& val, const std::size_t size) // Get the number of chars, <= size, that contain only whole // UTF-8 codepoints. std::size_t s = 0; - auto codepoint_size = utils::get_next_codepoint_size(val[pos + s]); + auto codepoint_size = utils::get_next_codepoint_size(static_cast(val[pos + s])); while (s + codepoint_size <= size && pos + s < val.size()) { s += codepoint_size; - codepoint_size = utils::get_next_codepoint_size(val[pos + s]); + codepoint_size = utils::get_next_codepoint_size(static_cast(val[pos + s])); } res.emplace_back(val.substr(pos, s)); pos += s; -- cgit v1.2.3 From 6c431b64d050a13853ebf3715fb6bf7986c0cff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 22:16:42 +0200 Subject: Fix one more warning --- src/database/database.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index f6b9d52..5fabadd 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -87,7 +87,7 @@ class Database struct Address: Column { static constexpr auto name = "address_"; }; struct ThrottleLimit: Column { static constexpr auto name = "throttlelimit_"; - ThrottleLimit(): Column(10) {} }; + ThrottleLimit(): Column(10) {} }; using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; -- cgit v1.2.3 From 7d0df9b6ddee8db69ea0a511f031f32a4537a749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 15:21:12 +0200 Subject: Disable the throttle limit if negative Also, invalid values result in -1 being set --- src/database/database.hpp | 4 ++-- src/irc/irc_client.cpp | 2 +- src/irc/irc_client.hpp | 2 +- src/utils/tokens_bucket.hpp | 12 ++++++++---- src/xmpp/biboumi_adhoc_commands.cpp | 6 +++++- 5 files changed, 17 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/database/database.hpp b/src/database/database.hpp index 5fabadd..4a413be 100644 --- a/src/database/database.hpp +++ b/src/database/database.hpp @@ -86,8 +86,8 @@ class Database struct Address: Column { static constexpr auto name = "address_"; }; - struct ThrottleLimit: Column { static constexpr auto name = "throttlelimit_"; - ThrottleLimit(): Column(10) {} }; + struct ThrottleLimit: Column { static constexpr auto name = "throttlelimit_"; + ThrottleLimit(): Column(10) {} }; using MucLogLineTable = Table; using MucLogLine = MucLogLineTable::RowType; diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 78d0fbf..2835a33 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1291,7 +1291,7 @@ bool IrcClient::abort_on_invalid_cert() const } #endif -std::size_t IrcClient::get_throttle_limit() const +long int IrcClient::get_throttle_limit() const { #ifdef USE_DATABASE return Database::get_irc_server_options(this->bridge.get_bare_jid(), this->hostname).col(); diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index aa314f8..1653225 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -402,7 +402,7 @@ private: */ Resolver dns_resolver; TokensBucket tokens_bucket; - std::size_t get_throttle_limit() const; + long int get_throttle_limit() const; }; diff --git a/src/utils/tokens_bucket.hpp b/src/utils/tokens_bucket.hpp index 03af015..2992e21 100644 --- a/src/utils/tokens_bucket.hpp +++ b/src/utils/tokens_bucket.hpp @@ -17,7 +17,7 @@ class TokensBucket { public: - TokensBucket(std::size_t max_size, std::chrono::milliseconds fill_duration, std::function callback, std::string name): + TokensBucket(long int max_size, std::chrono::milliseconds fill_duration, std::function callback, std::string name): limit(max_size), tokens(limit), callback(std::move(callback)) @@ -29,6 +29,8 @@ public: bool use_token() { + if (this->limit < 0) + return true; if (this->tokens > 0) { this->tokens--; @@ -38,19 +40,21 @@ public: return false; } - void set_limit(std::size_t limit) + void set_limit(long int limit) { this->limit = limit; } private: - std::size_t limit; + long int limit; std::size_t tokens; std::function callback; void add_token() { - if (this->callback() && this->tokens != limit) + if (this->limit < 0) + return; + if (this->callback() && this->tokens != static_casttokens)>(this->limit)) this->tokens++; } }; diff --git a/src/xmpp/biboumi_adhoc_commands.cpp b/src/xmpp/biboumi_adhoc_commands.cpp index 45557aa..7c31f36 100644 --- a/src/xmpp/biboumi_adhoc_commands.cpp +++ b/src/xmpp/biboumi_adhoc_commands.cpp @@ -494,7 +494,11 @@ void ConfigureIrcServerStep2(XmppComponent& xmpp_component, AdhocSession& sessio else if (field->get_tag("var") == "throttle_limit" && value) { - options.col() = std::stoul(value->get_inner()); + try { + options.col() = std::stol(value->get_inner()); + } catch (const std::logic_error&) { + options.col() = -1; + } Bridge* bridge = biboumi_component.find_user_bridge(session.get_owner_jid()); if (bridge) { -- cgit v1.2.3 From a3e865ad63a1c0d634001d9d2e86c425bc5094e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Thu, 23 Aug 2018 23:58:32 +0200 Subject: Fix a signed/unsigned mismatch --- src/irc/irc_client.cpp | 2 +- src/irc/irc_client.hpp | 2 +- src/utils/tokens_bucket.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/irc/irc_client.cpp b/src/irc/irc_client.cpp index 2835a33..0b5715e 100644 --- a/src/irc/irc_client.cpp +++ b/src/irc/irc_client.cpp @@ -1248,7 +1248,7 @@ void IrcClient::on_channel_mode(const IrcMessage& message) } } -void IrcClient::set_throttle_limit(std::size_t limit) +void IrcClient::set_throttle_limit(long int limit) { this->tokens_bucket.set_limit(limit); } diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 1653225..416eb30 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -301,7 +301,7 @@ public: const std::vector& get_sorted_user_modes() const { return this->sorted_user_modes; } std::set get_chantypes() const { return this->chantypes; } - void set_throttle_limit(std::size_t limit); + void set_throttle_limit(long int limit); /** * Store the history limit that the client asked when joining this room. */ diff --git a/src/utils/tokens_bucket.hpp b/src/utils/tokens_bucket.hpp index 2992e21..263359a 100644 --- a/src/utils/tokens_bucket.hpp +++ b/src/utils/tokens_bucket.hpp @@ -19,7 +19,7 @@ class TokensBucket public: TokensBucket(long int max_size, std::chrono::milliseconds fill_duration, std::function callback, std::string name): limit(max_size), - tokens(limit), + tokens(static_cast(limit)), callback(std::move(callback)) { log_debug("creating TokensBucket with max size: ", max_size); -- cgit v1.2.3 From 248e25c22fc15105d2a9db695ddb93ed5a8e0802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 26 Aug 2018 15:41:54 +0200 Subject: Replace a useless shared_ptr by a unique_ptr --- src/bridge/bridge.cpp | 10 +++++----- src/bridge/bridge.hpp | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index a69bdff..d7f5f16 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -63,7 +63,7 @@ void Bridge::shutdown(const std::string& exit_message) { for (auto& pair: this->irc_clients) { - std::shared_ptr& irc = pair.second; + std::unique_ptr& irc = pair.second; irc->send_quit_command(exit_message); } } @@ -134,11 +134,11 @@ IrcClient* Bridge::make_irc_client(const std::string& hostname, const std::strin realname = this->get_bare_jid(); } this->irc_clients.emplace(hostname, - std::make_shared(this->poller, hostname, + std::make_unique(this->poller, hostname, nickname, username, realname, jid.domain, *this)); - std::shared_ptr irc = this->irc_clients.at(hostname); + std::unique_ptr& irc = this->irc_clients.at(hostname); return irc.get(); } } @@ -1151,12 +1151,12 @@ void Bridge::trigger_on_irc_message(const std::string& irc_hostname, const IrcMe } } -std::unordered_map>& Bridge::get_irc_clients() +std::unordered_map>& Bridge::get_irc_clients() { return this->irc_clients; } -const std::unordered_map>& Bridge::get_irc_clients() const +const std::unordered_map>& Bridge::get_irc_clients() const { return this->irc_clients; } diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index cb48a96..b2f7734 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -241,8 +241,8 @@ public: * iq_responder_callback_t and remove the callback from the list. */ void trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message); - std::unordered_map>& get_irc_clients(); - const std::unordered_map>& get_irc_clients() const; + std::unordered_map>& get_irc_clients(); + const std::unordered_map>& get_irc_clients() const; std::set get_chantypes(const std::string& hostname) const; #ifdef USE_DATABASE void set_record_history(const bool val); @@ -275,7 +275,7 @@ private: * One IrcClient for each IRC server we need to be connected to. * The pointer is shared by the bridge and the poller. */ - std::unordered_map> irc_clients; + std::unordered_map> irc_clients; /** * To communicate back with the XMPP component */ -- cgit v1.2.3 From 478619b10a27f7a25ba0b1082f4b12981b29d546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 26 Aug 2018 15:42:38 +0200 Subject: Trivial little syntax changes --- src/bridge/bridge.cpp | 4 ++-- src/irc/irc_client.hpp | 2 +- src/xmpp/biboumi_component.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index d7f5f16..5ba8a2d 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -456,8 +456,8 @@ void Bridge::leave_irc_channel(Iid&& iid, const std::string& status_message, con true, true, resource, irc); this->remove_resource_from_chan(key, resource); } - if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0) - this->remove_resource_from_server(iid.get_server(), resource); + if (this->number_of_channels_the_resource_is_in(iid.get_server(), resource) == 0) + 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) diff --git a/src/irc/irc_client.hpp b/src/irc/irc_client.hpp index 416eb30..674f3ff 100644 --- a/src/irc/irc_client.hpp +++ b/src/irc/irc_client.hpp @@ -34,7 +34,7 @@ class Bridge; class IrcClient: public TCPClientSocketHandler { public: - explicit IrcClient(std::shared_ptr& poller, std::string hostname, + explicit IrcClient(std::shared_ptr& poller, std::string hostname, std::string nickname, std::string username, std::string realname, std::string user_hostname, Bridge& bridge); diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp index 6add068..85617e8 100644 --- a/src/xmpp/biboumi_component.cpp +++ b/src/xmpp/biboumi_component.cpp @@ -102,8 +102,8 @@ void BiboumiComponent::shutdown() void BiboumiComponent::clean() { - auto it = this->bridges.begin(); - while (it != this->bridges.end()) + auto it = std::begin(this->bridges); + while (it != std::end(this->bridges)) { it->second->clean(); if (it->second->active_clients() == 0) -- cgit v1.2.3 From b9f6fbd8405c1d16ca637fb32850d44173528e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 26 Aug 2018 18:08:14 +0200 Subject: Remove an unused function (and a useless debug log) --- src/bridge/bridge.cpp | 10 ---------- src/bridge/bridge.hpp | 1 - 2 files changed, 11 deletions(-) (limited to 'src') diff --git a/src/bridge/bridge.cpp b/src/bridge/bridge.cpp index 5ba8a2d..cc2ef66 100644 --- a/src/bridge/bridge.cpp +++ b/src/bridge/bridge.cpp @@ -1008,7 +1008,6 @@ void Bridge::send_room_history(const std::string& hostname, std::string chan_nam { #ifdef USE_DATABASE const auto goptions = Database::get_global_options(this->user_jid); - log_debug(goptions.col()); auto limit = goptions.col(); if (limit < 0) limit = 20; @@ -1223,15 +1222,6 @@ void Bridge::remove_resource_from_server(const Bridge::IrcHostname& irc_hostname } } -bool Bridge::is_resource_in_server(const Bridge::IrcHostname& irc_hostname, const std::string& resource) const -{ - auto it = this->resources_in_server.find(irc_hostname); - if (it != this->resources_in_server.end()) - if (it->second.count(resource) == 1) - return true; - return false; -} - std::size_t Bridge::number_of_resources_in_chan(const Bridge::ChannelKey& channel) const { auto it = this->resources_in_chan.find(channel); diff --git a/src/bridge/bridge.hpp b/src/bridge/bridge.hpp index b2f7734..5c547ff 100644 --- a/src/bridge/bridge.hpp +++ b/src/bridge/bridge.hpp @@ -324,7 +324,6 @@ private: void add_resource_to_server(const IrcHostname& irc_hostname, const std::string& resource); void remove_resource_from_server(const IrcHostname& irc_hostname, const std::string& resource); - bool is_resource_in_server(const IrcHostname& irc_hostname, const std::string& resource) const; size_t number_of_channels_the_resource_is_in(const std::string& irc_hostname, const std::string& resource) const; /** -- cgit v1.2.3