aboutsummaryrefslogtreecommitdiff
path: root/xmpp-vala
diff options
context:
space:
mode:
authorfiaxh <git@lightrise.org>2021-11-04 17:11:33 +0100
committerfiaxh <git@lightrise.org>2021-11-04 17:11:33 +0100
commit54427b04f9a35bd8912cb15a03cd36c44defb4a4 (patch)
tree080c732aa2092fca519e76256d55fe33dbbeef1a /xmpp-vala
parent37c543b6e7579d825aee966a5d663ba9c79f0b0a (diff)
downloaddino-54427b04f9a35bd8912cb15a03cd36c44defb4a4.tar.gz
dino-54427b04f9a35bd8912cb15a03cd36c44defb4a4.zip
Add initial COIN (XEP-0298) implementation to xmpp-vala
Diffstat (limited to 'xmpp-vala')
-rw-r--r--xmpp-vala/src/module/xep/0298_coin.vala136
1 files changed, 136 insertions, 0 deletions
diff --git a/xmpp-vala/src/module/xep/0298_coin.vala b/xmpp-vala/src/module/xep/0298_coin.vala
new file mode 100644
index 00000000..58b3b055
--- /dev/null
+++ b/xmpp-vala/src/module/xep/0298_coin.vala
@@ -0,0 +1,136 @@
+using Gee;
+
+namespace Xmpp.Xep.Coin {
+ private const string NS_RFC = "urn:ietf:params:xml:ns:conference-info";
+
+ public class Module : XmppStreamModule, Iq.Handler {
+ public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_RFC, "0298_coin");
+
+ public signal void coin_info_received(Jid jid, ConferenceInfo info);
+
+ public async override void on_iq_set(XmppStream stream, Iq.Stanza iq) {
+ ConferenceInfo? info = parse_node(iq.stanza.get_subnode("conference-info", NS_RFC), null);
+ if (info == null) return;
+
+ coin_info_received(iq.from, info);
+ }
+
+ public override void attach(XmppStream stream) {
+ stream.get_module(Iq.Module.IDENTITY).register_for_namespace(NS_RFC, this);
+ }
+
+ public override void detach(XmppStream stream) { }
+
+ public override string get_ns() { return NS_RFC; }
+
+ public override string get_id() { return IDENTITY.id; }
+ }
+
+ public ConferenceInfo? parse_node(StanzaNode conference_node, ConferenceInfo? previous_conference_info) {
+ string? version_str = conference_node.get_attribute("version");
+ string? conference_state = conference_node.get_attribute("state");
+ if (version_str == null || conference_state == null) return null;
+
+ int version = int.parse(version_str);
+ if (previous_conference_info != null && version <= previous_conference_info.version) return null;
+
+ ConferenceInfo conference_info = previous_conference_info ?? new ConferenceInfo();
+ conference_info.version = version;
+
+ Gee.List<StanzaNode> user_nodes = conference_node.get_deep_subnodes(NS_RFC + ":users", NS_RFC + ":user");
+ foreach (StanzaNode user_node in user_nodes) {
+ string? jid_string = user_node.get_attribute("entity");
+ if (jid_string == null) continue;
+// if (!jid_string.has_prefix("xmpp:")) continue; // silk does this wrong
+ Jid? jid = null;
+ try {
+ jid = new Jid(jid_string.substring(4));
+ } catch (Error e) {
+ continue;
+ }
+ string user_state = user_node.get_attribute("state");
+ if (conference_state == "full" && user_state != "full") return null;
+
+ if (user_state == "deleted") {
+ conference_info.users.unset(jid);
+ continue;
+ }
+
+ ConferenceUser user = new ConferenceUser();
+ user.jid = jid;
+ user.display_text = user_node.get_deep_string_content(NS_RFC + ":display-text");
+
+ Gee.List<StanzaNode> endpoint_nodes = user_node.get_subnodes("endpoint");
+ foreach (StanzaNode entpoint_node in endpoint_nodes) {
+ Gee.List<StanzaNode> media_nodes = entpoint_node.get_subnodes("media");
+ foreach (StanzaNode media_node in media_nodes) {
+ string? id = media_node.get_attribute("id");
+ string? ty = media_node.get_deep_string_content(NS_RFC + ":type");
+ string? src_id_str = media_node.get_deep_string_content(NS_RFC + ":src-id");
+
+ if (id == null) continue;
+
+ ConferenceMedia media = new ConferenceMedia();
+ media.id = id;
+ media.src_id = src_id_str != null ? int.parse(src_id_str) : -1;
+ media.ty = ty;
+ user.medias[id] = media;
+ }
+
+ conference_info.users[user.jid] = user;
+ }
+ }
+ return conference_info;
+ }
+
+ public class ConferenceInfo {
+ public int version = -1;
+ public HashMap<Jid, ConferenceUser> users = new HashMap<Jid, ConferenceUser>(Jid.hash_func, Jid.equals_func);
+
+ public StanzaNode to_xml() {
+ StanzaNode ret = new StanzaNode.build("conference-info", NS_RFC).add_self_xmlns()
+ .put_attribute("version", this.version.to_string())
+ .put_attribute("state", "full");
+ StanzaNode users_node = new StanzaNode.build("users", NS_RFC);
+
+ foreach (ConferenceUser user in this.users.values) {
+ users_node.put_node(user.to_xml());
+ }
+ ret.put_node(users_node);
+ return ret;
+ }
+ }
+
+ public class ConferenceUser {
+ public Jid jid;
+ public string? display_text;
+ public HashMap<string, ConferenceMedia> medias = new HashMap<string, ConferenceMedia>();
+
+ public StanzaNode to_xml() {
+ StanzaNode user_node = new StanzaNode.build("user", NS_RFC)
+ .put_attribute("entity", jid.to_string());
+ foreach (ConferenceMedia media in medias.values) {
+ user_node.put_node(media.to_xml());
+ }
+ return user_node;
+ }
+ }
+
+ public class ConferenceMedia {
+ public string id;
+ public string? ty;
+ public int src_id = -1;
+
+ public StanzaNode to_xml() {
+ StanzaNode media_node = new StanzaNode.build("media", NS_RFC)
+ .put_attribute("id", id);
+ if (ty != null) {
+ media_node.put_node(new StanzaNode.build("type", NS_RFC).put_node(new StanzaNode.text(ty)));
+ }
+ if (src_id != -1) {
+ media_node.put_node(new StanzaNode.build("src-id", NS_RFC).put_node(new StanzaNode.text(src_id.to_string())));
+ }
+ return media_node;
+ }
+ }
+} \ No newline at end of file