summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Scherer <misc@mandriva.org>2011-06-27 18:41:35 +0100
committerWill Thompson <will.thompson@collabora.co.uk>2011-06-27 18:45:13 +0100
commit12ea43016a73e853a1a6ad8227f2a6f109474abf (patch)
treea8a0b4753d11c64edce87a7944bb71a5e217ff40
parent901577fd23a6e7f7e639be6c8d8b086a3531a091 (diff)
Support XEP-0012: Last Activity
Patch largely rewritten by Will, since Gabble has changed a lot in the two years since he rejected it on (in retrospect, shaky and unnecessarily hostile) grounds. Fixes: <https://bugs.freedesktop.org/show_bug.cgi?id=11688> Signed-off-by: Will Thompson <will.thompson@collabora.co.uk>
-rw-r--r--src/connection.c59
-rw-r--r--src/connection.h1
-rw-r--r--src/message-util.c1
-rw-r--r--src/namespaces.h1
-rw-r--r--tests/twisted/Makefile.am1
-rw-r--r--tests/twisted/last-activity.py49
-rw-r--r--tests/twisted/ns.py1
7 files changed, 113 insertions, 0 deletions
diff --git a/src/connection.c b/src/connection.c
index 4af976728..dcbe52312 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -22,6 +22,7 @@
#include "connection.h"
#include "gabble.h"
+#include <stdio.h>
#include <string.h>
#define DBUS_API_SUBJECT_TO_CHANGE
@@ -236,6 +237,10 @@ struct _GabbleConnectionPrivate
/* serial number of current advertised caps */
guint caps_serial;
+ /* Last activity time for XEP-0012 purposes, where "activity" is defined to
+ * mean "sending a message".
+ */
+ time_t last_activity_time;
/* capabilities from various sources: */
/* subscriptions on behalf of the Connection, like PEP "+notify"
@@ -518,6 +523,7 @@ gabble_connection_init (GabbleConnection *self)
self->lmconn = lm_connection_new ();
priv->caps_serial = 1;
+ priv->last_activity_time = time (NULL);
priv->port = 5222;
gabble_capabilities_init (self);
@@ -1379,6 +1385,18 @@ _gabble_connection_send (GabbleConnection *conn, LmMessage *msg, GError **error)
return TRUE;
}
+void
+gabble_connection_update_last_use (GabbleConnection *conn)
+{
+ conn->priv->last_activity_time = time (NULL);
+}
+
+static gdouble
+gabble_connection_get_last_use (GabbleConnection *conn)
+{
+ return difftime (time (NULL), conn->priv->last_activity_time);
+}
+
typedef struct {
GabbleConnectionMsgReplyFunc reply_func;
@@ -1970,6 +1988,41 @@ connector_register_cb (GObject *source,
g_free (jid);
}
+static gboolean
+connection_iq_last_cb (
+ WockyPorter *porter,
+ WockyStanza *stanza,
+ gpointer user_data)
+{
+ GabbleConnection *self = GABBLE_CONNECTION (user_data);
+ const gchar *from = wocky_stanza_get_from (stanza);
+ /* Aside from 21 being an appropriate number, 2 ^ 64 is 20 digits long. */
+ char seconds[21];
+
+ /* Check if the peer, if any, is authorized to receive our presence. */
+ if (from != NULL)
+ {
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+ (TpBaseConnection *) self, TP_HANDLE_TYPE_CONTACT);
+ TpHandle handle = tp_handle_lookup (contact_repo, from, NULL, NULL);
+
+ /* If there's no handle for them, they're certainly not on the roster. */
+ if (handle == 0 ||
+ !gabble_roster_handle_gets_presence_from_us (self->roster, handle))
+ {
+ wocky_porter_send_iq_error (porter, stanza,
+ WOCKY_XMPP_ERROR_FORBIDDEN, NULL);
+ return TRUE;
+ }
+ }
+
+ sprintf (seconds, "%.0f", gabble_connection_get_last_use (self));
+ wocky_porter_acknowledge_iq (porter, stanza,
+ '(', "query", ':', NS_LAST, '@', "seconds", seconds, ')',
+ NULL);
+ return TRUE;
+}
+
static void
connect_iq_callbacks (GabbleConnection *conn)
{
@@ -1987,6 +2040,12 @@ connect_iq_callbacks (GabbleConnection *conn)
iq_version_cb, conn,
'(', "query", ':', NS_VERSION, ')', NULL);
+ wocky_porter_register_handler_from_anyone (priv->porter,
+ WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_GET,
+ WOCKY_PORTER_HANDLER_PRIORITY_NORMAL,
+ connection_iq_last_cb, conn,
+ '(', "query", ':', NS_LAST, ')', NULL);
+
/* FIXME: the porter should do this for us. */
wocky_porter_register_handler_from_anyone (priv->porter,
WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_NONE,
diff --git a/src/connection.h b/src/connection.h
index 2b425e926..109f2d4fb 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -218,6 +218,7 @@ void _gabble_connection_acknowledge_set_iq (GabbleConnection *conn,
LmMessage *iq);
void _gabble_connection_send_iq_error (GabbleConnection *conn,
LmMessage *message, GabbleXmppError error, const gchar *errmsg);
+void gabble_connection_update_last_use (GabbleConnection *conn);
const char *_gabble_connection_find_conference_server (GabbleConnection *);
gchar *gabble_connection_get_canonical_room_name (GabbleConnection *conn,
diff --git a/src/message-util.c b/src/message-util.c
index 1e7f2a003..c0f5a6938 100644
--- a/src/message-util.c
+++ b/src/message-util.c
@@ -180,6 +180,7 @@ gabble_message_util_build_stanza (TpMessage *message,
else
g_free (id);
+ gabble_connection_update_last_use (conn);
return stanza;
}
diff --git a/src/namespaces.h b/src/namespaces.h
index 08b00c6b4..d39853dbd 100644
--- a/src/namespaces.h
+++ b/src/namespaces.h
@@ -84,6 +84,7 @@
/* Jingle ICE-UDP transport */
#define NS_JINGLE_TRANSPORT_ICEUDP "urn:xmpp:jingle:transports:ice-udp:1"
+#define NS_LAST "jabber:iq:last"
#define NS_MUC "http://jabber.org/protocol/muc"
#define NS_MUC_BYTESTREAM "http://telepathy.freedesktop.org/xmpp/protocol/muc-bytestream"
#define NS_MUC_USER "http://jabber.org/protocol/muc#user"
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index 0603d6ac8..3bb3a241d 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -20,6 +20,7 @@ TWISTED_TESTS = \
client-types.py \
cm/protocol.py \
gateways.py \
+ last-activity.py \
muc/avatars.py \
muc/banned.py \
muc/conference.py \
diff --git a/tests/twisted/last-activity.py b/tests/twisted/last-activity.py
new file mode 100644
index 000000000..fd3da5a36
--- /dev/null
+++ b/tests/twisted/last-activity.py
@@ -0,0 +1,49 @@
+"""
+Trivial smoke-test for XEP-0012 support.
+"""
+from servicetest import assertEquals, assertContains
+from gabbletest import exec_test, elem, elem_iq
+import ns
+
+def test(q, bus, conn, stream):
+ e = q.expect('stream-iq', iq_type='get', query_ns=ns.ROSTER)
+ e.stanza['type'] = 'result'
+ e.query.addChild(
+ elem('item', jid='romeo@montague.lit', subscription='both'))
+ stream.send(e.stanza)
+
+ # Romeo's on the roster.
+ stream.send(
+ elem_iq(stream, 'get', from_='romeo@montague.lit')(
+ elem(ns.LAST, 'query')
+ )
+ )
+ e = q.expect('stream-iq', iq_type='result',
+ query_ns=ns.LAST, query_name='query')
+ # No real assertions about the number of seconds; this is just a smoke
+ # test.
+ seconds = e.query['seconds']
+ assert seconds >= 0
+
+ # Juliet is not.
+ stream.send(
+ elem_iq(stream, 'get', from_='juliet@capulet.lit')(
+ elem(ns.LAST, 'query')
+ )
+ )
+ e = q.expect('stream-iq', iq_type='error',
+ query_ns=ns.LAST, query_name='query')
+ # Yuck.
+ assertEquals('forbidden', e.stanza.children[1].children[0].name)
+
+ # If the server asks, Gabble had better not crash.
+ stream.send(
+ elem_iq(stream, 'get')(
+ elem(ns.LAST, 'query')
+ )
+ )
+ e = q.expect('stream-iq', iq_type='result',
+ query_ns=ns.LAST, query_name='query')
+
+if __name__ == '__main__':
+ exec_test(test)
diff --git a/tests/twisted/ns.py b/tests/twisted/ns.py
index 66d2ecb55..629f5b418 100644
--- a/tests/twisted/ns.py
+++ b/tests/twisted/ns.py
@@ -32,6 +32,7 @@ JINGLE_RTP_ERRORS = "urn:xmpp:jingle:apps:rtp:errors:1"
JINGLE_RTP_INFO_1 = "urn:xmpp:jingle:apps:rtp:info:1"
JINGLE_TRANSPORT_ICEUDP = "urn:xmpp:jingle:transports:ice-udp:1"
JINGLE_TRANSPORT_RAWUDP = "urn:xmpp:jingle:transports:raw-udp:1"
+LAST = "jabber:iq:last"
MUC = 'http://jabber.org/protocol/muc'
MUC_BYTESTREAM = 'http://telepathy.freedesktop.org/xmpp/protocol/muc-bytestream'
MUC_OWNER = '%s#owner' % MUC