summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/presence-cache.c19
-rw-r--r--tests/twisted/Makefile.am1
-rw-r--r--tests/twisted/presence/error.py71
3 files changed, 91 insertions, 0 deletions
diff --git a/src/presence-cache.c b/src/presence-cache.c
index bf5f87bf9..4b73104d3 100644
--- a/src/presence-cache.c
+++ b/src/presence-cache.c
@@ -43,6 +43,7 @@
#include <wocky/wocky-utils.h>
#include <wocky/wocky-namespaces.h>
#include <wocky/wocky-data-form.h>
+#include <wocky/wocky-xmpp-error-enumtypes.h>
#define DEBUG_FLAG GABBLE_DEBUG_PRESENCE
@@ -1837,11 +1838,29 @@ gabble_presence_parse_presence_message (
return TRUE;
case WOCKY_STANZA_SUB_TYPE_ERROR:
+ {
+ GError *error = NULL;
+ gboolean ret;
+
NODE_DEBUG (presence_node, "Received error presence");
+
+ ret = wocky_stanza_extract_errors (message, NULL, &error, NULL, NULL);
+ g_assert (ret);
+
+ /* If there's a <status/> in this presence, it's our own echoed back at
+ * us. So we don't want to use that. Instead, we use the <error><text> if
+ * there is any, or the name of the error condition if not. */
+ if (tp_str_empty (error->message))
+ status_message = wocky_enum_to_nick (WOCKY_TYPE_XMPP_ERROR,
+ error->code);
+ else
+ status_message = error->message;
+
gabble_presence_cache_update (cache, handle, resource,
GABBLE_PRESENCE_ERROR, status_message, priority);
return TRUE;
+ }
case WOCKY_STANZA_SUB_TYPE_UNAVAILABLE:
if (gabble_roster_handle_sends_presence_to_us (priv->conn->roster,
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 7c756ff28..03638bb6c 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -64,6 +64,7 @@ TWISTED_TESTS = \
plugin-channel-managers.py \
power-save.py \
presence/decloak.py \
+ presence/error.py \
presence/initial-contact-presence.py \
presence/initial-presence.py \
presence/invisible_xep_0126.py \
diff --git a/tests/twisted/presence/error.py b/tests/twisted/presence/error.py
new file mode 100644
index 000000000..53f3703bc
--- /dev/null
+++ b/tests/twisted/presence/error.py
@@ -0,0 +1,71 @@
+"""
+Tests that Gabble provides at least some useful information from error
+presences.
+"""
+
+from gabbletest import exec_test, make_presence, elem
+from servicetest import assertEquals
+import ns
+import constants as cs
+
+def test(q, bus, conn, stream):
+ jids = ['gregory@unreachable.example.com',
+ 'thehawk@unreachable.example.net',
+ ]
+ gregory, hawk = jids
+ gregory_handle, hawk_handle = conn.RequestHandles(cs.HT_CONTACT, jids)
+
+ event = q.expect('stream-iq', query_ns=ns.ROSTER)
+ event.stanza['type'] = 'result'
+ for jid in jids:
+ item = event.query.addElement('item')
+ item['jid'] = jid
+ item['subscription'] = 'both'
+
+ stream.send(event.stanza)
+ q.expect('dbus-signal', signal='PresencesChanged',
+ args=[{gregory_handle: (cs.PRESENCE_OFFLINE, 'offline', ''),
+ hawk_handle: (cs.PRESENCE_OFFLINE, 'offline', ''),
+ }
+ ])
+
+ # Our server can't resolve unreachable.example.com so it sends us an error
+ # presence for Gregory. (This is what Prosody actually does.)
+ presence = make_presence(gregory, type='error')
+ error_text = u'Connection failed: DNS resolution failed'
+ presence.addChild(
+ elem('error', type='cancel')(
+ elem(ns.STANZA, 'remote-server-not-found'),
+ elem(ns.STANZA, 'text')(
+ error_text
+ )
+ ))
+
+ stream.send(presence)
+
+ e = q.expect('dbus-signal', signal='PresencesChanged')
+ presences, = e.args
+ type_, status, message = presences[gregory_handle]
+ assertEquals(cs.PRESENCE_ERROR, type_)
+ assertEquals('error', status)
+ assertEquals(error_text, message)
+
+ # How about maybe the hawk's server is busted?
+ presence = make_presence(hawk, type='error')
+ presence.addChild(
+ elem('error', type='cancel')(
+ elem(ns.STANZA, 'internal-server-error'),
+ ))
+ stream.send(presence)
+
+ e = q.expect('dbus-signal', signal='PresencesChanged')
+ presences, = e.args
+ type_, status, message = presences[hawk_handle]
+ assertEquals(cs.PRESENCE_ERROR, type_)
+ assertEquals('error', status)
+ # FIXME: It might be less user-hostile to give some kind of readable
+ # description of the error in future.
+ assertEquals('internal-server-error', message)
+
+if __name__ == '__main__':
+ exec_test(test)