Handle entity hash in server features node, make ServiceDiscovery request_info/items async, add caching has_entity_feature
This commit is contained in:
parent
9661116d78
commit
e7bc68ad4d
|
@ -16,6 +16,8 @@ public class EntityCapabilitiesStorage : Xep.EntityCapabilities.Storage, Object
|
||||||
}
|
}
|
||||||
|
|
||||||
public void store_features(string entity, Gee.List<string> features) {
|
public void store_features(string entity, Gee.List<string> features) {
|
||||||
|
if (features_cache.contains(entity)) return;
|
||||||
|
|
||||||
foreach (string feature in features) {
|
foreach (string feature in features) {
|
||||||
db.entity_feature.insert()
|
db.entity_feature.insert()
|
||||||
.value(db.entity_feature.entity, entity)
|
.value(db.entity_feature.entity, entity)
|
||||||
|
|
|
@ -386,24 +386,20 @@ public class MessageProcessor : StreamInteractionModule, Object {
|
||||||
return Entities.Message.Type.GROUPCHAT_PM;
|
return Entities.Message.Type.GROUPCHAT_PM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SourceFunc callback = determine_message_type.callback;
|
|
||||||
XmppStream stream = stream_interactor.get_stream(account);
|
XmppStream stream = stream_interactor.get_stream(account);
|
||||||
if (stream != null) stream.get_module(Xep.ServiceDiscovery.Module.IDENTITY).get_entity_categories(stream, message.counterpart.bare_jid, (stream, identities) => {
|
if (stream != null) {
|
||||||
|
Gee.Set<Xep.ServiceDiscovery.Identity>? identities = yield stream.get_module(Xep.ServiceDiscovery.Module.IDENTITY).get_entity_identities(stream, message.counterpart.bare_jid);
|
||||||
if (identities == null) {
|
if (identities == null) {
|
||||||
message.type_ = Entities.Message.Type.CHAT;
|
return Entities.Message.Type.CHAT;
|
||||||
Idle.add((owned) callback);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
foreach (Xep.ServiceDiscovery.Identity identity in identities) {
|
foreach (Xep.ServiceDiscovery.Identity identity in identities) {
|
||||||
if (identity.category == Xep.ServiceDiscovery.Identity.CATEGORY_CONFERENCE) {
|
if (identity.category == Xep.ServiceDiscovery.Identity.CATEGORY_CONFERENCE) {
|
||||||
message.type_ = Entities.Message.Type.GROUPCHAT_PM;
|
return Entities.Message.Type.GROUPCHAT_PM;
|
||||||
} else {
|
} else {
|
||||||
message.type_ = Entities.Message.Type.CHAT;
|
return Entities.Message.Type.CHAT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Idle.add((owned) callback);
|
}
|
||||||
});
|
|
||||||
yield;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Entities.Message.Type.CHAT;
|
return Entities.Message.Type.CHAT;
|
||||||
|
|
|
@ -23,8 +23,8 @@ public class Flag : XmppStreamFlag {
|
||||||
owned get { return own_identities_.read_only_view; }
|
owned get { return own_identities_.read_only_view; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Gee.Set<Identity>? get_entity_categories(Jid jid) {
|
public Gee.Set<Identity>? get_entity_identities(Jid jid) {
|
||||||
return entity_identities.has_key(jid) ? entity_identities[jid] : null; // TODO isn’t this default for hashmap
|
return entity_identities.has_key(jid) ? entity_identities[jid].read_only_view : null; // TODO isn’t this default for hashmap
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool? has_entity_identity(Jid jid, string category, string type) {
|
public bool? has_entity_identity(Jid jid, string category, string type) {
|
||||||
|
|
|
@ -9,6 +9,8 @@ public const string NS_URI_ITEMS = NS_URI + "#items";
|
||||||
public class Module : XmppStreamModule, Iq.Handler {
|
public class Module : XmppStreamModule, Iq.Handler {
|
||||||
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0030_service_discovery_module");
|
public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0030_service_discovery_module");
|
||||||
|
|
||||||
|
private HashMap<Jid, Future<InfoResult?>> active_info_requests = new HashMap<Jid, Future<InfoResult?>>(Jid.hash_func, Jid.equals_func);
|
||||||
|
|
||||||
public Identity own_identity;
|
public Identity own_identity;
|
||||||
|
|
||||||
public Module.with_identity(string category, string type, string? name = null) {
|
public Module.with_identity(string category, string type, string? name = null) {
|
||||||
|
@ -39,36 +41,63 @@ public class Module : XmppStreamModule, Iq.Handler {
|
||||||
stream.get_flag(Flag.IDENTITY).remove_own_identity(identity);
|
stream.get_flag(Flag.IDENTITY).remove_own_identity(identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void HasEntryCategoryRes(XmppStream stream, Gee.Set<Identity>? identities);
|
public async bool has_entity_feature(XmppStream stream, Jid jid, string feature) {
|
||||||
public void get_entity_categories(XmppStream stream, Jid jid, owned HasEntryCategoryRes listener) {
|
Flag flag = stream.get_flag(Flag.IDENTITY);
|
||||||
Gee.Set<Identity>? res = stream.get_flag(Flag.IDENTITY).get_entity_categories(jid);
|
|
||||||
if (res != null) listener(stream, res);
|
if (flag.has_entity_feature(jid, feature) == null) {
|
||||||
request_info(stream, jid, (stream, query_result) => {
|
InfoResult? info_result = yield request_info(stream, jid);
|
||||||
listener(stream, query_result != null ? query_result.identities : null);
|
stream.get_flag(Flag.IDENTITY).set_entity_features(info_result.iq.from, info_result != null ? info_result.features : null);
|
||||||
});
|
stream.get_flag(Flag.IDENTITY).set_entity_identities(info_result.iq.from, info_result != null ? info_result.identities : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return flag.has_entity_feature(jid, feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void OnInfoResult(XmppStream stream, InfoResult? query_result);
|
public async Gee.Set<Identity>? get_entity_identities(XmppStream stream, Jid jid) {
|
||||||
public void request_info(XmppStream stream, Jid jid, owned OnInfoResult listener) {
|
Flag flag = stream.get_flag(Flag.IDENTITY);
|
||||||
Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_INFO).add_self_xmlns());
|
|
||||||
iq.to = jid;
|
if (flag.get_entity_identities(jid) == null) {
|
||||||
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => {
|
InfoResult? info_result = yield request_info(stream, jid);
|
||||||
InfoResult? result = InfoResult.create_from_iq(iq);
|
stream.get_flag(Flag.IDENTITY).set_entity_features(info_result.iq.from, info_result != null ? info_result.features : null);
|
||||||
stream.get_flag(Flag.IDENTITY).set_entity_features(iq.from, result != null ? result.features : null);
|
stream.get_flag(Flag.IDENTITY).set_entity_identities(info_result.iq.from, info_result != null ? info_result.identities : null);
|
||||||
stream.get_flag(Flag.IDENTITY).set_entity_identities(iq.from, result != null ? result.identities : null);
|
}
|
||||||
listener(stream, result);
|
|
||||||
});
|
return flag.get_entity_identities(jid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void OnItemsResult(XmppStream stream, ItemsResult query_result);
|
public async InfoResult? request_info(XmppStream stream, Jid jid) {
|
||||||
public void request_items(XmppStream stream, Jid jid, owned OnItemsResult listener) {
|
var future = active_info_requests[jid];
|
||||||
Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_ITEMS).add_self_xmlns());
|
if (future == null) {
|
||||||
iq.to = jid;
|
var promise = new Promise<InfoResult?>();
|
||||||
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => {
|
future = promise.future;
|
||||||
ItemsResult? result = ItemsResult.create_from_iq(iq);
|
active_info_requests[jid] = future;
|
||||||
stream.get_flag(Flag.IDENTITY).set_entity_items(iq.from, result != null ? result.items : null);
|
|
||||||
listener(stream, result);
|
Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_INFO).add_self_xmlns()) { to=jid };
|
||||||
});
|
Iq.Stanza iq_response = yield stream.get_module(Iq.Module.IDENTITY).send_iq_async(stream, iq);
|
||||||
|
InfoResult? result = InfoResult.create_from_iq(iq_response);
|
||||||
|
|
||||||
|
promise.set_value(result);
|
||||||
|
active_info_requests.unset(jid);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
InfoResult? res = yield future.wait_async();
|
||||||
|
return res;
|
||||||
|
} catch (FutureError error) {
|
||||||
|
warning("Future error when waiting for info request result: %s", error.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ItemsResult? request_items(XmppStream stream, Jid jid) {
|
||||||
|
StanzaNode query_node = new StanzaNode.build("query", NS_URI_ITEMS).add_self_xmlns();
|
||||||
|
Iq.Stanza iq = new Iq.Stanza.get(query_node) { to=jid };
|
||||||
|
|
||||||
|
Iq.Stanza iq_result = yield stream.get_module(Iq.Module.IDENTITY).send_iq_async(stream, iq);
|
||||||
|
ItemsResult? result = ItemsResult.create_from_iq(iq_result);
|
||||||
|
stream.get_flag(Flag.IDENTITY).set_entity_items(iq_result.from, result != null ? result.items : null);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void on_iq_get(XmppStream stream, Iq.Stanza iq) {
|
public void on_iq_get(XmppStream stream, Iq.Stanza iq) {
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class Module : XmppStreamModule {
|
||||||
|
|
||||||
stream.get_flag(Flag.IDENTITY).start_muc_enter(bare_jid, presence.id);
|
stream.get_flag(Flag.IDENTITY).start_muc_enter(bare_jid, presence.id);
|
||||||
|
|
||||||
query_room_info(stream, bare_jid);
|
query_room_info.begin(stream, bare_jid);
|
||||||
stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence);
|
stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence);
|
||||||
|
|
||||||
var promise = new Promise<JoinResult?>();
|
var promise = new Promise<JoinResult?>();
|
||||||
|
@ -273,7 +273,7 @@ public class Module : XmppStreamModule {
|
||||||
if (status_codes.contains(StatusCode.CONFIG_CHANGE_NON_PRIVACY) ||
|
if (status_codes.contains(StatusCode.CONFIG_CHANGE_NON_PRIVACY) ||
|
||||||
status_codes.contains(StatusCode.NON_ANONYMOUS) ||
|
status_codes.contains(StatusCode.NON_ANONYMOUS) ||
|
||||||
status_codes.contains(StatusCode.SEMI_ANONYMOUS)) {
|
status_codes.contains(StatusCode.SEMI_ANONYMOUS)) {
|
||||||
query_room_info(stream, message.from.bare_jid);
|
query_room_info.begin(stream, message.from.bare_jid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -398,45 +398,43 @@ public class Module : XmppStreamModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void query_room_info(XmppStream stream, Jid jid) {
|
private async void query_room_info(XmppStream stream, Jid jid) {
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, jid, (stream, query_result) => {
|
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>();
|
Gee.List<Feature> features = new ArrayList<Feature>();
|
||||||
if (query_result != null) {
|
|
||||||
|
|
||||||
foreach (ServiceDiscovery.Identity identity in query_result.identities) {
|
foreach (ServiceDiscovery.Identity identity in info_result.identities) {
|
||||||
if (identity.category == "conference") {
|
if (identity.category == "conference") {
|
||||||
stream.get_flag(Flag.IDENTITY).set_room_name(jid, identity.name);
|
stream.get_flag(Flag.IDENTITY).set_room_name(jid, identity.name);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (string feature in query_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);
|
|
||||||
});
|
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 delegate void OnAffiliationResult(XmppStream stream, Gee.List<Jid> jids);
|
public delegate void OnAffiliationResult(XmppStream stream, Gee.List<Jid> jids);
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class Module : XmppStreamModule, Iq.Handler {
|
||||||
|
|
||||||
public override void attach(XmppStream stream) {
|
public override void attach(XmppStream stream) {
|
||||||
stream.add_flag(new Flag());
|
stream.add_flag(new Flag());
|
||||||
query_availability(stream);
|
query_availability.begin(stream);
|
||||||
}
|
}
|
||||||
public override void detach(XmppStream stream) { }
|
public override void detach(XmppStream stream) { }
|
||||||
|
|
||||||
|
@ -33,41 +33,36 @@ public class Module : XmppStreamModule, Iq.Handler {
|
||||||
return stream.get_flag(Flag.IDENTITY).proxies;
|
return stream.get_flag(Flag.IDENTITY).proxies;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void query_availability(XmppStream stream) {
|
private async void query_availability(XmppStream stream) {
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_items(stream, stream.remote_name, (stream, items_result) => {
|
ServiceDiscovery.ItemsResult? items_result = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).request_items(stream, stream.remote_name);
|
||||||
foreach (Xep.ServiceDiscovery.Item item in items_result.items) {
|
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, item.jid, (stream, info_result) => {
|
foreach (Xep.ServiceDiscovery.Item item in items_result.items) {
|
||||||
foreach (string feature in info_result.features) {
|
bool has_feature = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).has_entity_feature(stream, item.jid, NS_URI);
|
||||||
if (feature == NS_URI) {
|
if (!has_feature) continue;
|
||||||
StanzaNode query_ = new StanzaNode.build("query", NS_URI).add_self_xmlns();
|
|
||||||
Iq.Stanza iq = new Iq.Stanza.get(query_) { to=item.jid };
|
StanzaNode query_node = new StanzaNode.build("query", NS_URI).add_self_xmlns();
|
||||||
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => {
|
Iq.Stanza iq = new Iq.Stanza.get(query_node) { to=item.jid };
|
||||||
if (iq.is_error()) {
|
|
||||||
return;
|
Iq.Stanza iq_result = yield stream.get_module(Iq.Module.IDENTITY).send_iq_async(stream, iq);
|
||||||
}
|
if (iq_result.is_error()) continue;
|
||||||
StanzaNode? query = iq.stanza.get_subnode("query", NS_URI);
|
|
||||||
StanzaNode? stream_host = query != null ? query.get_subnode("streamhost", NS_URI) : null;
|
StanzaNode? query_result_node = iq_result.stanza.get_subnode("query", NS_URI);
|
||||||
if (query == null || stream_host == null) {
|
StanzaNode? stream_host = query_result_node != null ? query_result_node.get_subnode("streamhost", NS_URI) : null;
|
||||||
return;
|
if (query_result_node == null || stream_host == null) {
|
||||||
}
|
return;
|
||||||
string? host = stream_host.get_attribute("host");
|
|
||||||
string? jid_str = stream_host.get_attribute("jid");
|
|
||||||
Jid? jid = null;
|
|
||||||
try {
|
|
||||||
jid = jid_str != null ? new Jid(jid_str) : null;
|
|
||||||
} catch (InvalidJidError ignored) {
|
|
||||||
}
|
|
||||||
int port = stream_host.get_attribute_int("port");
|
|
||||||
if (host == null || jid == null || port <= 0 || port > 65535) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
stream.get_flag(Flag.IDENTITY).proxies.add(new Proxy(host, jid, port));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
string? host = stream_host.get_attribute("host");
|
||||||
|
string? jid_str = stream_host.get_attribute("jid");
|
||||||
|
Jid? jid = null;
|
||||||
|
try {
|
||||||
|
jid = jid_str != null ? new Jid(jid_str) : null;
|
||||||
|
} catch (InvalidJidError ignored) { }
|
||||||
|
int port = stream_host.get_attribute_int("port");
|
||||||
|
if (host == null || jid == null || port <= 0 || port > 65535) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stream.get_flag(Flag.IDENTITY).proxies.add(new Proxy(host, jid, port));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string get_ns() { return NS_URI; }
|
public override string get_ns() { return NS_URI; }
|
||||||
|
|
|
@ -5,10 +5,15 @@ namespace Xmpp.Xep.EntityCapabilities {
|
||||||
|
|
||||||
private Regex? sha1_base64_regex = null;
|
private Regex? sha1_base64_regex = null;
|
||||||
|
|
||||||
public string? get_caps_hash(Presence.Stanza presence) {
|
private Regex get_sha1_base64_regex() {
|
||||||
if (sha1_base64_regex == null) {
|
if (sha1_base64_regex == null) {
|
||||||
sha1_base64_regex = /^[A-Za-z0-9+\/]{27}=$/;
|
sha1_base64_regex = /^[A-Za-z0-9+\/]{27}=$/;
|
||||||
}
|
}
|
||||||
|
return sha1_base64_regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? get_caps_hash(Presence.Stanza presence) {
|
||||||
|
Regex sha1_base64_regex = get_sha1_base64_regex();
|
||||||
StanzaNode? c_node = presence.stanza.get_subnode("c", NS_URI);
|
StanzaNode? c_node = presence.stanza.get_subnode("c", NS_URI);
|
||||||
if (c_node == null) return null;
|
if (c_node == null) return null;
|
||||||
string? ver_attribute = c_node.get_attribute("ver", NS_URI);
|
string? ver_attribute = c_node.get_attribute("ver", NS_URI);
|
||||||
|
@ -37,6 +42,8 @@ namespace Xmpp.Xep.EntityCapabilities {
|
||||||
stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.connect(on_pre_send_presence_stanza);
|
stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.connect(on_pre_send_presence_stanza);
|
||||||
stream.get_module(Presence.Module.IDENTITY).received_presence.connect(on_received_presence);
|
stream.get_module(Presence.Module.IDENTITY).received_presence.connect(on_received_presence);
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
|
stream.get_module(ServiceDiscovery.Module.IDENTITY).add_feature(stream, NS_URI);
|
||||||
|
|
||||||
|
check_features_node_ver(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void detach(XmppStream stream) {
|
public override void detach(XmppStream stream) {
|
||||||
|
@ -61,14 +68,27 @@ namespace Xmpp.Xep.EntityCapabilities {
|
||||||
string? caps_hash = get_caps_hash(presence);
|
string? caps_hash = get_caps_hash(presence);
|
||||||
if (caps_hash == null) return;
|
if (caps_hash == null) return;
|
||||||
|
|
||||||
|
process_hash.begin(stream, presence.from, caps_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check_features_node_ver(XmppStream stream) {
|
||||||
|
StanzaNode? node = stream.features.get_subnode("c", NS_URI);
|
||||||
|
if (node == null) return;
|
||||||
|
|
||||||
|
string? ver_attribute = node.get_attribute("ver", NS_URI);
|
||||||
|
if (ver_attribute == null) return;
|
||||||
|
|
||||||
|
process_hash.begin(stream, stream.remote_name, ver_attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void process_hash(XmppStream stream, Jid jid_from, string caps_hash) {
|
||||||
Gee.List<string> capabilities = storage.get_features(caps_hash);
|
Gee.List<string> capabilities = storage.get_features(caps_hash);
|
||||||
ServiceDiscovery.Identity identity = storage.get_identities(caps_hash);
|
ServiceDiscovery.Identity identity = storage.get_identities(caps_hash);
|
||||||
if (identity == null) {
|
if (identity == null) {
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, presence.from, (stream, query_result) => {
|
ServiceDiscovery.InfoResult? info_result = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, jid_from);
|
||||||
store_entity_result(stream, caps_hash, query_result);
|
store_entity_result(stream, caps_hash, info_result);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
stream.get_flag(ServiceDiscovery.Flag.IDENTITY).set_entity_features(presence.from, capabilities);
|
stream.get_flag(ServiceDiscovery.Flag.IDENTITY).set_entity_features(jid_from, capabilities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,29 +80,24 @@ public class Module : XmppStreamModule, Iq.Handler {
|
||||||
public override string get_ns() { return NS_URI; }
|
public override string get_ns() { return NS_URI; }
|
||||||
public override string get_id() { return IDENTITY.id; }
|
public override string get_id() { return IDENTITY.id; }
|
||||||
|
|
||||||
private void on_stream_negotiated(XmppStream stream) {
|
private async void on_stream_negotiated(XmppStream stream) {
|
||||||
stream.get_module(Xep.ServiceDiscovery.Module.IDENTITY).request_info(stream, stream.remote_name, (stream, info_result) => {
|
bool has_feature = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).has_entity_feature(stream, stream.remote_name, NS_URI);
|
||||||
if (info_result.features.contains(NS_URI)) {
|
if (has_feature) {
|
||||||
stream.add_flag(new Flag());
|
stream.add_flag(new Flag());
|
||||||
get_blocklist(stream, (stream, jids) => {
|
stream.get_flag(Flag.IDENTITY).blocklist = yield get_blocklist(stream);
|
||||||
stream.get_flag(Flag.IDENTITY).blocklist = jids;
|
}
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate void OnBlocklist(XmppStream stream, Gee.List<string> jids);
|
private async Gee.List<string> get_blocklist(XmppStream stream) {
|
||||||
private void get_blocklist(XmppStream stream, owned OnBlocklist listener) {
|
|
||||||
StanzaNode blocklist_node = new StanzaNode.build("blocklist", NS_URI).add_self_xmlns();
|
StanzaNode blocklist_node = new StanzaNode.build("blocklist", NS_URI).add_self_xmlns();
|
||||||
Iq.Stanza iq = new Iq.Stanza.get(blocklist_node);
|
Iq.Stanza iq = new Iq.Stanza.get(blocklist_node);
|
||||||
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq) => {
|
|
||||||
StanzaNode? node = iq.stanza.get_subnode("blocklist", NS_URI);
|
Iq.Stanza result_iq = yield stream.get_module(Iq.Module.IDENTITY).send_iq_async(stream, iq);
|
||||||
if (node != null) {
|
StanzaNode? node = result_iq.stanza.get_subnode("blocklist", NS_URI);
|
||||||
Gee.List<string> jids = get_jids_from_items(node);
|
if (node != null) {
|
||||||
listener(stream, jids);
|
return get_jids_from_items(node);
|
||||||
}
|
}
|
||||||
});
|
return new ArrayList<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Gee.List<string> get_jids_from_items(StanzaNode node) {
|
private Gee.List<string> get_jids_from_items(StanzaNode node) {
|
||||||
|
|
|
@ -108,17 +108,22 @@ public class Module : XmppStreamModule {
|
||||||
return result_iq;
|
return result_iq;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void query_availability(XmppStream stream) {
|
private async void query_availability(XmppStream stream) {
|
||||||
stream.get_module(Xep.ServiceDiscovery.Module.IDENTITY).request_info(stream, stream.get_flag(Bind.Flag.IDENTITY).my_jid.bare_jid, (stream, info_result) => {
|
Jid own_jid = stream.get_flag(Bind.Flag.IDENTITY).my_jid.bare_jid;
|
||||||
if (info_result == null) return;
|
|
||||||
if (info_result.features.contains(NS_URI)) {
|
bool ver_2_available = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).has_entity_feature(stream, own_jid, NS_URI);
|
||||||
stream.add_flag(new Flag(NS_URI));
|
if (ver_2_available) {
|
||||||
feature_available(stream);
|
stream.add_flag(new Flag(NS_URI));
|
||||||
} else if (info_result.features.contains(NS_URI_1)) {
|
feature_available(stream);
|
||||||
stream.add_flag(new Flag(NS_URI_1));
|
return;
|
||||||
feature_available(stream);
|
}
|
||||||
}
|
|
||||||
});
|
bool ver_1_available = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).has_entity_feature(stream, own_jid, NS_URI_1);
|
||||||
|
if (ver_1_available) {
|
||||||
|
stream.add_flag(new Flag(NS_URI_1));
|
||||||
|
feature_available(stream);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,25 +105,22 @@ public class Module : XmppStreamModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void detach(XmppStream stream) {
|
public override void detach(XmppStream stream) {
|
||||||
stream.get_module(Bind.Module.IDENTITY).bound_to_resource.disconnect(query_availability);
|
stream.stream_negotiated.disconnect(query_availability);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string get_ns() { return NS_URI; }
|
public override string get_ns() { return NS_URI; }
|
||||||
public override string get_id() { return IDENTITY.id; }
|
public override string get_id() { return IDENTITY.id; }
|
||||||
|
|
||||||
private void query_availability(XmppStream stream) {
|
private async void query_availability(XmppStream stream) {
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, stream.remote_name, (stream, info_result) => {
|
ServiceDiscovery.InfoResult? info_result = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, stream.remote_name);
|
||||||
bool available = check_ns_in_info(stream, stream.remote_name, info_result);
|
bool available = check_ns_in_info(stream, stream.remote_name, info_result);
|
||||||
if (!available) {
|
if (!available) {
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_items(stream, stream.remote_name, (stream, items_result) => {
|
ServiceDiscovery.ItemsResult? items_result = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).request_items(stream, stream.remote_name);
|
||||||
foreach (Xep.ServiceDiscovery.Item item in items_result.items) {
|
foreach (Xep.ServiceDiscovery.Item item in items_result.items) {
|
||||||
stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, item.jid, (stream, info_result) => {
|
ServiceDiscovery.InfoResult? info_result2 = yield stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, item.jid);
|
||||||
check_ns_in_info(stream, item.jid, info_result);
|
check_ns_in_info(stream, item.jid, info_result2);
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool check_ns_in_info(XmppStream stream, Jid jid, Xep.ServiceDiscovery.InfoResult info_result) {
|
private bool check_ns_in_info(XmppStream stream, Jid jid, Xep.ServiceDiscovery.InfoResult info_result) {
|
||||||
|
|
Loading…
Reference in a new issue