aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdino/meson.build1
-rw-r--r--libdino/src/service/entity_capabilities_storage.vala71
-rw-r--r--libdino/src/service/entity_info.vala31
-rw-r--r--libdino/src/service/message_processor.vala8
-rw-r--r--libdino/src/service/module_manager.vala1
-rw-r--r--libdino/src/service/muc_manager.vala49
-rw-r--r--xmpp-vala/src/module/xep/0045_muc/flag.vala17
-rw-r--r--xmpp-vala/src/module/xep/0045_muc/module.vala71
-rw-r--r--xmpp-vala/src/module/xep/0115_entity_capabilities.vala5
9 files changed, 57 insertions, 197 deletions
diff --git a/libdino/meson.build b/libdino/meson.build
index bf29dbf9..12665b18 100644
--- a/libdino/meson.build
+++ b/libdino/meson.build
@@ -55,7 +55,6 @@ sources = files(
'src/service/conversation_manager.vala',
'src/service/counterpart_interaction_manager.vala',
'src/service/database.vala',
- 'src/service/entity_capabilities_storage.vala',
'src/service/entity_info.vala',
'src/service/fallback_body.vala',
'src/service/file_manager.vala',
diff --git a/libdino/src/service/entity_capabilities_storage.vala b/libdino/src/service/entity_capabilities_storage.vala
deleted file mode 100644
index c6d0bbbd..00000000
--- a/libdino/src/service/entity_capabilities_storage.vala
+++ /dev/null
@@ -1,71 +0,0 @@
-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) {
- if (features_cache.has_key(entity)) return;
-
- 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.Set<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.entity_name, identity.name)
- .perform();
- return;
- }
- }
- }
-
- public Gee.List<string> get_features(string 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.entity_name]);
- }
- identity_cache[entity] = identity;
- return identity;
- }
-}
-}
diff --git a/libdino/src/service/entity_info.vala b/libdino/src/service/entity_info.vala
index 53d14b15..03828d1d 100644
--- a/libdino/src/service/entity_info.vala
+++ b/libdino/src/service/entity_info.vala
@@ -12,7 +12,6 @@ public class EntityInfo : StreamInteractionModule, Object {
private StreamInteractor stream_interactor;
private Database db;
- private EntityCapabilitiesStorage entity_capabilities_storage;
private Dino.Entities.Settings settings;
private HashMap<Jid, string> entity_caps_hashes = new HashMap<Jid, string>(Jid.hash_func, Jid.equals_func);
@@ -40,7 +39,6 @@ public class EntityInfo : StreamInteractionModule, Object {
private EntityInfo(StreamInteractor stream_interactor, Database db, Dino.Entities.Settings settings) {
this.stream_interactor = stream_interactor;
this.db = db;
- this.entity_capabilities_storage = new EntityCapabilitiesStorage(db);
this.settings = settings;
stream_interactor.account_added.connect(on_account_added);
@@ -58,18 +56,32 @@ public class EntityInfo : StreamInteractionModule, Object {
Timeout.add_seconds(60 * 60, () => { remove_old_entities(); return true; });
}
- public async Gee.Set<Identity>? get_identities(Account account, Jid jid) {
+ public Gee.Set<Identity>? get_identities_offline(Account account, Jid jid) {
if (jid_identity.has_key(jid)) {
return jid_identity[jid];
}
- string? hash = entity_caps_hashes[jid];
- if (hash != null) {
- Gee.Set<Identity>? identities = get_stored_identities(hash);
- if (identities != null) return identities;
+ var qry = 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_identity, db.entity.caps_hash, db.entity_identity.entity);
+
+ HashSet<Identity> identities = new HashSet<Identity>(Identity.hash_func, Identity.equals_func);
+
+ foreach (Row row in qry) {
+ var identity = new Identity(row[db.entity_identity.category], row[db.entity_identity.type], row[db.entity_identity.entity_name]);
+ identities.add(identity);
}
- ServiceDiscovery.InfoResult? info_result = yield get_info_result(account, jid, hash);
+ return identities;
+ }
+
+ public async Gee.Set<Identity>? get_identities(Account account, Jid jid) {
+ var identities = get_identities_offline(account, jid);
+ if (identities != null) return identities;
+
+ ServiceDiscovery.InfoResult? info_result = yield get_info_result(account, jid, entity_caps_hashes[jid]);
if (info_result != null) {
return info_result.identities;
}
@@ -261,7 +273,7 @@ public class EntityInfo : StreamInteractionModule, Object {
return identities;
}
- private async ServiceDiscovery.InfoResult? get_info_result(Account account, Jid jid, string? hash = null) {
+ public async ServiceDiscovery.InfoResult? get_info_result(Account account, Jid jid, string? hash = null) {
XmppStream? stream = stream_interactor.get_stream(account);
if (stream == null) return null;
@@ -298,7 +310,6 @@ public class EntityInfo : StreamInteractionModule, Object {
}
private void initialize_modules(Account account, ArrayList<XmppStreamModule> modules) {
- modules.add(new Xep.EntityCapabilities.Module(entity_capabilities_storage));
var entity_time_module = modules.first_match((it) => it is EntityTime.Module) as EntityTime.Module;
if (entity_time_module != null) {
settings.bind_property("share-time", entity_time_module, "enabled", BindingFlags.SYNC_CREATE);
diff --git a/libdino/src/service/message_processor.vala b/libdino/src/service/message_processor.vala
index b9c23240..9190cd9d 100644
--- a/libdino/src/service/message_processor.vala
+++ b/libdino/src/service/message_processor.vala
@@ -472,12 +472,8 @@ public class MessageProcessor : StreamInteractionModule, Object {
// Set an origin ID if a MUC doen't guarantee to keep IDs
if (conversation.type_ == Conversation.Type.GROUPCHAT) {
- Xep.Muc.Flag? flag = stream.get_flag(Xep.Muc.Flag.IDENTITY);
- if (flag == null) {
- message.marked = Entities.Message.Marked.UNSENT;
- return;
- }
- if(!flag.has_room_feature(conversation.counterpart, Xep.Muc.Feature.STABLE_ID)) {
+ var supports_stable_ids = stream_interactor.get_module(EntityInfo.IDENTITY).has_feature_cached(conversation.account, conversation.counterpart, Xep.Muc.FEATURE_STABLE_ID);
+ if(!supports_stable_ids) {
UniqueStableStanzaIDs.set_origin_id(new_message, message.stanza_id);
}
}
diff --git a/libdino/src/service/module_manager.vala b/libdino/src/service/module_manager.vala
index 5ba4fe80..f7cad0fe 100644
--- a/libdino/src/service/module_manager.vala
+++ b/libdino/src/service/module_manager.vala
@@ -69,6 +69,7 @@ public class ModuleManager {
module_map[account].add(new Presence.Module());
module_map[account].add(new Xmpp.MessageModule());
module_map[account].add(new Xmpp.MessageArchiveManagement.Module());
+ module_map[account].add(new Xep.EntityCapabilities.Module());
module_map[account].add(new Xep.MessageCarbons.Module());
module_map[account].add(new Xep.BitsOfBinary.Module());
module_map[account].add(new Xep.Muc.Module());
diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala
index b47a52bf..4959074b 100644
--- a/libdino/src/service/muc_manager.vala
+++ b/libdino/src/service/muc_manager.vala
@@ -108,19 +108,11 @@ public class MucManager : StreamInteractionModule, Object {
joined_conversation.nickname = nick;
stream_interactor.get_module(ConversationManager.IDENTITY).start_conversation(joined_conversation);
- bool can_do_affiliation_versioning = yield entity_info.has_feature(account, jid, Xmpp.Xep.MucAffiliationsVersioning.NS_URI);
- if (!can_do_affiliation_versioning) {
- stream.get_module(Xep.Muc.Module.IDENTITY).fetch_affiliations.begin(stream, jid.bare_jid, () => {
- muc_affiliations.clear_affiliations(account, jid);
- persist_muc_affiliations(account, jid.bare_jid);
- });
- }
-
if (can_do_mam) {
var history_sync = stream_interactor.get_module(MessageProcessor.IDENTITY).history_sync;
if (conversation == null) {
// We never joined the conversation before, just fetch the latest MAM page
- yield history_sync.fetch_latest_page(account, jid.bare_jid, null, new DateTime.from_unix_utc(0), cancellable);
+ history_sync.fetch_latest_page.begin(account, jid.bare_jid, null, new DateTime.from_unix_utc(0), cancellable);
} else {
// Fetch everything up to the last time the user actively joined
if (!mucs_sync_cancellables.has_key(account)) {
@@ -137,6 +129,17 @@ public class MucManager : StreamInteractionModule, Object {
}
}
}
+
+ bool can_do_affiliation_versioning = yield entity_info.has_feature(account, jid, Xmpp.Xep.MucAffiliationsVersioning.NS_URI);
+ if (!can_do_affiliation_versioning) {
+ stream.get_module(Xep.Muc.Module.IDENTITY).fetch_affiliations.begin(stream, jid.bare_jid, () => {
+ muc_affiliations.clear_affiliations(account, jid);
+ persist_muc_affiliations(account, jid.bare_jid);
+ });
+ }
+
+ room_info_updated(account, jid); // EntityInfo.has_feature trigged a disco query
+
} else if (res.muc_error != null) {
// Join failed
enter_errors[jid] = res.muc_error;
@@ -254,19 +257,11 @@ 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) {
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");
+ return entity_info.has_feature_offline(account, jid, Xep.Muc.FEATURE_MEMBERS_ONLY) && entity_info.has_feature_offline(account, jid, Xep.Muc.FEATURE_NON_ANONYMOUS);
}
public bool is_moderated_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.MODERATED);
+ return stream_interactor.get_module(EntityInfo.IDENTITY).has_feature_cached(account, jid, Xep.Muc.FEATURE_MODERATED);
}
public bool is_public_room(Account account, Jid jid) {
@@ -332,9 +327,13 @@ public class MucManager : StreamInteractionModule, Object {
}
public string? get_room_name(Account account, Jid jid) {
- Xep.Muc.Flag? flag = get_muc_flag(account);
- if (flag != null) {
- return flag.get_room_name(jid);
+ var identities = stream_interactor.get_module(EntityInfo.IDENTITY).get_identities_offline(account, jid);
+ if (identities == null) return null;
+
+ foreach (var identity in identities) {
+ if (identity.category == "conference") {
+ return identity.name;
+ }
}
return null;
}
@@ -471,8 +470,10 @@ public class MucManager : StreamInteractionModule, Object {
private_room_occupants_updated(account, muc_jid);
}
});
- stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_info_updated.connect( (stream, muc_jid) => {
- room_info_updated(account, muc_jid);
+ stream_interactor.module_manager.get_module(account, Xep.Muc.Module.IDENTITY).room_info_changed.connect( (stream, muc_jid) => {
+ stream_interactor.get_module(EntityInfo.IDENTITY).get_info_result.begin(account, muc_jid, null, () => {
+ room_info_updated(account, muc_jid);
+ });
});
stream_interactor.module_manager.get_module(account, Xep.OccupantIds.Module.IDENTITY).received_own_occupant_id.connect( (stream, jid, occupant_id) => {
if (!own_occupant_ids.has_key(account)) {
diff --git a/xmpp-vala/src/module/xep/0045_muc/flag.vala b/xmpp-vala/src/module/xep/0045_muc/flag.vala
index d0d2c359..a72965b3 100644
--- a/xmpp-vala/src/module/xep/0045_muc/flag.vala
+++ b/xmpp-vala/src/module/xep/0045_muc/flag.vala
@@ -5,9 +5,6 @@ namespace Xmpp.Xep.Muc {
public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "muc");
- private HashMap<Jid, Gee.List<Feature>> room_features = new HashMap<Jid, Gee.List<Feature>>(Jid.hash_bare_func, Jid.equals_bare_func);
- private HashMap<Jid, string> room_names = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
-
private HashMap<Jid, string> enter_ids = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
public HashMap<Jid, Promise<JoinResult?>> enter_futures = new HashMap<Jid, Promise<JoinResult?>>(Jid.hash_func, Jid.equals_func);
private HashMap<Jid, string> own_nicks = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
@@ -18,12 +15,6 @@ public class Flag : XmppStreamFlag {
private HashMap<Jid, HashMap<Jid, Affiliation>> affiliations = new HashMap<Jid, HashMap<Jid, Affiliation>>(Jid.hash_bare_func, Jid.equals_bare_func);
private HashMap<Jid, Role> occupant_role = new HashMap<Jid, Role>(Jid.hash_func, Jid.equals_func);
- public string? get_room_name(Jid muc_jid) { return room_names.has_key(muc_jid.bare_jid) ? room_names[muc_jid.bare_jid] : null; }
-
- public bool has_room_feature(Jid muc_jid, Feature feature) {
- return room_features.has_key(muc_jid.bare_jid) && room_features[muc_jid.bare_jid].contains(feature);
- }
-
public Jid? get_real_jid(Jid full_jid) { return occupant_real_jids[full_jid]; }
public Jid? get_occupant_jid(Jid real_jid, Jid room) {
@@ -77,14 +68,6 @@ public class Flag : XmppStreamFlag {
public string? get_muc_subject(Jid muc_jid) { return subjects[muc_jid.bare_jid]; }
- internal void set_room_name(Jid muc_jid, string name) {
- room_names[muc_jid.bare_jid] = name;
- }
-
- internal void set_room_features(Jid muc_jid, Gee.List<Feature> features) {
- room_features[muc_jid.bare_jid] = features;
- }
-
internal void set_real_jid(Jid full_jid, Jid real_jid) { occupant_real_jids[full_jid] = real_jid; }
internal void set_offline_member(Jid muc_jid, Jid real_jid, Affiliation affiliation) {
diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala
index ad929b00..76045172 100644
--- a/xmpp-vala/src/module/xep/0045_muc/module.vala
+++ b/xmpp-vala/src/module/xep/0045_muc/module.vala
@@ -8,6 +8,12 @@ private const string NS_URI_OWNER = NS_URI + "#owner";
public const string NS_URI_USER = NS_URI + "#user";
private const string NS_URI_REQUEST = NS_URI + "#request";
+public const string FEATURE_STABLE_ID = "http://jabber.org/protocol/muc#stable_id";
+public const string FEATURE_MEMBERS_ONLY = "muc_membersonly";
+public const string FEATURE_MODERATED = "muc_moderated";
+public const string FEATURE_NON_ANONYMOUS = "muc_nonanonymous";
+public const string FEATURE_PASSWORD_PROTECTED = "muc_passwordprotected";
+
public enum MucEnterError {
PASSWORD_REQUIRED,
BANNED,
@@ -34,26 +40,6 @@ public enum Role {
VISITOR
}
-public enum Feature {
- REGISTER,
- ROOMCONFIG,
- ROOMINFO,
- HIDDEN,
- MEMBERS_ONLY,
- MODERATED,
- NON_ANONYMOUS,
- OPEN,
- PASSWORD_PROTECTED,
- PERSISTENT,
- PUBLIC,
- ROOMS,
- SEMI_ANONYMOUS,
- STABLE_ID,
- TEMPORARY,
- UNMODERATED,
- UNSECURED
-}
-
public static void add_muc_pm_message_stanza_x_node(MessageStanza message_stanza) {
StanzaNode x_node = new StanzaNode.build("x", "http://jabber.org/protocol/muc#user").add_self_xmlns();
message_stanza.stanza.put_node(x_node);
@@ -74,6 +60,7 @@ public class Module : XmppStreamModule {
public signal void subject_set(XmppStream stream, string? subject, Jid jid);
public signal void invite_received(XmppStream stream, Jid room_jid, Jid from_jid, string? password, string? reason);
public signal void voice_request_received(XmppStream stream, Jid room_jid, Jid from_jid, string nick);
+ public signal void room_info_changed(XmppStream stream, Jid muc_jid);
public signal void room_info_updated(XmppStream stream, Jid muc_jid);
public signal void self_removed_from_room(XmppStream stream, Jid jid, StatusCode code);
@@ -299,7 +286,7 @@ public class Module : XmppStreamModule {
if (status_codes.contains(StatusCode.CONFIG_CHANGE_NON_PRIVACY) ||
status_codes.contains(StatusCode.NON_ANONYMOUS) ||
status_codes.contains(StatusCode.SEMI_ANONYMOUS)) {
- query_room_info.begin(stream, message.from.bare_jid);
+ room_info_changed(stream, message.from.bare_jid);
}
}
}
@@ -358,9 +345,6 @@ public class Module : XmppStreamModule {
if (status_codes.contains(StatusCode.SELF_PRESENCE)) {
Jid bare_jid = presence.from.bare_jid;
if (flag.get_enter_id(bare_jid) != null) {
-
- query_room_info.begin(stream, bare_jid);
-
flag.finish_muc_enter(bare_jid);
var join_result = new JoinResult() { nick=presence.from.resourcepart, newly_created=status_codes.contains(StatusCode.NEW_ROOM_CREATED) };
flag.enter_futures[bare_jid].set_value(join_result);
@@ -430,45 +414,6 @@ public class Module : XmppStreamModule {
}
}
- private async void query_room_info(XmppStream stream, Jid jid) {
- ServiceDiscovery.InfoResult? info_result = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, jid);
- if (info_result == null) return;
-
- Gee.List<Feature> features = new ArrayList<Feature>();
-
- foreach (ServiceDiscovery.Identity identity in info_result.identities) {
- if (identity.category == "conference" && identity.name != null) {
- stream.get_flag(Flag.IDENTITY).set_room_name(jid, identity.name);
- }
- }
-
- foreach (string feature in info_result.features) {
- Feature? parsed = null;
- switch (feature) {
- case "http://jabber.org/protocol/muc#register": parsed = Feature.REGISTER; break;
- case "http://jabber.org/protocol/muc#roomconfig": parsed = Feature.ROOMCONFIG; break;
- case "http://jabber.org/protocol/muc#roominfo": parsed = Feature.ROOMINFO; break;
- case "http://jabber.org/protocol/muc#stable_id": parsed = Feature.STABLE_ID; break;
- case "muc_hidden": parsed = Feature.HIDDEN; break;
- case "muc_membersonly": parsed = Feature.MEMBERS_ONLY; break;
- case "muc_moderated": parsed = Feature.MODERATED; break;
- case "muc_nonanonymous": parsed = Feature.NON_ANONYMOUS; break;
- case "muc_open": parsed = Feature.OPEN; break;
- case "muc_passwordprotected": parsed = Feature.PASSWORD_PROTECTED; break;
- case "muc_persistent": parsed = Feature.PERSISTENT; break;
- case "muc_public": parsed = Feature.PUBLIC; break;
- case "muc_rooms": parsed = Feature.ROOMS; break;
- case "muc_semianonymous": parsed = Feature.SEMI_ANONYMOUS; break;
- case "muc_temporary": parsed = Feature.TEMPORARY; break;
- case "muc_unmoderated": parsed = Feature.UNMODERATED; break;
- case "muc_unsecured": parsed = Feature.UNSECURED; break;
- }
- if (parsed != null) features.add(parsed);
- }
- stream.get_flag(Flag.IDENTITY).set_room_features(jid, features);
- room_info_updated(stream, jid);
- }
-
public async void fetch_affiliations(XmppStream stream, Jid muc_jid) {
query_affiliation.begin(stream, muc_jid, "member");
query_affiliation.begin(stream, muc_jid, "admin");
diff --git a/xmpp-vala/src/module/xep/0115_entity_capabilities.vala b/xmpp-vala/src/module/xep/0115_entity_capabilities.vala
index 8e15e0c2..e39dcbbd 100644
--- a/xmpp-vala/src/module/xep/0115_entity_capabilities.vala
+++ b/xmpp-vala/src/module/xep/0115_entity_capabilities.vala
@@ -35,11 +35,6 @@ namespace Xmpp.Xep.EntityCapabilities {
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0115_entity_capabilities");
private string own_ver_hash;
- private Storage storage;
-
- public Module(Storage storage) {
- this.storage = storage;
- }
private string get_own_hash(XmppStream stream) {
if (own_ver_hash == null) {