Add --print-xmpp flag to log details
This commit is contained in:
parent
8248cfcbb2
commit
2a49d4a1aa
|
@ -8,16 +8,18 @@ public class Dino.Application : Gtk.Application {
|
||||||
public StreamInteractor stream_interaction;
|
public StreamInteractor stream_interaction;
|
||||||
public Plugins.Registry plugin_registry = new Plugins.Registry();
|
public Plugins.Registry plugin_registry = new Plugins.Registry();
|
||||||
|
|
||||||
|
static string print_xmpp;
|
||||||
|
|
||||||
|
private const OptionEntry[] options = {
|
||||||
|
{ "print-xmpp", 0, 0, OptionArg.STRING, ref print_xmpp, "Print XMPP stanzas identified by DESC to stderr", "DESC" },
|
||||||
|
{ null }
|
||||||
|
};
|
||||||
|
|
||||||
public Application() throws Error {
|
public Application() throws Error {
|
||||||
if (DirUtils.create_with_parents(get_storage_dir(), 0700) == -1) {
|
if (DirUtils.create_with_parents(get_storage_dir(), 0700) == -1) {
|
||||||
throw new Error(-1, 0, "Could not create storage dir \"%s\": %s", get_storage_dir(), FileUtils.error_from_errno(errno).to_string());
|
throw new Error(-1, 0, "Could not create storage dir \"%s\": %s", get_storage_dir(), FileUtils.error_from_errno(errno).to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Legacy import
|
|
||||||
if (FileUtils.test("store.sqlite3", FileTest.IS_REGULAR)) {
|
|
||||||
FileUtils.rename("store.sqlite3", Path.build_filename(get_storage_dir(), "dino.db"));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.db = new Database(Path.build_filename(get_storage_dir(), "dino.db"));
|
this.db = new Database(Path.build_filename(get_storage_dir(), "dino.db"));
|
||||||
this.stream_interaction = new StreamInteractor(db);
|
this.stream_interaction = new StreamInteractor(db);
|
||||||
|
|
||||||
|
@ -31,8 +33,10 @@ public class Dino.Application : Gtk.Application {
|
||||||
ChatInteraction.start(stream_interaction);
|
ChatInteraction.start(stream_interaction);
|
||||||
|
|
||||||
activate.connect(() => {
|
activate.connect(() => {
|
||||||
|
stream_interaction.connection_manager.log_options = print_xmpp;
|
||||||
restore();
|
restore();
|
||||||
});
|
});
|
||||||
|
add_main_option_entries(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string get_storage_dir() {
|
public static string get_storage_dir() {
|
||||||
|
|
|
@ -21,6 +21,7 @@ public class ConnectionManager {
|
||||||
private NetworkManager? network_manager;
|
private NetworkManager? network_manager;
|
||||||
private Login1Manager? login1;
|
private Login1Manager? login1;
|
||||||
private ModuleManager module_manager;
|
private ModuleManager module_manager;
|
||||||
|
public string? log_options;
|
||||||
|
|
||||||
private class Connection {
|
private class Connection {
|
||||||
public Core.XmppStream stream { get; set; }
|
public Core.XmppStream stream { get; set; }
|
||||||
|
@ -92,7 +93,7 @@ public class ConnectionManager {
|
||||||
foreach (Core.XmppStreamModule module in module_manager.get_modules(account, resource)) {
|
foreach (Core.XmppStreamModule module in module_manager.get_modules(account, resource)) {
|
||||||
stream.add_module(module);
|
stream.add_module(module);
|
||||||
}
|
}
|
||||||
stream.debug = false;
|
stream.log = new Core.XmppLog(account.bare_jid.to_string(), log_options);
|
||||||
|
|
||||||
Connection connection = new Connection(stream, new DateTime.now_local());
|
Connection connection = new Connection(stream, new DateTime.now_local());
|
||||||
stream_states[account] = connection;
|
stream_states[account] = connection;
|
||||||
|
|
|
@ -10,11 +10,6 @@ public class Plugin : RootInterface, Object {
|
||||||
public AccountSettingsEntry settings_entry;
|
public AccountSettingsEntry settings_entry;
|
||||||
|
|
||||||
public void registered(Dino.Application app) {
|
public void registered(Dino.Application app) {
|
||||||
// FIXME: Legacy import
|
|
||||||
if (FileUtils.test("omemo.db", FileTest.IS_REGULAR)) {
|
|
||||||
FileUtils.rename("omemo.db", Path.build_filename(Application.get_storage_dir(), "omemo.db"));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context = new Signal.Context(DEBUG);
|
context = new Signal.Context(DEBUG);
|
||||||
this.app = app;
|
this.app = app;
|
||||||
|
|
|
@ -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 {
|
public string to_xml(NamespaceState? state_) throws XmlError {
|
||||||
NamespaceState state = state_ ?? new NamespaceState();
|
NamespaceState state = state_ ?? new NamespaceState();
|
||||||
if (ns_uri == state.current_ns_uri || (ns_uri == XMLNS_URI && name == "xmlns")) {
|
if (ns_uri == state.current_ns_uri || (ns_uri == XMLNS_URI && name == "xmlns")) {
|
||||||
|
|
|
@ -3,6 +3,11 @@ using Gee;
|
||||||
namespace Xmpp.Core {
|
namespace Xmpp.Core {
|
||||||
|
|
||||||
public abstract class StanzaEntry {
|
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? ns_uri;
|
||||||
public string name;
|
public string name;
|
||||||
public string? val;
|
public string? val;
|
||||||
|
@ -46,7 +51,8 @@ public class StanzaNode : StanzaEntry {
|
||||||
public bool has_nodes = false;
|
public bool has_nodes = false;
|
||||||
public bool pseudo = 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) {
|
public StanzaNode.build(string name, string ns_uri = "jabber:client", ArrayList<StanzaNode>? nodes = null, ArrayList<StanzaAttribute>? attrs = null) {
|
||||||
this.ns_uri = ns_uri;
|
this.ns_uri = ns_uri;
|
||||||
|
@ -93,6 +99,12 @@ public class StanzaNode : StanzaEntry {
|
||||||
return int.parse(res);
|
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) {
|
public bool get_attribute_bool(string name, bool def = false, string? ns_uri = null) {
|
||||||
string? res = get_attribute(name, ns_uri);
|
string? res = get_attribute(name, ns_uri);
|
||||||
if (res == null) return def;
|
if (res == null) return def;
|
||||||
|
@ -314,6 +326,34 @@ public class StanzaNode : StanzaEntry {
|
||||||
return sb.str;
|
return sb.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
public string to_xml(NamespaceState? state = null) throws XmlError {
|
||||||
NamespaceState my_state = state ?? new NamespaceState.for_stanza();
|
NamespaceState my_state = state ?? new NamespaceState.for_stanza();
|
||||||
if (name == "#text") return @"$encoded_val";
|
if (name == "#text") return @"$encoded_val";
|
||||||
|
@ -352,4 +392,5 @@ public class StanzaNode : StanzaEntry {
|
||||||
return sb.str;
|
return sb.str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
public class XmppStream {
|
||||||
private static string NS_URI = "http://etherx.jabber.org/streams";
|
private static string NS_URI = "http://etherx.jabber.org/streams";
|
||||||
|
|
||||||
public string remote_name;
|
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); }
|
public StanzaNode? features { get; private set; default = new StanzaNode.build("features", NS_URI); }
|
||||||
|
|
||||||
private IOStream? stream;
|
private IOStream? stream;
|
||||||
|
@ -51,7 +173,7 @@ public class XmppStream {
|
||||||
|
|
||||||
public void disconnect() throws IOStreamError {
|
public void disconnect() throws IOStreamError {
|
||||||
if (writer == null) throw new IOStreamError.DISCONNECT("trying to disconnect, but no stream open");
|
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>");
|
writer.write.begin("</stream:stream>");
|
||||||
reader.cancel();
|
reader.cancel();
|
||||||
stream.close_async.begin();
|
stream.close_async.begin();
|
||||||
|
@ -75,8 +197,8 @@ public class XmppStream {
|
||||||
public StanzaNode read() throws IOStreamError {
|
public StanzaNode read() throws IOStreamError {
|
||||||
if (reader == null) throw new IOStreamError.READ("trying to read, but no stream open");
|
if (reader == null) throw new IOStreamError.READ("trying to read, but no stream open");
|
||||||
try {
|
try {
|
||||||
var node = reader.read_node();
|
StanzaNode node = reader.read_node();
|
||||||
if (debug) stderr.printf("IN\n%s\n", node.to_string());
|
log.node("IN", node);
|
||||||
return node;
|
return node;
|
||||||
} catch (XmlError e) {
|
} catch (XmlError e) {
|
||||||
throw new IOStreamError.READ(e.message);
|
throw new IOStreamError.READ(e.message);
|
||||||
|
@ -86,7 +208,7 @@ public class XmppStream {
|
||||||
public void write(StanzaNode node) throws IOStreamError {
|
public void write(StanzaNode node) throws IOStreamError {
|
||||||
if (writer == null) throw new IOStreamError.WRITE("trying to write, but no stream open");
|
if (writer == null) throw new IOStreamError.WRITE("trying to write, but no stream open");
|
||||||
try {
|
try {
|
||||||
if (debug) stderr.printf("OUT\n%s\n", node.to_string());
|
log.node("OUT", node);
|
||||||
writer.write_node(node);
|
writer.write_node(node);
|
||||||
} catch (XmlError e) {
|
} catch (XmlError e) {
|
||||||
throw new IOStreamError.WRITE(e.message);
|
throw new IOStreamError.WRITE(e.message);
|
||||||
|
@ -138,12 +260,13 @@ public class XmppStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setup() throws IOStreamError {
|
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("to", remote_name)
|
||||||
.put_attribute("version", "1.0")
|
.put_attribute("version", "1.0")
|
||||||
.put_attribute("xmlns", "jabber:client")
|
.put_attribute("xmlns", "jabber:client")
|
||||||
.put_attribute("stream", "http://etherx.jabber.org/streams", XMLNS_URI);
|
.put_attribute("stream", "http://etherx.jabber.org/streams", XMLNS_URI);
|
||||||
outs.has_nodes = true;
|
outs.has_nodes = true;
|
||||||
|
log.node("OUT ROOT", outs);
|
||||||
write(outs);
|
write(outs);
|
||||||
received_root_node(this, read_root());
|
received_root_node(this, read_root());
|
||||||
}
|
}
|
||||||
|
@ -219,8 +342,8 @@ public class XmppStream {
|
||||||
|
|
||||||
private StanzaNode read_root() throws IOStreamError {
|
private StanzaNode read_root() throws IOStreamError {
|
||||||
try {
|
try {
|
||||||
var node = reader.read_root_node();
|
StanzaNode node = reader.read_root_node();
|
||||||
if (debug) stderr.printf("IN\n%s\n", node.to_string());
|
log.node("IN ROOT", node);
|
||||||
return node;
|
return node;
|
||||||
} catch (XmlError e) {
|
} catch (XmlError e) {
|
||||||
throw new IOStreamError.READ(e.message);
|
throw new IOStreamError.READ(e.message);
|
||||||
|
@ -248,6 +371,7 @@ public class FlagIdentity<T> : Object {
|
||||||
|
|
||||||
public abstract class XmppStreamFlag : Object {
|
public abstract class XmppStreamFlag : Object {
|
||||||
public abstract string get_ns();
|
public abstract string get_ns();
|
||||||
|
|
||||||
public abstract string get_id();
|
public abstract string get_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,13 +395,18 @@ public class ModuleIdentity<T> : Object {
|
||||||
|
|
||||||
public abstract class XmppStreamModule : Object {
|
public abstract class XmppStreamModule : Object {
|
||||||
public abstract void attach(XmppStream stream);
|
public abstract void attach(XmppStream stream);
|
||||||
|
|
||||||
public abstract void detach(XmppStream stream);
|
public abstract void detach(XmppStream stream);
|
||||||
|
|
||||||
public abstract string get_ns();
|
public abstract string get_ns();
|
||||||
|
|
||||||
public abstract string get_id();
|
public abstract string get_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class XmppStreamNegotiationModule : XmppStreamModule {
|
public abstract class XmppStreamNegotiationModule : XmppStreamModule {
|
||||||
public abstract bool mandatory_outstanding(XmppStream stream);
|
public abstract bool mandatory_outstanding(XmppStream stream);
|
||||||
|
|
||||||
public abstract bool negotiation_active(XmppStream stream);
|
public abstract bool negotiation_active(XmppStream stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using Gdk;
|
|
||||||
|
|
||||||
using Xmpp.Core;
|
using Xmpp.Core;
|
||||||
|
|
||||||
namespace Xmpp.Xep.MessageDeliveryReceipts {
|
namespace Xmpp.Xep.MessageDeliveryReceipts {
|
||||||
|
|
Loading…
Reference in a new issue