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::IrcServerOptionsTable Database::irc_server_options("IrcServerOptions_");
|
||||
Database::IrcChannelOptionsTable Database::irc_channel_options("IrcChannelOptions_");
|
||||
Database::RosterTable Database::roster("roster");
|
||||
|
||||
|
||||
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_channel_options.create(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()};
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
sqlite3_close_v2(Database::db);
|
||||
|
||||
@@ -72,6 +72,11 @@ class Database
|
||||
struct Persistent: Column<bool> { static constexpr auto name = "persistent_";
|
||||
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 MucLogLine = MucLogLineTable::RowType;
|
||||
|
||||
@@ -84,6 +89,9 @@ class Database
|
||||
using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>;
|
||||
using IrcChannelOptions = IrcChannelOptionsTable::RowType;
|
||||
|
||||
using RosterTable = Table<LocalJid, RemoteJid>;
|
||||
using RosterItem = RosterTable::RowType;
|
||||
|
||||
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,
|
||||
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 open(const std::string& filename);
|
||||
|
||||
@@ -123,6 +137,7 @@ class Database
|
||||
static GlobalOptionsTable global_options;
|
||||
static IrcServerOptionsTable irc_server_options;
|
||||
static IrcChannelOptionsTable irc_channel_options;
|
||||
static RosterTable roster;
|
||||
static sqlite3* db;
|
||||
|
||||
private:
|
||||
|
||||
@@ -83,6 +83,15 @@ void BiboumiComponent::shutdown()
|
||||
{
|
||||
for (auto& pair: this->bridges)
|
||||
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()
|
||||
@@ -160,10 +169,28 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
|
||||
{
|
||||
if (type == "subscribe")
|
||||
{ // Auto-accept any subscription request for an IRC server
|
||||
this->accept_subscription(to_str, from.bare());
|
||||
this->ask_subscription(to_str, from.bare());
|
||||
this->send_presence_to_contact(to_str, from.bare(), "subscribed", id);
|
||||
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
|
||||
{
|
||||
@@ -979,3 +1006,31 @@ void BiboumiComponent::ask_subscription(const std::string& from, const std::stri
|
||||
presence["type"] = "subscribe";
|
||||
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=(BiboumiComponent&&) = delete;
|
||||
|
||||
void after_handshake() override final;
|
||||
|
||||
/**
|
||||
* Returns the bridge for the given user. If it does not exist, return
|
||||
* 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 accept_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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user