Add initial COIN (XEP-0298) implementation to xmpp-vala

This commit is contained in:
fiaxh 2021-11-04 17:11:33 +01:00
parent 37c543b6e7
commit 54427b04f9

View file

@ -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;
}
}
}