Remove features from service discovery module when detaching module from stream

fixes #179
fixes #812
This commit is contained in:
fiaxh 2020-04-21 16:25:21 +02:00
parent 3a8fef7b7b
commit 7c4260eed7
25 changed files with 122 additions and 33 deletions

View file

@ -24,7 +24,7 @@ public class EntityCapabilitiesStorage : Xep.EntityCapabilities.Storage, Object
}
}
public void store_identities(string entity, Gee.List<Identity> identities) {
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()

View file

@ -26,6 +26,7 @@ public class Module : XmppStreamModule, Jet.EnvelopEncoding {
}
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public bool is_available(XmppStream stream, Jid full_jid) {

View file

@ -35,7 +35,9 @@ public class StreamModule : XmppStreamModule {
stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NODE_DEVICELIST, (stream, jid, id, node) => parse_device_list(stream, jid, id, node), null);
}
public override void detach(XmppStream stream) {}
public override void detach(XmppStream stream) {
stream.get_module(Pubsub.Module.IDENTITY).remove_filtered_notification(stream, NODE_DEVICELIST);
}
public async ArrayList<int32> request_user_devicelist(XmppStream stream, Jid jid) {
var future = active_devicelist_requests[jid];

View file

@ -6,11 +6,24 @@ public class Flag : XmppStreamFlag {
public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "service_discovery");
private HashMap<Jid, Gee.List<string>?> entity_features = new HashMap<Jid, Gee.List<string>?>(Jid.hash_func, Jid.equals_func);
private HashMap<Jid, Gee.List<Identity>?> entity_identities = new HashMap<Jid, Gee.List<Identity>?>(Jid.hash_func, Jid.equals_func);
private HashMap<Jid, Gee.Set<Identity>?> entity_identities = new HashMap<Jid, Gee.Set<Identity>?>(Jid.hash_func, Jid.equals_func);
private HashMap<Jid, Gee.List<Item>?> entity_items = new HashMap<Jid, Gee.List<Item>?>(Jid.hash_func, Jid.equals_func);
public Gee.List<string> features = new ArrayList<string>();
public Gee.List<Identity>? get_entity_categories(Jid jid) {
private Gee.Set<string> own_features_ = new HashSet<string>();
public Gee.List<string> own_features {
owned get {
var ret = new ArrayList<string>();
foreach (var feature in own_features_) ret.add(feature);
return ret;
}
}
private Gee.Set<Identity> own_identities_ = new HashSet<Identity>(Identity.hash_func, Identity.equals_func);
public Gee.Set<Identity> own_identities {
owned get { return own_identities_.read_only_view; }
}
public Gee.Set<Identity>? get_entity_categories(Jid jid) {
return entity_identities.has_key(jid) ? entity_identities[jid] : null; // TODO isnt this default for hashmap
}
@ -29,7 +42,7 @@ public class Flag : XmppStreamFlag {
return entity_features[jid].contains(feature);
}
public void set_entity_identities(Jid jid, Gee.List<Identity>? identities) {
public void set_entity_identities(Jid jid, Gee.Set<Identity>? identities) {
entity_identities[jid] = identities;
}
@ -41,7 +54,20 @@ public class Flag : XmppStreamFlag {
entity_items[jid] = features;
}
public void add_own_feature(string feature) { features.add(feature); }
public void add_own_feature(string feature) {
if (own_features_.contains(feature)) {
warning("Tried to add the feature %s a second time".printf(feature));
return;
}
own_features_.add(feature);
}
public void remove_own_feature(string feature) {
own_features_.remove(feature);
}
public void add_own_identity(Identity identity) { own_identities_.add(identity); }
public void remove_own_identity(Identity identity) { own_identities_.remove(identity); }
public override string get_ns() { return NS_URI; }

View file

@ -17,6 +17,18 @@ public class Identity {
this.type_ = type;
this.name = name;
}
public static uint hash_func(Identity a) {
uint hash = a.category.hash() ^ a.type_.hash();
if (a.name != null) {
hash ^= a.name.hash();
}
return hash;
}
public static bool equals_func(Identity a, Identity b) {
return a.category == b.category && a.type_ == b.type_ && a.name == b.name;
}
}
}

View file

@ -20,9 +20,9 @@ public class InfoResult {
}
}
public Gee.List<Identity> identities {
public Gee.Set<Identity> identities {
owned get {
ArrayList<Identity> ret = new ArrayList<Identity>();
HashSet<Identity> ret = new HashSet<Identity>();
foreach (StanzaNode feature_node in iq.stanza.get_subnode("query", NS_URI_INFO).get_subnodes("identity", NS_URI_INFO)) {
ret.add(new Identity(feature_node.get_attribute("category", NS_URI_INFO),
feature_node.get_attribute("type", NS_URI_INFO),

View file

@ -9,27 +9,39 @@ public const string NS_URI_ITEMS = NS_URI + "#items";
public class Module : XmppStreamModule, Iq.Handler {
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0030_service_discovery_module");
public ArrayList<Identity> identities = new ArrayList<Identity>();
public Identity own_identity;
public Module.with_identity(string category, string type, string? name = null) {
add_identity(category, type, name);
own_identity = new Identity(category, type, name);
}
public void add_feature(XmppStream stream, string feature) {
stream.get_flag(Flag.IDENTITY).add_own_feature(feature);
}
public void remove_feature(XmppStream stream, string feature) {
stream.get_flag(Flag.IDENTITY).remove_own_feature(feature);
}
public void add_feature_notify(XmppStream stream, string feature) {
add_feature(stream, feature + "+notify");
}
public void add_identity(string category, string type, string? name = null) {
identities.add(new Identity(category, type, name));
public void remove_feature_notify(XmppStream stream, string feature) {
remove_feature(stream, feature + "+notify");
}
public delegate void HasEntryCategoryRes(XmppStream stream, Gee.List<Identity>? identities);
public void add_identity(XmppStream stream, Identity identity) {
stream.get_flag(Flag.IDENTITY).add_own_identity(identity);
}
public void remove_identity(XmppStream stream, Identity identity) {
stream.get_flag(Flag.IDENTITY).remove_own_identity(identity);
}
public delegate void HasEntryCategoryRes(XmppStream stream, Gee.Set<Identity>? identities);
public void get_entity_categories(XmppStream stream, Jid jid, owned HasEntryCategoryRes listener) {
Gee.List<Identity>? res = stream.get_flag(Flag.IDENTITY).get_entity_categories(jid);
Gee.Set<Identity>? res = stream.get_flag(Flag.IDENTITY).get_entity_categories(jid);
if (res != null) listener(stream, res);
request_info(stream, jid, (stream, query_result) => {
listener(stream, query_result != null ? query_result.identities : null);
@ -68,12 +80,17 @@ public class Module : XmppStreamModule, Iq.Handler {
public override void attach(XmppStream stream) {
stream.add_flag(new Flag());
add_identity(stream, own_identity);
stream.get_module(Iq.Module.IDENTITY).register_for_namespace(NS_URI_INFO, this);
add_feature(stream, NS_URI_INFO);
}
public override void detach(XmppStream stream) {
remove_identity(stream, own_identity);
stream.get_module(Iq.Module.IDENTITY).unregister_from_namespace(NS_URI_INFO, this);
remove_feature(stream, NS_URI_INFO);
}
public static void require(XmppStream stream) {
@ -85,8 +102,8 @@ public class Module : XmppStreamModule, Iq.Handler {
private void send_query_result(XmppStream stream, Iq.Stanza iq_request) {
InfoResult query_result = new ServiceDiscovery.InfoResult(iq_request);
query_result.features = stream.get_flag(Flag.IDENTITY).features;
query_result.identities = identities;
query_result.features = stream.get_flag(Flag.IDENTITY).own_features;
query_result.identities = stream.get_flag(Flag.IDENTITY).own_identities;
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, query_result.iq);
}
}

View file

@ -221,9 +221,7 @@ public class Module : XmppStreamModule {
stream.get_module(Presence.Module.IDENTITY).received_presence.connect(check_for_enter_error);
stream.get_module(Presence.Module.IDENTITY).received_available.connect(on_received_available);
stream.get_module(Presence.Module.IDENTITY).received_unavailable.connect(on_received_unavailable);
if (stream.get_module(ServiceDiscovery.Module.IDENTITY) != null) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
}
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
}
public override void detach(XmppStream stream) {
@ -232,6 +230,7 @@ public class Module : XmppStreamModule {
stream.get_module(Presence.Module.IDENTITY).received_presence.disconnect(check_for_enter_error);
stream.get_module(Presence.Module.IDENTITY).received_available.disconnect(on_received_available);
stream.get_module(Presence.Module.IDENTITY).received_unavailable.disconnect(on_received_unavailable);
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public override string get_ns() { return NS_URI; }

View file

@ -29,6 +29,12 @@ namespace Xmpp.Xep.Pubsub {
}
}
public void remove_filtered_notification(XmppStream stream, string node) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature_notify(stream, node);
item_listeners.unset(node);
retract_listeners.unset(node);
}
public async Gee.List<StanzaNode>? request_all(XmppStream stream, Jid jid, string node) { // TODO multiple nodes gehen auch
Iq.Stanza request_iq = new Iq.Stanza.get(new StanzaNode.build("pubsub", NS_URI).add_self_xmlns().put_node(new StanzaNode.build("items", NS_URI).put_attribute("node", node)));
request_iq.to = jid;

View file

@ -35,7 +35,9 @@ namespace Xmpp.Xep.UserAvatars {
stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NS_URI_METADATA, on_pupsub_event, null);
}
public override void detach(XmppStream stream) { }
public override void detach(XmppStream stream) {
stream.get_module(Pubsub.Module.IDENTITY).remove_filtered_notification(stream, NS_URI_METADATA);
}
public void on_pupsub_event(XmppStream stream, Jid jid, string id, StanzaNode? node) {

View file

@ -37,6 +37,7 @@ public class Module : XmppStreamModule {
}
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
stream.get_module(MessageModule.IDENTITY).received_message.disconnect(on_received_message);
stream.get_module(MessageModule.IDENTITY).send_pipeline.disconnect(send_pipeline_listener);
}

View file

@ -28,7 +28,7 @@ namespace Xmpp.Xep.EntityCapabilities {
private string get_own_hash(XmppStream stream) {
if (own_ver_hash == null) {
own_ver_hash = compute_hash(stream.get_module(ServiceDiscovery.Module.IDENTITY).identities, stream.get_flag(ServiceDiscovery.Flag.IDENTITY).features, new ArrayList<DataForms.DataForm>());
own_ver_hash = compute_hash(stream.get_flag(ServiceDiscovery.Flag.IDENTITY).own_identities, stream.get_flag(ServiceDiscovery.Flag.IDENTITY).own_features, new ArrayList<DataForms.DataForm>());
}
return own_ver_hash;
}
@ -42,6 +42,7 @@ namespace Xmpp.Xep.EntityCapabilities {
public override void detach(XmppStream stream) {
stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.disconnect(on_pre_send_presence_stanza);
stream.get_module(Presence.Module.IDENTITY).received_presence.disconnect(on_received_presence);
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public override string get_ns() { return NS_URI; }
@ -86,7 +87,10 @@ namespace Xmpp.Xep.EntityCapabilities {
}
}
private static string compute_hash(Gee.List<ServiceDiscovery.Identity> identities, Gee.List<string> features, Gee.List<DataForms.DataForm> data_forms) {
private static string compute_hash(Gee.Set<ServiceDiscovery.Identity> identities_set, Gee.List<string> features, Gee.List<DataForms.DataForm> data_forms) {
var identities = new ArrayList<ServiceDiscovery.Identity>();
foreach (var identity in identities_set) identities.add(identity);
identities.sort(compare_identities);
features.sort();
@ -154,7 +158,7 @@ namespace Xmpp.Xep.EntityCapabilities {
}
public interface Storage : Object {
public abstract void store_identities(string entity, Gee.List<ServiceDiscovery.Identity> identities);
public abstract void store_identities(string entity, Gee.Set<ServiceDiscovery.Identity> identities);
public abstract void store_features(string entity, Gee.List<string> capabilities);
public abstract ServiceDiscovery.Identity? get_identities(string entity);
public abstract Gee.List<string> get_features(string entity);

View file

@ -127,6 +127,7 @@ public class Module : XmppStreamModule, Iq.Handler {
current_stream = stream;
}
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
stream.get_module(Iq.Module.IDENTITY).unregister_from_namespace(NS_URI, this);
}

View file

@ -26,6 +26,7 @@ namespace Xmpp.Xep.MessageDeliveryReceipts {
}
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
stream.get_module(MessageModule.IDENTITY).received_message.disconnect(received_message);
stream.get_module(MessageModule.IDENTITY).send_pipeline.disconnect(send_pipeline_listener);
}

View file

@ -72,8 +72,9 @@ public class Module : XmppStreamModule, Iq.Handler {
}
public override void detach(XmppStream stream) {
stream.stream_negotiated.disconnect(on_stream_negotiated);
stream.get_module(Iq.Module.IDENTITY).unregister_from_namespace(NS_URI, this);
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
stream.stream_negotiated.disconnect(on_stream_negotiated);
}
public override string get_ns() { return NS_URI; }

View file

@ -22,6 +22,7 @@ namespace Xmpp.Xep.Ping {
public override void detach(XmppStream stream) {
stream.get_module(Iq.Module.IDENTITY).unregister_from_namespace(NS_URI, this);
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public void on_iq_get(XmppStream stream, Iq.Stanza iq) {

View file

@ -13,7 +13,9 @@ public class Module : Jingle.ContentType, XmppStreamModule {
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
stream.get_module(Jingle.Module.IDENTITY).register_content_type(this);
}
public override void detach(XmppStream stream) { }
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public string content_type_ns_uri() {
return NS_URI;

View file

@ -13,7 +13,9 @@ public class Module : Jingle.Transport, XmppStreamModule {
stream.get_module(Jingle.Module.IDENTITY).register_transport(this);
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
}
public override void detach(XmppStream stream) { }
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public override string get_ns() { return NS_URI; }
public override string get_id() { return IDENTITY.id; }

View file

@ -14,7 +14,9 @@ public class Module : Jingle.Transport, XmppStreamModule {
stream.get_module(Jingle.Module.IDENTITY).register_transport(this);
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
}
public override void detach(XmppStream stream) { }
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public override string get_ns() { return NS_URI; }
public override string get_id() { return IDENTITY.id; }

View file

@ -26,6 +26,7 @@ public class Module : XmppStreamModule {
public override void detach(XmppStream stream) {
stream.stream_negotiated.disconnect(enable);
stream.get_module(MessageModule.IDENTITY).received_pipeline.disconnect(received_pipeline_listener);
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public override string get_ns() {

View file

@ -21,7 +21,9 @@ public class Module : XmppStreamModule {
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
}
public override void detach(XmppStream stream) {}
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public override string get_ns() { return NS_URI; }

View file

@ -36,8 +36,9 @@ public class Module : XmppStreamModule {
}
public override void detach(XmppStream stream) {
stream.get_module(MessageModule.IDENTITY).received_message.disconnect(on_received_message);
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
stream.get_module(MessageModule.IDENTITY).send_pipeline.disconnect(send_pipeline_listener);
stream.get_module(MessageModule.IDENTITY).received_message.disconnect(on_received_message);
}
public override string get_ns() { return NS_URI; }

View file

@ -14,7 +14,9 @@ public class Module : XmppStreamModule {
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
}
public override void detach(XmppStream stream) {}
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public override string get_ns() { return NS_URI; }

View file

@ -15,6 +15,7 @@ public class Module : XmppStreamModule, SecurityPrecondition {
}
public override void detach(XmppStream stream) {
stream.get_module(ServiceDiscovery.Module.IDENTITY).remove_feature(stream, NS_URI);
}
public bool is_available(XmppStream stream, Jid full_jid) {

View file

@ -101,7 +101,9 @@ public class Module : BookmarksProvider, XmppStreamModule {
stream.get_module(Pubsub.Module.IDENTITY).add_filtered_notification(stream, NS_URI, on_pupsub_item, on_pupsub_retract);
}
public override void detach(XmppStream stream) { }
public override void detach(XmppStream stream) {
stream.get_module(Pubsub.Module.IDENTITY).remove_filtered_notification(stream, NS_URI);
}
public override string get_ns() { return NS_URI; }
public override string get_id() { return IDENTITY.id; }