1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
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 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;
}
}
}
|