Add initial COIN (XEP-0298) implementation to xmpp-vala
This commit is contained in:
parent
37c543b6e7
commit
54427b04f9
136
xmpp-vala/src/module/xep/0298_coin.vala
Normal file
136
xmpp-vala/src/module/xep/0298_coin.vala
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue