diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt index 7f936fc2..68c4f356 100644 --- a/xmpp-vala/CMakeLists.txt +++ b/xmpp-vala/CMakeLists.txt @@ -34,6 +34,7 @@ SOURCES "src/module/tls.vala" "src/module/util.vala" + "src/module/xep/0004_data_forms.vala" "src/module/xep/0030_service_discovery/flag.vala" "src/module/xep/0030_service_discovery/identity.vala" "src/module/xep/0030_service_discovery/info_result.vala" diff --git a/xmpp-vala/src/core/stanza_node.vala b/xmpp-vala/src/core/stanza_node.vala index fd44c925..026b8ddb 100644 --- a/xmpp-vala/src/core/stanza_node.vala +++ b/xmpp-vala/src/core/stanza_node.vala @@ -45,8 +45,8 @@ public abstract class StanzaEntry { } public class StanzaNode : StanzaEntry { - public ArrayList sub_nodes = new ArrayList(); - public ArrayList attributes = new ArrayList(); + public Gee.List sub_nodes = new ArrayList(); + public Gee.List attributes = new ArrayList(); public bool has_nodes = false; public bool pseudo = false; @@ -129,7 +129,7 @@ public class StanzaNode : StanzaEntry { return null; } - public ArrayList get_attributes_by_ns_uri(string ns_uri) { + public Gee.List get_attributes_by_ns_uri(string ns_uri) { ArrayList ret = new ArrayList (); foreach (var attr in attributes) { if (attr.ns_uri == ns_uri) ret.add(attr); @@ -181,7 +181,7 @@ public class StanzaNode : StanzaEntry { return null; } - public ArrayList get_subnodes(string name, string? ns_uri = null, bool recurse = false) { + public Gee.List get_subnodes(string name, string? ns_uri = null, bool recurse = false) { ArrayList ret = new ArrayList(); string _name = name; string? _ns_uri = ns_uri; @@ -220,12 +220,12 @@ public class StanzaNode : StanzaEntry { return node; } - public ArrayList get_deep_subnodes(...) { + public Gee.List get_deep_subnodes(...) { va_list l = va_list(); return get_deep_subnodes_(va_list.copy(l)); } - public ArrayList get_deep_subnodes_(va_list l) { + public Gee.List get_deep_subnodes_(va_list l) { StanzaNode node = this; string? subnode_name = l.arg(); if (subnode_name == null) return new ArrayList(); @@ -240,11 +240,11 @@ public class StanzaNode : StanzaEntry { return node.get_subnodes((!)subnode_name); } - public ArrayList get_all_subnodes() { + public Gee.List get_all_subnodes() { return sub_nodes; } - public ArrayList get_deep_all_subnodes(...) { + public Gee.List get_deep_all_subnodes(...) { va_list l = va_list(); StanzaNode? node = get_deep_subnode_(va_list.copy(l)); if (node != null) return ((!)node).get_all_subnodes(); diff --git a/xmpp-vala/src/core/stanza_reader.vala b/xmpp-vala/src/core/stanza_reader.vala index f1ce5c19..dd284fa6 100644 --- a/xmpp-vala/src/core/stanza_reader.vala +++ b/xmpp-vala/src/core/stanza_reader.vala @@ -230,13 +230,13 @@ public class StanzaReader { skip_single(); if (desc.contains(":")) { var split = desc.split(":"); - assert(split[0] == ns_state.find_name((!)res.ns_uri)); - assert(split[1] == res.name); + if (split[0] != ns_state.find_name((!)res.ns_uri)) throw new XmlError.BAD_XML(""); + if (split[1] != res.name) throw new XmlError.BAD_XML(""); } else { - assert(ns_state.current_ns_uri == res.ns_uri); - assert(desc == res.name); + if (ns_state.current_ns_uri != res.ns_uri) throw new XmlError.BAD_XML(""); + if (desc != res.name) throw new XmlError.BAD_XML(""); } - return res; + finishNodeSeen = true; } else { res.sub_nodes.add(read_stanza_node(ns_state.clone())); ns_state = baseNs ?? new NamespaceState.for_stanza(); @@ -245,6 +245,7 @@ public class StanzaReader { res.sub_nodes.add(read_text_node()); } } while (!finishNodeSeen); + if (res.sub_nodes.size == 0) res.has_nodes = false; } return res; } 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 responseListeners = new HashMap(); private HashMap> namespaceRegistrants = new HashMap>(); - [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 children = node.get_all_subnodes(); + Gee.List children = node.get_all_subnodes(); if (children.size == 1 && namespaceRegistrants.has_key(children[0].ns_uri)) { - ArrayList handlers = namespaceRegistrants[children[0].ns_uri]; + Gee.List 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 subnodes = error_node.sub_nodes; + Gee.List 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 subnodes = node.sub_nodes; + Gee.List 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 fields = new ArrayList(); + + 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 get_values() { + Gee.List ret = new ArrayList(); + Gee.List 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 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