aboutsummaryrefslogtreecommitdiff
path: root/xmpp-vala/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'xmpp-vala/src/core')
-rw-r--r--xmpp-vala/src/core/stanza_attribute.vala8
-rw-r--r--xmpp-vala/src/core/stanza_node.vala65
-rw-r--r--xmpp-vala/src/core/xmpp_stream.vala147
3 files changed, 199 insertions, 21 deletions
diff --git a/xmpp-vala/src/core/stanza_attribute.vala b/xmpp-vala/src/core/stanza_attribute.vala
index 3169e90e..e6887f33 100644
--- a/xmpp-vala/src/core/stanza_attribute.vala
+++ b/xmpp-vala/src/core/stanza_attribute.vala
@@ -17,6 +17,14 @@ public class StanzaAttribute : StanzaEntry {
}
}
+ public string to_ansi_string(bool hide_ns = false) {
+ if (ns_uri == null || hide_ns) {
+ return @"$name=$ANSI_COLOR_GREEN'$val'$ANSI_COLOR_END";
+ } else {
+ return @"$ANSI_COLOR_GRAY{$ns_uri}:$ANSI_COLOR_END$name=$ANSI_COLOR_GREEN'$val'$ANSI_COLOR_END";
+ }
+ }
+
public string to_xml(NamespaceState? state_) throws XmlError {
NamespaceState state = state_ ?? new NamespaceState();
if (ns_uri == state.current_ns_uri || (ns_uri == XMLNS_URI && name == "xmlns")) {
diff --git a/xmpp-vala/src/core/stanza_node.vala b/xmpp-vala/src/core/stanza_node.vala
index aff1770d..d9398a39 100644
--- a/xmpp-vala/src/core/stanza_node.vala
+++ b/xmpp-vala/src/core/stanza_node.vala
@@ -3,6 +3,11 @@ using Gee;
namespace Xmpp.Core {
public abstract class StanzaEntry {
+ protected const string ANSI_COLOR_END = "\x1b[0m";
+ protected const string ANSI_COLOR_GREEN = "\x1b[32m";
+ protected const string ANSI_COLOR_YELLOW = "\x1b[33m";
+ protected const string ANSI_COLOR_GRAY = "\x1b[37m";
+
public string? ns_uri;
public string name;
public string? val;
@@ -46,7 +51,8 @@ public class StanzaNode : StanzaEntry {
public bool has_nodes = false;
public bool pseudo = false;
- public StanzaNode () {}
+ public StanzaNode() {
+ }
public StanzaNode.build(string name, string ns_uri = "jabber:client", ArrayList<StanzaNode>? nodes = null, ArrayList<StanzaAttribute>? attrs = null) {
this.ns_uri = ns_uri;
@@ -81,7 +87,7 @@ public class StanzaNode : StanzaEntry {
_ns_uri = this.ns_uri;
}
}
- foreach(var attr in attributes) {
+ foreach (var attr in attributes) {
if (attr.ns_uri == _ns_uri && attr.name == _name) return attr.val;
}
return null;
@@ -93,6 +99,12 @@ public class StanzaNode : StanzaEntry {
return int.parse(res);
}
+ public uint get_attribute_uint(string name, uint def = 0, string? ns_uri = null) {
+ string? res = get_attribute(name, ns_uri);
+ if (res == null) return def;
+ return (uint) long.parse(res);
+ }
+
public bool get_attribute_bool(string name, bool def = false, string? ns_uri = null) {
string? res = get_attribute(name, ns_uri);
if (res == null) return def;
@@ -111,7 +123,7 @@ public class StanzaNode : StanzaEntry {
_ns_uri = this.ns_uri;
}
}
- foreach(var attr in attributes) {
+ foreach (var attr in attributes) {
if (attr.ns_uri == _ns_uri && attr.name == _name) return attr;
}
return null;
@@ -119,7 +131,7 @@ public class StanzaNode : StanzaEntry {
public ArrayList<StanzaAttribute> get_attributes_by_ns_uri(string ns_uri) {
ArrayList<StanzaAttribute> ret = new ArrayList<StanzaAttribute> ();
- foreach(var attr in attributes) {
+ foreach (var attr in attributes) {
if (attr.ns_uri == ns_uri) ret.add(attr);
}
return ret;
@@ -145,7 +157,7 @@ public class StanzaNode : StanzaEntry {
StanzaNode? node = this;
string? attribute_name = l.arg();
if (attribute_name == null) return null;
- while(true) {
+ while (true) {
string? s = l.arg();
if (s == null) break;
node = node.get_subnode(attribute_name);
@@ -167,7 +179,7 @@ public class StanzaNode : StanzaEntry {
_ns_uri = this.ns_uri;
}
}
- foreach(var node in sub_nodes) {
+ foreach (var node in sub_nodes) {
if (node.ns_uri == _ns_uri && node.name == _name) return node;
if (recurse) {
var x = node.get_subnode(_name, _ns_uri, recurse);
@@ -190,7 +202,7 @@ public class StanzaNode : StanzaEntry {
_ns_uri = this.ns_uri;
}
}
- foreach(var node in sub_nodes) {
+ foreach (var node in sub_nodes) {
if (node.ns_uri == _ns_uri && node.name == _name) ret.add(node);
if (recurse) {
ret.add_all(node.get_subnodes(_name, _ns_uri, recurse));
@@ -206,7 +218,7 @@ public class StanzaNode : StanzaEntry {
public StanzaNode? get_deep_subnode_(va_list l) {
StanzaNode? node = this;
- while(true) {
+ while (true) {
string? s = l.arg();
if (s == null) break;
node = node.get_subnode(s);
@@ -226,7 +238,7 @@ public class StanzaNode : StanzaEntry {
StanzaNode? node = this;
string? subnode_name = l.arg();
if (subnode_name == null) return new ArrayList<StanzaNode>();
- while(true) {
+ while (true) {
string? s = l.arg();
if (s == null) break;
node = node.get_subnode(subnode_name);
@@ -276,7 +288,7 @@ public class StanzaNode : StanzaEntry {
**/
public void set_attribute(string name, string val, string? ns_uri = null) {
if (ns_uri == null) ns_uri = this.ns_uri;
- foreach(var attr in attributes) {
+ foreach (var attr in attributes) {
if (attr.ns_uri == ns_uri && attr.name == name) {
attr.val = val;
return;
@@ -314,10 +326,38 @@ public class StanzaNode : StanzaEntry {
return sb.str;
}
- public string to_xml (NamespaceState? state = null) throws XmlError {
+ public string to_ansi_string(bool hide_ns = false, int i = 0) {
+ string indent = string.nfill (i * 2, ' ');
+ if (name == "#text") {
+ return @"$indent$val\n";
+ }
+ var sb = new StringBuilder();
+ sb.append(@"$indent$ANSI_COLOR_YELLOW<");
+ if (!hide_ns) sb.append(@"$ANSI_COLOR_GRAY{$ns_uri}:$ANSI_COLOR_YELLOW");
+ sb.append(@"$name$ANSI_COLOR_END");
+ foreach (StanzaAttribute attr in attributes) {
+ sb.append_printf(" %s", attr.to_ansi_string(hide_ns));
+ }
+ if (!has_nodes && sub_nodes.size == 0) {
+ sb.append(@" $ANSI_COLOR_YELLOW/>$ANSI_COLOR_END\n");
+ } else {
+ sb.append(@"$ANSI_COLOR_YELLOW>$ANSI_COLOR_END\n");
+ if (sub_nodes.size != 0) {
+ foreach (StanzaNode subnode in sub_nodes) {
+ sb.append(subnode.to_ansi_string(hide_ns, i + 1));
+ }
+ sb.append(@"$indent$ANSI_COLOR_YELLOW</");
+ if (!hide_ns) sb.append(@"$ANSI_COLOR_GRAY{$ns_uri}:$ANSI_COLOR_YELLOW");
+ sb.append(@"$name>$ANSI_COLOR_END\n");
+ }
+ }
+ return sb.str;
+ }
+
+ public string to_xml(NamespaceState? state = null) throws XmlError {
NamespaceState my_state = state ?? new NamespaceState.for_stanza();
if (name == "#text") return @"$encoded_val";
- foreach(var xmlns in get_attributes_by_ns_uri (XMLNS_URI)) {
+ foreach (var xmlns in get_attributes_by_ns_uri (XMLNS_URI)) {
if (xmlns.name == "xmlns") {
my_state = new NamespaceState.with_current(my_state, xmlns.val);
} else {
@@ -352,4 +392,5 @@ public class StanzaNode : StanzaEntry {
return sb.str;
}
}
+
}
diff --git a/xmpp-vala/src/core/xmpp_stream.vala b/xmpp-vala/src/core/xmpp_stream.vala
index 0283920b..684c7ed0 100644
--- a/xmpp-vala/src/core/xmpp_stream.vala
+++ b/xmpp-vala/src/core/xmpp_stream.vala
@@ -10,11 +10,133 @@ public errordomain IOStreamError {
}
+public class XmppLog {
+ protected const string ANSI_COLOR_END = "\x1b[0m";
+ protected const string ANSI_COLOR_WHITE = "\x1b[37;1m";
+
+ class NodeLogDesc {
+ public string? name;
+ private string? ns_uri;
+ private string? val;
+ private Map<string, string?> attrs = new HashMap<string, string?>();
+ private NodeLogDesc? inner;
+
+ public NodeLogDesc(string desc) {
+ string d = desc;
+
+ if (d.contains("[")) {
+ int start = d.index_of("[");
+ int end = d.index_of("]");
+ string attrs = d.substring(start + 1, end - start - 1);
+ d = d.substring(0, start) + d.substring(end + 1);
+ foreach (string attr in attrs.split(",")) {
+ if (attr.contains("=")) {
+ string key = attr.substring(0, attr.index_of("="));
+ string val = attr.substring(attr.index_of("=") + 1);
+ this.attrs[key] = val;
+ } else {
+ this.attrs[attr] = null;
+ }
+ }
+ }
+ if (d.contains(":") && d.index_of("{") == 0 && d.index_of("}") != -1) {
+ int end = d.index_of("}");
+ this.ns_uri = d.substring(1, end - 2);
+ d = d.substring(end + 2);
+ }
+ if (d.contains(".")) {
+ inner = new NodeLogDesc(d.substring(d.index_of(".") + 1));
+ d = d.substring(0, d.index_of("."));
+ } else if (d.contains("=")) {
+ this.val = d.substring(d.index_of("="));
+ d = d.substring(0, d.index_of("="));
+ }
+
+ if (d != "") this.name = d;
+ }
+
+ public bool matches(StanzaNode node) {
+ if (name != null && node.name != name) return false;
+ if (ns_uri != null && node.ns_uri != ns_uri) return false;
+ if (val != null && node.val != val) return false;
+ foreach (var pair in attrs.entries) {
+ if (pair.value == null && node.get_attribute(pair.key) == null) return false;
+ else if (pair.value != null && pair.value != node.get_attribute(pair.key)) return false;
+ }
+ if (inner == null) return true;
+ foreach (StanzaNode snode in node.get_all_subnodes()) {
+ if (inner.matches(snode)) return true;
+ }
+ return false;
+ }
+ }
+
+ private bool use_ansi;
+ private bool hide_ns = true;
+ private string ident;
+ private string desc;
+ private ArrayList<NodeLogDesc> descs = new ArrayList<NodeLogDesc>();
+
+ public XmppLog(string? ident = null, string? desc = null) {
+ this.ident = ident;
+ this.desc = desc;
+ this.use_ansi = is_atty(stderr.fileno());
+ while (this.desc != null && this.desc.contains(";")) {
+ string opt = this.desc.substring(0, this.desc.index_of(";"));
+ this.desc = this.desc.substring(opt.length + 1);
+ switch (opt) {
+ case "ansi": use_ansi = true; break;
+ case "no-ansi": use_ansi = false; break;
+ case "hide-ns": hide_ns = true; break;
+ case "show-ns": hide_ns = false; break;
+ }
+ }
+ if (desc != null) {
+ foreach (string d in this.desc.split("|")) {
+ descs.add(new NodeLogDesc(d));
+ }
+ }
+ }
+
+ public virtual bool should_log_node(StanzaNode node) {
+ if (ident == null || desc == null) return false;
+ if (desc == "all") return true;
+ foreach (var desc in descs) {
+ if (desc.matches(node)) return true;
+ }
+ return false;
+ }
+
+ public virtual bool should_log_str(string str) {
+ if (ident == null || desc == null) return false;
+ if (desc == "all") return true;
+ foreach (var desc in descs) {
+ if (desc.name == "#text") return true;
+ }
+ return false;
+ }
+
+ public void node(string what, StanzaNode node) {
+ if (should_log_node(node)) {
+ stderr.printf("%sXMPP %s [%s]%s\n%s\n", ANSI_COLOR_WHITE, what, ident, ANSI_COLOR_END, use_ansi ? node.to_ansi_string(hide_ns) : node.to_string());
+ }
+ }
+
+ public void str(string what, string str) {
+ if (should_log_str(str)) {
+ stderr.printf("%sXMPP %s [%s]%s\n%s\n", ANSI_COLOR_WHITE, what, ident, ANSI_COLOR_END, str);
+ }
+ }
+
+ [CCode (cname = "isatty")]
+ private static extern bool is_atty(int fd);
+}
+
public class XmppStream {
private static string NS_URI = "http://etherx.jabber.org/streams";
public string remote_name;
- public bool debug = false;
+ public XmppLog log = new XmppLog();
public StanzaNode? features { get; private set; default = new StanzaNode.build("features", NS_URI); }
private IOStream? stream;
@@ -51,7 +173,7 @@ public class XmppStream {
public void disconnect() throws IOStreamError {
if (writer == null) throw new IOStreamError.DISCONNECT("trying to disconnect, but no stream open");
- if (debug) stderr.puts("OUT\n</stream:stream>\n");
+ log.str("OUT", "</stream:stream>");
writer.write.begin("</stream:stream>");
reader.cancel();
stream.close_async.begin();
@@ -75,8 +197,8 @@ public class XmppStream {
public StanzaNode read() throws IOStreamError {
if (reader == null) throw new IOStreamError.READ("trying to read, but no stream open");
try {
- var node = reader.read_node();
- if (debug) stderr.printf("IN\n%s\n", node.to_string());
+ StanzaNode node = reader.read_node();
+ log.node("IN", node);
return node;
} catch (XmlError e) {
throw new IOStreamError.READ(e.message);
@@ -86,7 +208,7 @@ public class XmppStream {
public void write(StanzaNode node) throws IOStreamError {
if (writer == null) throw new IOStreamError.WRITE("trying to write, but no stream open");
try {
- if (debug) stderr.printf("OUT\n%s\n", node.to_string());
+ log.node("OUT", node);
writer.write_node(node);
} catch (XmlError e) {
throw new IOStreamError.WRITE(e.message);
@@ -138,18 +260,19 @@ public class XmppStream {
}
private void setup() throws IOStreamError {
- var outs = new StanzaNode.build("stream", "http://etherx.jabber.org/streams")
+ StanzaNode outs = new StanzaNode.build("stream", "http://etherx.jabber.org/streams")
.put_attribute("to", remote_name)
.put_attribute("version", "1.0")
.put_attribute("xmlns", "jabber:client")
.put_attribute("stream", "http://etherx.jabber.org/streams", XMLNS_URI);
outs.has_nodes = true;
+ log.node("OUT ROOT", outs);
write(outs);
received_root_node(this, read_root());
}
private void loop() throws IOStreamError {
- while(true) {
+ while (true) {
if (setup_needed) {
setup();
setup_needed = false;
@@ -219,8 +342,8 @@ public class XmppStream {
private StanzaNode read_root() throws IOStreamError {
try {
- var node = reader.read_root_node();
- if (debug) stderr.printf("IN\n%s\n", node.to_string());
+ StanzaNode node = reader.read_root_node();
+ log.node("IN ROOT", node);
return node;
} catch (XmlError e) {
throw new IOStreamError.READ(e.message);
@@ -248,6 +371,7 @@ public class FlagIdentity<T> : Object {
public abstract class XmppStreamFlag : Object {
public abstract string get_ns();
+
public abstract string get_id();
}
@@ -271,13 +395,18 @@ public class ModuleIdentity<T> : Object {
public abstract class XmppStreamModule : Object {
public abstract void attach(XmppStream stream);
+
public abstract void detach(XmppStream stream);
+
public abstract string get_ns();
+
public abstract string get_id();
}
public abstract class XmppStreamNegotiationModule : XmppStreamModule {
public abstract bool mandatory_outstanding(XmppStream stream);
+
public abstract bool negotiation_active(XmppStream stream);
}
+
}