Use a db roster to manage biboumi’s presence with the contacts
This commit is contained in:
@@ -13,6 +13,8 @@ Database::MucLogLineTable Database::muc_log_lines("MucLogLine_");
|
|||||||
Database::GlobalOptionsTable Database::global_options("GlobalOptions_");
|
Database::GlobalOptionsTable Database::global_options("GlobalOptions_");
|
||||||
Database::IrcServerOptionsTable Database::irc_server_options("IrcServerOptions_");
|
Database::IrcServerOptionsTable Database::irc_server_options("IrcServerOptions_");
|
||||||
Database::IrcChannelOptionsTable Database::irc_channel_options("IrcChannelOptions_");
|
Database::IrcChannelOptionsTable Database::irc_channel_options("IrcChannelOptions_");
|
||||||
|
Database::RosterTable Database::roster("roster");
|
||||||
|
|
||||||
|
|
||||||
void Database::open(const std::string& filename)
|
void Database::open(const std::string& filename)
|
||||||
{
|
{
|
||||||
@@ -36,6 +38,8 @@ void Database::open(const std::string& filename)
|
|||||||
Database::irc_server_options.upgrade(Database::db);
|
Database::irc_server_options.upgrade(Database::db);
|
||||||
Database::irc_channel_options.create(Database::db);
|
Database::irc_channel_options.create(Database::db);
|
||||||
Database::irc_channel_options.upgrade(Database::db);
|
Database::irc_channel_options.upgrade(Database::db);
|
||||||
|
Database::roster.create(Database::db);
|
||||||
|
Database::roster.upgrade(Database::db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -177,6 +181,51 @@ std::vector<Database::MucLogLine> Database::get_muc_logs(const std::string& owne
|
|||||||
return {result.crbegin(), result.crend()};
|
return {result.crbegin(), result.crend()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Database::add_roster_item(const std::string& local, const std::string& remote)
|
||||||
|
{
|
||||||
|
auto roster_item = Database::roster.row();
|
||||||
|
|
||||||
|
roster_item.col<Database::LocalJid>() = local;
|
||||||
|
roster_item.col<Database::RemoteJid>() = remote;
|
||||||
|
|
||||||
|
roster_item.save(Database::db);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::delete_roster_item(const std::string& local, const std::string& remote)
|
||||||
|
{
|
||||||
|
Query query("DELETE FROM "s + Database::roster.get_name());
|
||||||
|
query << " WHERE " << Database::RemoteJid{} << "=" << remote << \
|
||||||
|
" AND " << Database::LocalJid{} << "=" << local;
|
||||||
|
|
||||||
|
query.execute(Database::db);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Database::has_roster_item(const std::string& local, const std::string& remote)
|
||||||
|
{
|
||||||
|
auto query = Database::roster.select();
|
||||||
|
query.where() << Database::LocalJid{} << "=" << local << \
|
||||||
|
" and " << Database::RemoteJid{} << "=" << remote;
|
||||||
|
|
||||||
|
auto res = query.execute(Database::db);
|
||||||
|
|
||||||
|
return !res.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Database::RosterItem> Database::get_contact_list(const std::string& local)
|
||||||
|
{
|
||||||
|
auto query = Database::roster.select();
|
||||||
|
query.where() << Database::LocalJid{} << "=" << local;
|
||||||
|
|
||||||
|
return query.execute(Database::db);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Database::RosterItem> Database::get_full_roster()
|
||||||
|
{
|
||||||
|
auto query = Database::roster.select();
|
||||||
|
|
||||||
|
return query.execute(Database::db);
|
||||||
|
}
|
||||||
|
|
||||||
void Database::close()
|
void Database::close()
|
||||||
{
|
{
|
||||||
sqlite3_close_v2(Database::db);
|
sqlite3_close_v2(Database::db);
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ class Database
|
|||||||
struct Persistent: Column<bool> { static constexpr auto name = "persistent_";
|
struct Persistent: Column<bool> { static constexpr auto name = "persistent_";
|
||||||
Persistent(): Column<bool>(false) {} };
|
Persistent(): Column<bool>(false) {} };
|
||||||
|
|
||||||
|
struct LocalJid: Column<std::string> { static constexpr auto name = "local"; };
|
||||||
|
|
||||||
|
struct RemoteJid: Column<std::string> { static constexpr auto name = "remote"; };
|
||||||
|
|
||||||
|
|
||||||
using MucLogLineTable = Table<Id, Uuid, Owner, IrcChanName, IrcServerName, Date, Body, Nick>;
|
using MucLogLineTable = Table<Id, Uuid, Owner, IrcChanName, IrcServerName, Date, Body, Nick>;
|
||||||
using MucLogLine = MucLogLineTable::RowType;
|
using MucLogLine = MucLogLineTable::RowType;
|
||||||
|
|
||||||
@@ -84,6 +89,9 @@ class Database
|
|||||||
using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>;
|
using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>;
|
||||||
using IrcChannelOptions = IrcChannelOptionsTable::RowType;
|
using IrcChannelOptions = IrcChannelOptionsTable::RowType;
|
||||||
|
|
||||||
|
using RosterTable = Table<LocalJid, RemoteJid>;
|
||||||
|
using RosterItem = RosterTable::RowType;
|
||||||
|
|
||||||
Database() = default;
|
Database() = default;
|
||||||
~Database() = default;
|
~Database() = default;
|
||||||
|
|
||||||
@@ -109,6 +117,12 @@ class Database
|
|||||||
static std::string store_muc_message(const std::string& owner, const std::string& chan_name, const std::string& server_name,
|
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);
|
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);
|
||||||
|
static void delete_roster_item(const std::string& local, const std::string& remote);
|
||||||
|
static std::vector<Database::RosterItem> get_contact_list(const std::string& local);
|
||||||
|
static std::vector<Database::RosterItem> get_full_roster();
|
||||||
|
|
||||||
static void close();
|
static void close();
|
||||||
static void open(const std::string& filename);
|
static void open(const std::string& filename);
|
||||||
|
|
||||||
@@ -123,6 +137,7 @@ class Database
|
|||||||
static GlobalOptionsTable global_options;
|
static GlobalOptionsTable global_options;
|
||||||
static IrcServerOptionsTable irc_server_options;
|
static IrcServerOptionsTable irc_server_options;
|
||||||
static IrcChannelOptionsTable irc_channel_options;
|
static IrcChannelOptionsTable irc_channel_options;
|
||||||
|
static RosterTable roster;
|
||||||
static sqlite3* db;
|
static sqlite3* db;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -83,6 +83,15 @@ void BiboumiComponent::shutdown()
|
|||||||
{
|
{
|
||||||
for (auto& pair: this->bridges)
|
for (auto& pair: this->bridges)
|
||||||
pair.second->shutdown("Gateway shutdown");
|
pair.second->shutdown("Gateway shutdown");
|
||||||
|
#ifdef USE_DATABASE
|
||||||
|
const auto full_roster = Database::get_full_roster();
|
||||||
|
for (const Database::RosterItem& roster_item: full_roster)
|
||||||
|
{
|
||||||
|
this->send_presence_to_contact(roster_item.col<Database::LocalJid>(),
|
||||||
|
roster_item.col<Database::RemoteJid>(),
|
||||||
|
"unavailable");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BiboumiComponent::clean()
|
void BiboumiComponent::clean()
|
||||||
@@ -160,10 +169,28 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
|
|||||||
{
|
{
|
||||||
if (type == "subscribe")
|
if (type == "subscribe")
|
||||||
{ // Auto-accept any subscription request for an IRC server
|
{ // Auto-accept any subscription request for an IRC server
|
||||||
this->accept_subscription(to_str, from.bare());
|
this->send_presence_to_contact(to_str, from.bare(), "subscribed", id);
|
||||||
this->ask_subscription(to_str, from.bare());
|
if (iid.type == Iid::Type::None)
|
||||||
|
this->send_presence_to_contact(to_str, from.bare(), "");
|
||||||
|
this->send_presence_to_contact(to_str, from.bare(), "subscribe");
|
||||||
|
#ifdef USE_DATABASE
|
||||||
|
if (!Database::has_roster_item(to_str, from.bare()))
|
||||||
|
Database::add_roster_item(to_str, from.bare());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (type == "unsubscribe")
|
||||||
|
{
|
||||||
|
#ifdef USE_DATABASE
|
||||||
|
const bool res = Database::has_roster_item(to_str, from.bare());
|
||||||
|
if (res)
|
||||||
|
Database::delete_roster_item(to_str, from.bare());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (type.empty())
|
||||||
|
{ // We just receive a presence from someone (as the result of a probe,
|
||||||
|
// or a directed presence, or a normal presence change)
|
||||||
|
this->send_presence_to_contact(to_str, from.bare(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -979,3 +1006,31 @@ void BiboumiComponent::ask_subscription(const std::string& from, const std::stri
|
|||||||
presence["type"] = "subscribe";
|
presence["type"] = "subscribe";
|
||||||
this->send_stanza(presence);
|
this->send_stanza(presence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BiboumiComponent::send_presence_to_contact(const std::string& from, const std::string& to,
|
||||||
|
const std::string& type, const std::string& id)
|
||||||
|
{
|
||||||
|
Stanza presence("presence");
|
||||||
|
presence["from"] = from;
|
||||||
|
presence["to"] = to;
|
||||||
|
if (!type.empty())
|
||||||
|
presence["type"] = type;
|
||||||
|
if (!id.empty())
|
||||||
|
presence["id"] = id;
|
||||||
|
this->send_stanza(presence);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BiboumiComponent::after_handshake()
|
||||||
|
{
|
||||||
|
XmppComponent::after_handshake();
|
||||||
|
|
||||||
|
#ifdef USE_DATABASE
|
||||||
|
const auto contacts = Database::get_contact_list(this->get_served_hostname());
|
||||||
|
|
||||||
|
for (const Database::RosterItem& roster_item: contacts)
|
||||||
|
{
|
||||||
|
const auto remote_jid = roster_item.col<Database::RemoteJid>();
|
||||||
|
this->send_presence_to_contact(this->get_served_hostname(), remote_jid, "probe");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ public:
|
|||||||
BiboumiComponent& operator=(const BiboumiComponent&) = delete;
|
BiboumiComponent& operator=(const BiboumiComponent&) = delete;
|
||||||
BiboumiComponent& operator=(BiboumiComponent&&) = delete;
|
BiboumiComponent& operator=(BiboumiComponent&&) = delete;
|
||||||
|
|
||||||
|
void after_handshake() override final;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the bridge for the given user. If it does not exist, return
|
* Returns the bridge for the given user. If it does not exist, return
|
||||||
* nullptr.
|
* nullptr.
|
||||||
@@ -87,6 +89,7 @@ public:
|
|||||||
void send_invitation(const std::string& room_target, const std::string& jid_to, const std::string& author_nick);
|
void send_invitation(const std::string& room_target, const std::string& jid_to, const std::string& author_nick);
|
||||||
void accept_subscription(const std::string& from, const std::string& to);
|
void accept_subscription(const std::string& from, const std::string& to);
|
||||||
void ask_subscription(const std::string& from, const std::string& to);
|
void ask_subscription(const std::string& from, const std::string& to);
|
||||||
|
void send_presence_to_contact(const std::string& from, const std::string& to, const std::string& type, const std::string& id="");
|
||||||
/**
|
/**
|
||||||
* Handle the various stanza types
|
* Handle the various stanza types
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user