aboutsummaryrefslogtreecommitdiff
path: root/libdino/src
diff options
context:
space:
mode:
Diffstat (limited to 'libdino/src')
-rw-r--r--libdino/src/application.vala1
-rw-r--r--libdino/src/service/database.vala55
-rw-r--r--libdino/src/service/entity_capabilities_storage.vala52
-rw-r--r--libdino/src/service/entity_info.vala67
-rw-r--r--libdino/src/service/module_manager.vala9
-rw-r--r--libdino/src/service/stream_interactor.vala2
6 files changed, 154 insertions, 32 deletions
diff --git a/libdino/src/application.vala b/libdino/src/application.vala
index e7e02be7..ac9a4e4b 100644
--- a/libdino/src/application.vala
+++ b/libdino/src/application.vala
@@ -44,6 +44,7 @@ public interface Application : GLib.Application {
NotificationEvents.start(stream_interactor);
SearchProcessor.start(stream_interactor, db);
Register.start(stream_interactor, db);
+ EntityInfo.start(stream_interactor, db);
create_actions();
diff --git a/libdino/src/service/database.vala b/libdino/src/service/database.vala
index 34bbea7a..ebf05637 100644
--- a/libdino/src/service/database.vala
+++ b/libdino/src/service/database.vala
@@ -7,7 +7,7 @@ using Dino.Entities;
namespace Dino {
public class Database : Qlite.Database {
- private const int VERSION = 12;
+ private const int VERSION = 13;
public class AccountTable : Table {
public Column<int> id = new Column.Integer("id") { primary_key = true, auto_increment = true };
@@ -35,6 +35,21 @@ public class Database : Qlite.Database {
}
}
+ public class EntityTable : Table {
+ public Column<int> id = new Column.Integer("id") { primary_key = true, auto_increment = true };
+ public Column<int> account_id = new Column.Integer("account_id");
+ public Column<int> jid_id = new Column.Integer("jid_id");
+ public Column<string> resource = new Column.Text("resource");
+ public Column<string> caps_hash = new Column.Text("caps_hash");
+ public Column<long> last_seen = new Column.Long("last_seen");
+
+ internal EntityTable(Database db) {
+ base(db, "entity");
+ init({id, account_id, jid_id, resource, caps_hash, last_seen});
+ unique({account_id, jid_id, resource}, "IGNORE");
+ }
+ }
+
public class ContentItemTable : Table {
public Column<int> id = new Column.Integer("id") { primary_key = true, auto_increment = true };
public Column<int> conversation_id = new Column.Integer("conversation_id") { not_null = true };
@@ -162,6 +177,20 @@ public class Database : Qlite.Database {
}
}
+ public class EntityIdentityTable : Table {
+ public Column<string> entity = new Column.Text("entity");
+ public Column<string> category = new Column.Text("category");
+ public Column<string> type = new Column.Text("type");
+ public Column<string> name = new Column.Text("name");
+
+ internal EntityIdentityTable(Database db) {
+ base(db, "entity_identity");
+ init({entity, category, name, type});
+ unique({entity, category, type}, "IGNORE");
+ index("entity_identity_idx", {entity});
+ }
+ }
+
public class EntityFeatureTable : Table {
public Column<string> entity = new Column.Text("entity");
public Column<string> feature = new Column.Text("feature");
@@ -215,12 +244,14 @@ public class Database : Qlite.Database {
public AccountTable account { get; private set; }
public JidTable jid { get; private set; }
+ public EntityTable entity { get; private set; }
public ContentItemTable content_item { get; private set; }
public MessageTable message { get; private set; }
public RealJidTable real_jid { get; private set; }
public FileTransferTable file_transfer { get; private set; }
public ConversationTable conversation { get; private set; }
public AvatarTable avatar { get; private set; }
+ public EntityIdentityTable entity_identity { get; private set; }
public EntityFeatureTable entity_feature { get; private set; }
public RosterTable roster { get; private set; }
public MamCatchupTable mam_catchup { get; private set; }
@@ -234,17 +265,19 @@ public class Database : Qlite.Database {
base(fileName, VERSION);
account = new AccountTable(this);
jid = new JidTable(this);
+ entity = new EntityTable(this);
content_item = new ContentItemTable(this);
message = new MessageTable(this);
real_jid = new RealJidTable(this);
file_transfer = new FileTransferTable(this);
conversation = new ConversationTable(this);
avatar = new AvatarTable(this);
+ entity_identity = new EntityIdentityTable(this);
entity_feature = new EntityFeatureTable(this);
roster = new RosterTable(this);
mam_catchup = new MamCatchupTable(this);
settings = new SettingsTable(this);
- init({ account, jid, content_item, message, real_jid, file_transfer, conversation, avatar, entity_feature, roster, mam_catchup, settings });
+ init({ account, jid, entity, content_item, message, real_jid, file_transfer, conversation, avatar, entity_identity, entity_feature, roster, mam_catchup, settings });
try {
exec("PRAGMA synchronous=0");
} catch (Error e) { }
@@ -433,24 +466,6 @@ public class Database : Qlite.Database {
return ret;
}
- public void add_entity_features(string entity, Gee.List<string> features) {
- foreach (string feature in features) {
- entity_feature.insert()
- .value(entity_feature.entity, entity)
- .value(entity_feature.feature, feature)
- .perform();
- }
- }
-
- public Gee.List<string> get_entity_features(string entity) {
- ArrayList<string> ret = new ArrayList<string>();
- foreach (Row row in entity_feature.select({entity_feature.feature}).with(entity_feature.entity, "=", entity)) {
- ret.add(row[entity_feature.feature]);
- }
- return ret;
- }
-
-
public int get_jid_id(Jid jid_obj) {
var bare_jid = jid_obj.bare_jid;
if (jid_table_reverse.has_key(bare_jid)) {
diff --git a/libdino/src/service/entity_capabilities_storage.vala b/libdino/src/service/entity_capabilities_storage.vala
index 94d9d88e..d9f66913 100644
--- a/libdino/src/service/entity_capabilities_storage.vala
+++ b/libdino/src/service/entity_capabilities_storage.vala
@@ -1,23 +1,69 @@
using Gee;
-
+using Qlite;
using Xmpp;
+using Xmpp.Xep.ServiceDiscovery;
namespace Dino {
public class EntityCapabilitiesStorage : Xep.EntityCapabilities.Storage, Object {
private Database db;
+ private HashMap<string, Gee.List<string>> features_cache = new HashMap<string, Gee.List<string>>();
+ private HashMap<string, Identity> identity_cache = new HashMap<string, Identity>();
public EntityCapabilitiesStorage(Database db) {
this.db = db;
}
public void store_features(string entity, Gee.List<string> features) {
- db.add_entity_features(entity, features);
+ foreach (string feature in features) {
+ db.entity_feature.insert()
+ .value(db.entity_feature.entity, entity)
+ .value(db.entity_feature.feature, feature)
+ .perform();
+ }
+ }
+
+ public void store_identities(string entity, Gee.List<Identity> identities) {
+ foreach (Identity identity in identities) {
+ if (identity.category == Identity.CATEGORY_CLIENT) {
+ db.entity_identity.insert()
+ .value(db.entity_identity.entity, entity)
+ .value(db.entity_identity.category, identity.category)
+ .value(db.entity_identity.type, identity.type_)
+ .value(db.entity_identity.name, identity.name)
+ .perform();
+ return;
+ }
+ }
}
public Gee.List<string> get_features(string entity) {
- return db.get_entity_features(entity);
+ Gee.List<string>? features = features_cache[entity];
+ if (features != null) {
+ return features;
+ }
+
+ features = new ArrayList<string>();
+ foreach (Row row in db.entity_feature.select({db.entity_feature.feature}).with(db.entity_feature.entity, "=", entity)) {
+ features.add(row[db.entity_feature.feature]);
+ }
+ features_cache[entity] = features;
+ return features;
+ }
+
+ public Identity? get_identities(string entity) {
+ Identity? identity = identity_cache[entity];
+ if (identity != null) {
+ return identity;
+ }
+
+ RowOption row = db.entity_identity.select().with(db.entity_identity.entity, "=", entity).single().row();
+ if (row.is_present()) {
+ identity = new Identity(row[db.entity_identity.category], row[db.entity_identity.type], row[db.entity_identity.name]);
+ }
+ identity_cache[entity] = identity;
+ return identity;
}
}
}
diff --git a/libdino/src/service/entity_info.vala b/libdino/src/service/entity_info.vala
new file mode 100644
index 00000000..8efea7e5
--- /dev/null
+++ b/libdino/src/service/entity_info.vala
@@ -0,0 +1,67 @@
+using Gee;
+using Dino.Entities;
+using Xmpp;
+using Xmpp.Xep;
+using Xmpp.Xep.ServiceDiscovery;
+
+namespace Dino {
+public class EntityInfo : StreamInteractionModule, Object {
+ public static ModuleIdentity<EntityInfo> IDENTITY = new ModuleIdentity<EntityInfo>("entity_info");
+ public string id { get { return IDENTITY.id; } }
+
+ private StreamInteractor stream_interactor;
+ private Database db;
+ private EntityCapabilitiesStorage entity_capabilities_storage;
+
+
+ private HashMap<Jid, string> entity_caps_hashes = new HashMap<Jid, string>(Jid.hash_func, Jid.equals_func);
+
+ public static void start(StreamInteractor stream_interactor, Database db) {
+ EntityInfo m = new EntityInfo(stream_interactor, db);
+ stream_interactor.add_module(m);
+ }
+
+ private EntityInfo(StreamInteractor stream_interactor, Database db) {
+ this.stream_interactor = stream_interactor;
+ this.db = db;
+ this.entity_capabilities_storage = new EntityCapabilitiesStorage(db);
+
+ stream_interactor.account_added.connect(on_account_added);
+ stream_interactor.module_manager.initialize_account_modules.connect(initialize_modules);
+ }
+
+ public Identity? get_identity(Account account, Jid jid) {
+ string? caps_hash = entity_caps_hashes[jid];
+ if (caps_hash == null) return null;
+ return entity_capabilities_storage.get_identities(caps_hash);
+ }
+
+ private void on_received_available_presence(Account account, Presence.Stanza presence) {
+ bool is_gc = stream_interactor.get_module(MucManager.IDENTITY).is_groupchat(presence.from.bare_jid, account);
+ if (is_gc) return;
+
+ string? caps_hash = EntityCapabilities.get_caps_hash(presence);
+ if (caps_hash == null) return;
+
+ db.entity.upsert()
+ .value(db.entity.account_id, account.id, true)
+ .value(db.entity.jid_id, db.get_jid_id(presence.from), true)
+ .value(db.entity.resource, presence.from.resourcepart, true)
+ .value(db.entity.last_seen, (long)(new DateTime.now_local()).to_unix())
+ .value(db.entity.caps_hash, caps_hash)
+ .perform();
+
+ if (caps_hash != null) {
+ entity_caps_hashes[presence.from] = caps_hash;
+ }
+ }
+
+ private void on_account_added(Account account) {
+ stream_interactor.module_manager.get_module(account, Presence.Module.IDENTITY).received_available.connect((stream, presence) => on_received_available_presence(account, presence));
+ }
+
+ private void initialize_modules(Account account, ArrayList<XmppStreamModule> modules) {
+ modules.add(new Xep.EntityCapabilities.Module(entity_capabilities_storage));
+ }
+}
+}
diff --git a/libdino/src/service/module_manager.vala b/libdino/src/service/module_manager.vala
index a3f56652..0cd76a14 100644
--- a/libdino/src/service/module_manager.vala
+++ b/libdino/src/service/module_manager.vala
@@ -8,14 +8,8 @@ namespace Dino {
public class ModuleManager {
private HashMap<Account, ArrayList<XmppStreamModule>> module_map = new HashMap<Account, ArrayList<XmppStreamModule>>(Account.hash_func, Account.equals_func);
- private EntityCapabilitiesStorage entity_capabilities_storage;
-
public signal void initialize_account_modules(Account account, ArrayList<XmppStreamModule> modules);
- public ModuleManager(Database db) {
- entity_capabilities_storage = new EntityCapabilitiesStorage(db);
- }
-
public T? get_module<T>(Account account, Xmpp.ModuleIdentity<T> identity) {
if (identity == null) return null;
lock (module_map) {
@@ -59,7 +53,7 @@ public class ModuleManager {
module_map[account].add(new Bind.Module(account.resourcepart));
module_map[account].add(new Session.Module());
module_map[account].add(new Roster.Module());
- module_map[account].add(new Xep.ServiceDiscovery.Module.with_identity("client", "pc"));
+ module_map[account].add(new Xep.ServiceDiscovery.Module.with_identity("client", "pc", "Dino"));
module_map[account].add(new Xep.PrivateXmlStorage.Module());
module_map[account].add(new Xep.Bookmarks.Module());
module_map[account].add(new Xep.Bookmarks2.Module());
@@ -69,7 +63,6 @@ public class ModuleManager {
module_map[account].add(new Xep.MessageCarbons.Module());
module_map[account].add(new Xep.Muc.Module());
module_map[account].add(new Xep.Pubsub.Module());
- module_map[account].add(new Xep.EntityCapabilities.Module(entity_capabilities_storage));
module_map[account].add(new Xep.MessageDeliveryReceipts.Module());
module_map[account].add(new Xep.BlockingCommand.Module());
module_map[account].add(new Xep.ChatStateNotifications.Module());
diff --git a/libdino/src/service/stream_interactor.vala b/libdino/src/service/stream_interactor.vala
index a1770bb8..1ace195d 100644
--- a/libdino/src/service/stream_interactor.vala
+++ b/libdino/src/service/stream_interactor.vala
@@ -17,7 +17,7 @@ public class StreamInteractor : Object {
private ArrayList<StreamInteractionModule> modules = new ArrayList<StreamInteractionModule>();
public StreamInteractor(Database db) {
- module_manager = new ModuleManager(db);
+ module_manager = new ModuleManager();
connection_manager = new ConnectionManager(module_manager);
connection_manager.stream_opened.connect(on_stream_opened);