From c8b20d0f5f33fb8b9898d216c3b4c9280abf31da Mon Sep 17 00:00:00 2001 From: fiaxh Date: Sun, 26 May 2024 18:24:54 +0200 Subject: Store requested disco results with computed hash, use for offline determining of private MUCs --- libdino/src/service/entity_info.vala | 35 ++++++++++++++++++++++++++++++----- libdino/src/service/muc_manager.vala | 11 ++--------- qlite/src/upsert_builder.vala | 8 ++++++-- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/libdino/src/service/entity_info.vala b/libdino/src/service/entity_info.vala index d1217e81..83e27d4b 100644 --- a/libdino/src/service/entity_info.vala +++ b/libdino/src/service/entity_info.vala @@ -90,6 +90,20 @@ public class EntityInfo : StreamInteractionModule, Object { return info_result.features.contains(feature); } + public bool has_feature_offline(Account account, Jid jid, string feature) { + int ret = has_feature_cached_int(account, jid, feature); + if (ret == -1) { + return db.entity.select() + .with(db.entity.account_id, "=", account.id) + .with(db.entity.jid_id, "=", db.get_jid_id(jid)) + .with(db.entity.resource, "=", jid.resourcepart ?? "") + .join_with(db.entity_feature, db.entity.caps_hash, db.entity_feature.entity) + .with(db.entity_feature.feature, "=", feature) + .count() > 0; + } + return ret == 1; + } + public bool has_feature_cached(Account account, Jid jid, string feature) { return has_feature_cached_int(account, jid, feature) == 1; } @@ -203,13 +217,24 @@ public class EntityInfo : StreamInteractionModule, Object { ServiceDiscovery.InfoResult? info_result = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, jid); if (info_result == null) return null; - if (hash != null && EntityCapabilities.Module.compute_hash_for_info_result(info_result) == hash) { - store_features(hash, info_result.features); - store_identities(hash, info_result.identities); + var computed_hash = EntityCapabilities.Module.compute_hash_for_info_result(info_result); + + if (hash == null || computed_hash == hash) { + db.entity.upsert() + .value(db.entity.account_id, account.id, true) + .value(db.entity.jid_id, db.get_jid_id(jid), true) + .value(db.entity.resource, jid.resourcepart ?? "", true) + .value(db.entity.last_seen, (long)(new DateTime.now_local()).to_unix()) + .value(db.entity.caps_hash, computed_hash) + .perform(); + + store_features(computed_hash, info_result.features); + store_identities(computed_hash, info_result.identities); } else { - jid_features[jid] = info_result.features; - jid_identity[jid] = info_result.identities; + warning("Claimed entity caps hash from %s doesn't match computed one", jid.to_string()); } + jid_features[jid] = info_result.features; + jid_identity[jid] = info_result.identities; return info_result; } diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index 119079f0..6b52fe36 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -232,15 +232,8 @@ public class MucManager : StreamInteractionModule, Object { //the term `private room` is a short hand for members-only+non-anonymous rooms public bool is_private_room(Account account, Jid jid) { - XmppStream? stream = stream_interactor.get_stream(account); - if (stream == null) { - return false; - } - Xep.Muc.Flag? flag = stream.get_flag(Xep.Muc.Flag.IDENTITY); - if (flag == null) { - return false; - } - return flag.has_room_feature(jid, Xep.Muc.Feature.NON_ANONYMOUS) && flag.has_room_feature(jid, Xep.Muc.Feature.MEMBERS_ONLY); + var entity_info = stream_interactor.get_module(EntityInfo.IDENTITY); + return entity_info.has_feature_offline(account, jid, "muc_membersonly") && entity_info.has_feature_offline(account, jid, "muc_nonanonymous"); } public bool is_moderated_room(Account account, Jid jid) { diff --git a/qlite/src/upsert_builder.vala b/qlite/src/upsert_builder.vala index 7daf7109..79104972 100644 --- a/qlite/src/upsert_builder.vala +++ b/qlite/src/upsert_builder.vala @@ -26,9 +26,13 @@ public class UpsertBuilder : StatementBuilder { return this; } - public UpsertBuilder value_null(Column column) { + public UpsertBuilder value_null(Column column, bool key = false) { if (column.not_null) error("Can't set non-null column %s to null", column.name); - fields += new NullField(column); + if (key) { + keys += new NullField(column); + } else { + fields += new NullField(column); + } return this; } -- cgit v1.2.3-54-g00ecf