diff options
Diffstat (limited to 'xmpp-vala/src/module')
-rw-r--r-- | xmpp-vala/src/module/iq/module.vala | 10 | ||||
-rw-r--r-- | xmpp-vala/src/module/stanza.vala | 2 | ||||
-rw-r--r-- | xmpp-vala/src/module/stanza_error.vala | 2 | ||||
-rw-r--r-- | xmpp-vala/src/module/stream_error.vala | 2 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0004_data_forms.vala | 208 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0045_muc/flag.vala | 10 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0045_muc/module.vala | 79 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0048_bookmarks/module.vala | 6 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0085_chat_state_notifications.vala | 2 | ||||
-rw-r--r-- | xmpp-vala/src/module/xep/0333_chat_markers.vala | 2 |
10 files changed, 307 insertions, 16 deletions
diff --git a/xmpp-vala/src/module/iq/module.vala b/xmpp-vala/src/module/iq/module.vala index eed3389d..909ec984 100644 --- a/xmpp-vala/src/module/iq/module.vala +++ b/xmpp-vala/src/module/iq/module.vala @@ -11,15 +11,15 @@ namespace Xmpp.Iq { private HashMap<string, ResponseListener> responseListeners = new HashMap<string, ResponseListener>(); private HashMap<string, ArrayList<Handler>> namespaceRegistrants = new HashMap<string, ArrayList<Handler>>(); - [CCode (has_target = false)] public delegate void OnResult(XmppStream stream, Iq.Stanza iq, Object reference); - public void send_iq(XmppStream stream, Iq.Stanza iq, OnResult? listener = null, Object? reference = null) { + [CCode (has_target = false)] public delegate void OnResult(XmppStream stream, Iq.Stanza iq, Object store); + public void send_iq(XmppStream stream, Iq.Stanza iq, OnResult? listener = null, Object? store = null) { try { stream.write(iq.stanza); } catch (IOStreamError e) { print(@"$(e.message)\n"); } if (listener != null) { - responseListeners[iq.id] = new ResponseListener(listener, reference); + responseListeners[iq.id] = new ResponseListener(listener, store); } } @@ -61,9 +61,9 @@ namespace Xmpp.Iq { responseListeners.unset(iq.id); } } else { - ArrayList<StanzaNode> children = node.get_all_subnodes(); + Gee.List<StanzaNode> children = node.get_all_subnodes(); if (children.size == 1 && namespaceRegistrants.has_key(children[0].ns_uri)) { - ArrayList<Handler> handlers = namespaceRegistrants[children[0].ns_uri]; + Gee.List<Handler> handlers = namespaceRegistrants[children[0].ns_uri]; foreach (Handler handler in handlers) { if (iq.type_ == Iq.Stanza.TYPE_GET) { handler.on_iq_get(stream, iq); diff --git a/xmpp-vala/src/module/stanza.vala b/xmpp-vala/src/module/stanza.vala index 85cbadb7..2bf3e29b 100644 --- a/xmpp-vala/src/module/stanza.vala +++ b/xmpp-vala/src/module/stanza.vala @@ -2,7 +2,7 @@ using Xmpp.Core; namespace Xmpp { - public class Stanza { + public class Stanza : Object { public const string ATTRIBUTE_FROM = "from"; public const string ATTRIBUTE_ID = "id"; diff --git a/xmpp-vala/src/module/stanza_error.vala b/xmpp-vala/src/module/stanza_error.vala index be4633e9..b34caeb0 100644 --- a/xmpp-vala/src/module/stanza_error.vala +++ b/xmpp-vala/src/module/stanza_error.vala @@ -40,7 +40,7 @@ namespace Xmpp { public string condition { get { - ArrayList<StanzaNode> subnodes = error_node.sub_nodes; + Gee.List<StanzaNode> subnodes = error_node.sub_nodes; foreach (StanzaNode subnode in subnodes) { // TODO get subnode by ns if (subnode.ns_uri == "urn:ietf:params:xml:ns:xmpp-stanzas") { return subnode.name; diff --git a/xmpp-vala/src/module/stream_error.vala b/xmpp-vala/src/module/stream_error.vala index bd292d2b..fa54d06f 100644 --- a/xmpp-vala/src/module/stream_error.vala +++ b/xmpp-vala/src/module/stream_error.vala @@ -32,7 +32,7 @@ namespace Xmpp.StreamError { private Flag generate_error_flag(StanzaNode node) { string? subnode_name = null; - ArrayList<StanzaNode> subnodes = node.sub_nodes; + Gee.List<StanzaNode> subnodes = node.sub_nodes; foreach (StanzaNode subnode in subnodes) { // TODO get subnode by ns if (subnode.ns_uri == "urn:ietf:params:xml:ns:xmpp-streams" && subnode.name != "text") { subnode_name = subnode.name; diff --git a/xmpp-vala/src/module/xep/0004_data_forms.vala b/xmpp-vala/src/module/xep/0004_data_forms.vala new file mode 100644 index 00000000..add2fa9a --- /dev/null +++ b/xmpp-vala/src/module/xep/0004_data_forms.vala @@ -0,0 +1,208 @@ +using Gee; + +using Xmpp.Core; + +namespace Xmpp.Xep.DataForms { + +public const string NS_URI = "jabber:x:data"; + +public class DataForm { + + public StanzaNode stanza_node { get; set; } + public Gee.List<Field> fields = new ArrayList<Field>(); + + public XmppStream stream; + public OnResult on_result; + public Object? store; + + public void cancel() { + StanzaNode stanza_node = new StanzaNode.build("x", NS_URI); + stanza_node.add_self_xmlns().set_attribute("type", "cancel"); + on_result(stream, stanza_node, store); + } + + public void submit() { + stanza_node.set_attribute("type", "submit"); + on_result(stream, stanza_node, store); + } + + public enum Type { + BOOLEAN, + FIXED, + HIDDEN, + JID_MULTI, + LIST_SINGLE, + LIST_MULTI, + TEXT_PRIVATE, + TEXT_SINGLE, + } + + public class Option { + public string label { get; set; } + public string value { get; set; } + + public Option(string label, string value) { + this.label = label; + this.value = value; + } + } + + public abstract class Field { + public string label { + get { return node.get_attribute("label", NS_URI); } + set { node.set_attribute("label", value); } + } + public StanzaNode node { get; set; } + public abstract Type type_ { get; internal set; } + public string var { + get { return node.get_attribute("var", NS_URI); } + set { node.set_attribute("var", value); } + } + + public Field(StanzaNode node) { + this.node = node; + } + + internal Gee.List<string> get_values() { + Gee.List<string> ret = new ArrayList<string>(); + Gee.List<StanzaNode> value_nodes = node.get_subnodes("value", NS_URI); + foreach (StanzaNode node in value_nodes) { + ret.add(node.get_string_content()); + } + return ret; + } + + internal string get_value_string() { + Gee.List<string> values = get_values(); + return values.size > 0 ? values[0] : ""; + } + + internal void set_value_string(string val) { + StanzaNode? value_node = node.get_subnode("value", NS_URI); + if (value_node == null) { + value_node = new StanzaNode.build("value", NS_URI); + node.put_node(value_node); + } + value_node.sub_nodes.clear(); + value_node.put_node(new StanzaNode.text(val)); + } + + internal void add_value_string(string val) { + StanzaNode node = new StanzaNode.build("value"); + node.put_node(new StanzaNode.text(val)); + } + + internal Gee.List<Option>? get_options() { + Gee.List<Option> ret = new ArrayList<Option>(); + Gee.List<StanzaNode> option_nodes = node.get_subnodes("option", NS_URI); + foreach (StanzaNode node in option_nodes) { + Option option = new Option(node.get_attribute("label", NS_URI), node.get_subnode("value").get_string_content()); + ret.add(option); + } + return ret; + } + } + + public class BooleanField : Field { + public override Type type_ { get; internal set; default=Type.BOOLEAN; } + public bool value { + get { return get_value_string() == "1"; } + set { set_value_string(value ? "1" : "0"); } + } + public BooleanField(StanzaNode node) { base(node); } + } + + public class FixedField : Field { + public override Type type_ { get; internal set; default=Type.FIXED; } + public string value { + owned get { return get_value_string(); } + set { set_value_string(value); } + } + public FixedField(StanzaNode node) { base(node); } + } + + public class HiddenField : Field { + public override Type type_ { get; internal set; default=Type.HIDDEN; } + public HiddenField(StanzaNode node) { base(node); } + } + + public class JidMultiField : Field { + public Gee.List<Option> options { owned get { return get_options(); } } + public override Type type_ { get; internal set; default=Type.JID_MULTI; } + public Gee.List<string> value { get; set; } + public JidMultiField(StanzaNode node) { base(node); } + } + + public class ListSingleField : Field { + public Gee.List<Option> options { owned get { return get_options(); } } + public override Type type_ { get; internal set; default=Type.LIST_SINGLE; } + public string value { + owned get { return get_value_string(); } + set { set_value_string(value); } + } + public ListSingleField(StanzaNode node) { base(node); } + } + + public class ListMultiField : Field { + public Gee.List<Option> options { owned get { return get_options(); } } + public override Type type_ { get; internal set; default=Type.LIST_MULTI; } + public Gee.List<string> value { get; set; } + public ListMultiField(StanzaNode node) { base(node); } + } + + public class TextPrivateField : Field { + public override Type type_ { get; internal set; default=Type.TEXT_PRIVATE; } + public string value { + owned get { return get_value_string(); } + set { set_value_string(value); } + } + public TextPrivateField(StanzaNode node) { base(node); } + } + + public class TextSingleField : Field { + public override Type type_ { get; internal set; default=Type.TEXT_SINGLE; } + public string value { + owned get { return get_value_string(); } + set { set_value_string(value); } + } + public TextSingleField(StanzaNode node) { base(node); } + } + + // TODO text-multi + + internal DataForm(StanzaNode node, XmppStream stream, OnResult on_result, Object? store) { + this.stanza_node = node; + this.stream = stream; + this.on_result = on_result; + this.store = store; + Gee.List<StanzaNode> field_nodes = node.get_subnodes("field", NS_URI); + foreach (StanzaNode field_node in field_nodes) { + string? type = field_node.get_attribute("type", NS_URI); + switch (type) { + case "boolean": + fields.add(new BooleanField(field_node)); break; + case "fixed": + fields.add(new FixedField(field_node)); break; + case "hidden": + fields.add(new HiddenField(field_node)); break; + case "jid-multi": + fields.add(new JidMultiField(field_node)); break; + case "list-single": + fields.add(new ListSingleField(field_node)); break; + case "list-multi": + fields.add(new ListMultiField(field_node)); break; + case "text-private": + fields.add(new TextPrivateField(field_node)); break; + case "text-single": + fields.add(new TextSingleField(field_node)); break; + } + } + } + + [CCode (has_target = false)] public delegate void OnResult(XmppStream stream, StanzaNode node, Object? store); + public static DataForm? create(XmppStream stream, StanzaNode node, OnResult on_result, Object? store) { + return new DataForm(node, stream, on_result, store); + } +} + +}
\ No newline at end of file diff --git a/xmpp-vala/src/module/xep/0045_muc/flag.vala b/xmpp-vala/src/module/xep/0045_muc/flag.vala index 159f0193..cf729bf9 100644 --- a/xmpp-vala/src/module/xep/0045_muc/flag.vala +++ b/xmpp-vala/src/module/xep/0045_muc/flag.vala @@ -7,6 +7,8 @@ namespace Xmpp.Xep.Muc { public class Flag : XmppStreamFlag { public static FlagIdentity<Flag> IDENTITY = new FlagIdentity<Flag>(NS_URI, "muc"); + private HashMap<string, Gee.List<Feature>> room_features = new HashMap<string, Gee.List<Feature>>(); + private HashMap<string, string> enter_ids = new HashMap<string, string>(); private HashMap<string, string> own_nicks = new HashMap<string, string>(); private HashMap<string, string> subjects = new HashMap<string, string>(); @@ -16,6 +18,10 @@ public class Flag : XmppStreamFlag { private HashMap<string, HashMap<string, Affiliation>> affiliations = new HashMap<string, HashMap<string, Affiliation>>(); private HashMap<string, Role> occupant_role = new HashMap<string, Role>(); + public bool has_room_feature(string jid, Feature feature) { + return room_features.has_key(jid) && room_features[jid].contains(feature); + } + public string? get_real_jid(string full_jid) { return occupant_real_jids[full_jid]; } public Gee.List<string> get_offline_members(string full_jid) { @@ -53,6 +59,10 @@ public class Flag : XmppStreamFlag { public string? get_muc_subject(string bare_jid) { return subjects[bare_jid]; } + internal void set_room_features(string jid, Gee.List<Feature> features) { + room_features[jid] = features; + } + internal void set_real_jid(string full_jid, string real_jid) { occupant_real_jids[full_jid] = real_jid; } internal void set_offline_member(string muc_jid, string real_jid, Affiliation affiliation) { diff --git a/xmpp-vala/src/module/xep/0045_muc/module.vala b/xmpp-vala/src/module/xep/0045_muc/module.vala index 9893f8a3..c098fd14 100644 --- a/xmpp-vala/src/module/xep/0045_muc/module.vala +++ b/xmpp-vala/src/module/xep/0045_muc/module.vala @@ -6,6 +6,7 @@ namespace Xmpp.Xep.Muc { private const string NS_URI = "http://jabber.org/protocol/muc"; private const string NS_URI_ADMIN = NS_URI + "#admin"; +private const string NS_URI_OWNER = NS_URI + "#owner"; private const string NS_URI_USER = NS_URI + "#user"; public enum MucEnterError { @@ -32,6 +33,25 @@ public enum Role { VISITOR } +public enum Feature { + REGISTER, + ROOMCONFIG, + ROOMINFO, + HIDDEN, + MEMBERS_ONLY, + MODERATED, + NON_ANONYMOUS, + OPEN, + PASSWORD_PROTECTED, + PERSISTENT, + PUBLIC, + ROOMS, + SEMI_ANONYMOUS, + TEMPORARY, + UNMODERATED, + UNSECURED +} + public class Module : XmppStreamModule { public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, "0045_muc_module"); @@ -56,6 +76,8 @@ public class Module : XmppStreamModule { presence.stanza.put_node(x_node); stream.get_flag(Flag.IDENTITY).start_muc_enter(bare_jid, presence.id); + + query_room_info(stream, bare_jid); stream.get_module(Presence.Module.IDENTITY).send_presence(stream, presence); } @@ -85,6 +107,19 @@ public class Module : XmppStreamModule { change_role(stream, jid, nick, "none"); } + [CCode (has_target = false)] public delegate void OnConfigFormResult(XmppStream stream, string jid, DataForms.DataForm data_form, Object? store); + public void get_config_form(XmppStream stream, string jid, OnConfigFormResult listener, Object? store) { + Iq.Stanza iq = new Iq.Stanza.get(new StanzaNode.build("query", NS_URI_OWNER).add_self_xmlns()) { to=jid }; + stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq, store) => { + Tuple<OnConfigFormResult, Object?> tuple = store as Tuple<OnConfigFormResult, Object?>; + StanzaNode? x_node = iq.stanza.get_deep_subnode(NS_URI_OWNER + ":query", DataForms.NS_URI + ":x"); + if (x_node != null) { + DataForms.DataForm data_form = DataForms.DataForm.create(stream, x_node, on_config_form_result, iq); + tuple.a(stream, iq.from, data_form, tuple.b); + } + }, Tuple.create(listener, store)); + } + public override void attach(XmppStream stream) { stream.add_flag(new Muc.Flag()); Message.Module.require(stream); @@ -225,8 +260,37 @@ public class Module : XmppStreamModule { } } - [CCode (has_target = false)] public delegate void OnResult(XmppStream stream, Gee.List<string> jids, Object? store); - private void query_affiliation(XmppStream stream, string jid, string affiliation, OnResult? on_result, Object? store) { + private void query_room_info(XmppStream stream, string jid) { + stream.get_module(ServiceDiscovery.Module.IDENTITY).request_info(stream, jid, (stream, query_result, store) => { + Gee.List<Feature> features = new ArrayList<Feature>(); + 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 "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(query_result.iq.from, features); + }, null); + } + + [CCode (has_target = false)] public delegate void OnAffiliationResult(XmppStream stream, Gee.List<string> jids, Object? store); + private void query_affiliation(XmppStream stream, string jid, string affiliation, OnAffiliationResult? on_result, Object? store) { Iq.Stanza iq = new Iq.Stanza.get( new StanzaNode.build("query", NS_URI_ADMIN) .add_self_xmlns() @@ -234,7 +298,7 @@ public class Module : XmppStreamModule { .put_attribute("affiliation", affiliation)) ) { to=jid }; stream.get_module(Iq.Module.IDENTITY).send_iq(stream, iq, (stream, iq, store) => { - Tuple<OnResult?, Object?> tuple = store as Tuple<OnResult?, Object?>; + Tuple<OnAffiliationResult?, Object?> tuple = store as Tuple<OnAffiliationResult?, Object?>; if (iq.is_error()) return; StanzaNode? query_node = iq.stanza.get_subnode("query", NS_URI_ADMIN); if (query_node == null) return; @@ -252,6 +316,15 @@ public class Module : XmppStreamModule { }, Tuple.create(on_result, store)); } + public static void on_config_form_result(XmppStream stream, StanzaNode node, Object? store) { + Iq.Stanza form_iq = store as Iq.Stanza; + StanzaNode stanza_node = new StanzaNode.build("query", NS_URI_OWNER); + stanza_node.add_self_xmlns().put_node(node); + Iq.Stanza set_iq = new Iq.Stanza.set(stanza_node); + set_iq.to = form_iq.from; + stream.get_module(Iq.Module.IDENTITY).send_iq(stream, set_iq); + } + private static ArrayList<int> get_status_codes(StanzaNode x_node) { ArrayList<int> ret = new ArrayList<int>(); foreach (StanzaNode status_node in x_node.get_subnodes("status", NS_URI_USER)) { diff --git a/xmpp-vala/src/module/xep/0048_bookmarks/module.vala b/xmpp-vala/src/module/xep/0048_bookmarks/module.vala index bf5bd612..f2030ff6 100644 --- a/xmpp-vala/src/module/xep/0048_bookmarks/module.vala +++ b/xmpp-vala/src/module/xep/0048_bookmarks/module.vala @@ -85,9 +85,9 @@ public class Module : XmppStreamModule { public override string get_ns() { return NS_URI; } public override string get_id() { return IDENTITY.id; } - private static ArrayList<Conference> get_conferences_from_stanza(StanzaNode node) { - ArrayList<Conference> conferences = new ArrayList<Conference>(); - ArrayList<StanzaNode> conferenceNodes = node.get_subnode("storage", NS_URI).get_subnodes("conference", NS_URI); + private static Gee.List<Conference> get_conferences_from_stanza(StanzaNode node) { + Gee.List<Conference> conferences = new ArrayList<Conference>(); + Gee.List<StanzaNode> conferenceNodes = node.get_subnode("storage", NS_URI).get_subnodes("conference", NS_URI); foreach (StanzaNode conferenceNode in conferenceNodes) { Conference? conference = Conference.create_from_stanza_node(conferenceNode); conferences.add(conference); diff --git a/xmpp-vala/src/module/xep/0085_chat_state_notifications.vala b/xmpp-vala/src/module/xep/0085_chat_state_notifications.vala index 6212cade..9b5ba075 100644 --- a/xmpp-vala/src/module/xep/0085_chat_state_notifications.vala +++ b/xmpp-vala/src/module/xep/0085_chat_state_notifications.vala @@ -56,7 +56,7 @@ public class Module : XmppStreamModule { private void on_received_message(XmppStream stream, Message.Stanza message) { if (!message.is_error()) { - ArrayList<StanzaNode> nodes = message.stanza.get_all_subnodes(); + Gee.List<StanzaNode> nodes = message.stanza.get_all_subnodes(); foreach (StanzaNode node in nodes) { if (node.ns_uri == NS_URI && node.name in STATES) { diff --git a/xmpp-vala/src/module/xep/0333_chat_markers.vala b/xmpp-vala/src/module/xep/0333_chat_markers.vala index 7ac70806..e6bab2c6 100644 --- a/xmpp-vala/src/module/xep/0333_chat_markers.vala +++ b/xmpp-vala/src/module/xep/0333_chat_markers.vala @@ -57,7 +57,7 @@ public class Module : XmppStreamModule { send_marker(stream, message.from, message.id, message.type_, MARKER_RECEIVED); return; } - ArrayList<StanzaNode> nodes = message.stanza.get_all_subnodes(); + Gee.List<StanzaNode> nodes = message.stanza.get_all_subnodes(); foreach (StanzaNode node in nodes) { if (node.ns_uri == NS_URI && node.name in MARKERS) { marker_received(stream, message.from, node.name, node.get_attribute("id", NS_URI)); |