summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill Thompson <will.thompson@collabora.co.uk>2010-04-26 11:36:05 +0100
committerWill Thompson <will.thompson@collabora.co.uk>2010-04-26 11:36:07 +0100
commitdcbf0e1d5e36db7e9615fb653679cbb678b628de (patch)
tree26931cdff8fc72b872ab98e56aca070a4f4d74d7
parent0f2d10e0d236b97355d92f1fc9e826eb17db828b (diff)
parentb18261e0a9f79cad7f29df55bc99b92969dbfc26 (diff)
downloadtelepathy-gabble-dcbf0e1d5e36db7e9615fb653679cbb678b628de.tar.gz
Merge branch 'device-idle' into telepathy-gabble-0.8
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
-rw-r--r--configure.ac8
-rw-r--r--src/Makefile.am6
-rw-r--r--src/conn-slacker.c126
-rw-r--r--src/conn-slacker.h36
-rw-r--r--src/connection.c3
-rw-r--r--src/connection.h4
-rw-r--r--src/debug.h1
-rw-r--r--src/namespaces.h1
-rw-r--r--src/slacker.c298
-rw-r--r--src/slacker.h60
-rw-r--r--tests/twisted/Makefile.am8
-rw-r--r--tests/twisted/device-idleness.py91
-rw-r--r--tests/twisted/ns.py1
13 files changed, 643 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 710903c9e..d4ab9f888 100644
--- a/configure.ac
+++ b/configure.ac
@@ -237,6 +237,14 @@ else
AC_MSG_WARN([libuuid not found, falling back to generating random IDs])
fi
+dnl Check for MCE, a Maemo service used by Gabble to determine when the device
+dnl is idle.
+PKG_CHECK_MODULES([MCE], mce >= 1.5, [HAVE_MCE=yes], [HAVE_MCE=no])
+AM_CONDITIONAL([HAVE_MCE], [test x"$HAVE_MCE" = xyes])
+if test x"$HAVE_MCE" = xyes; then
+ AC_DEFINE([HAVE_MCE], [1], [Define if mce is available])
+fi
+
AC_CHECK_FUNCS(getifaddrs memset select strndup setresuid setreuid strerror)
SHAVE_INIT(.)
diff --git a/src/Makefile.am b/src/Makefile.am
index 5a81d3268..e0633fda9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,6 +7,8 @@ BUILT_SOURCES = \
CLEANFILES = $(BUILT_SOURCES)
+EXTRA_DIST =
+
libexec_PROGRAMS=telepathy-gabble
noinst_PROGRAMS = write-mgr-file
@@ -43,6 +45,8 @@ libgabble_convenience_la_SOURCES = \
conn-olpc.c \
conn-presence.h \
conn-presence.c \
+ conn-slacker.h \
+ conn-slacker.c \
connection.h \
connection.c \
connection-manager.h \
@@ -126,6 +130,8 @@ libgabble_convenience_la_SOURCES = \
roomlist-channel.c \
roomlist-manager.h \
roomlist-manager.c \
+ slacker.h \
+ slacker.c \
tube-iface.h \
tube-iface.c \
tubes-channel.h \
diff --git a/src/conn-slacker.c b/src/conn-slacker.c
new file mode 100644
index 000000000..fe17ece35
--- /dev/null
+++ b/src/conn-slacker.c
@@ -0,0 +1,126 @@
+/*
+ * conn-slacker.h - Header for Gabble connection code handling device idleness
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "conn-slacker.h"
+
+#define DEBUG_FLAG GABBLE_DEBUG_CONNECTION
+#include "debug.h"
+#include "namespaces.h"
+#include "util.h"
+
+static void
+conn_slacker_send_command (
+ GabbleConnection *conn,
+ const gchar *command)
+{
+ LmMessage *stanza = lm_message_build_with_sub_type (NULL,
+ LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET,
+ '(', "query", "",
+ '@', "xmlns", NS_GOOGLE_QUEUE,
+ '(', command, "", ')',
+ ')',
+ NULL);
+
+ _gabble_connection_send_with_reply (conn, stanza, NULL, NULL, NULL, NULL);
+ lm_message_unref (stanza);
+}
+
+
+static void
+conn_slacker_update_inactivity (
+ GabbleConnection *conn,
+ gboolean is_inactive)
+{
+ if (DEBUGGING)
+ {
+ gchar *jid = gabble_connection_get_full_jid (conn);
+
+ DEBUG ("device became %sactive; %sabling presence queueing for %s",
+ is_inactive ? "in" : "",
+ is_inactive ? "en" : "dis",
+ jid);
+ g_free (jid);
+ }
+
+ if (is_inactive)
+ {
+ conn_slacker_send_command (conn, "enable");
+ }
+ else
+ {
+ /* It seems that disabling the queue doesn't flush it, so we need to
+ * explicitly flush it too.
+ */
+ conn_slacker_send_command (conn, "disable");
+ conn_slacker_send_command (conn, "flush");
+ }
+}
+
+static void
+conn_slacker_inactivity_changed_cb (
+ GabbleSlacker *slacker,
+ gboolean is_inactive,
+ gpointer user_data)
+{
+ GabbleConnection *conn = GABBLE_CONNECTION (user_data);
+
+ conn_slacker_update_inactivity (conn, is_inactive);
+}
+
+void
+gabble_connection_slacker_start (GabbleConnection *conn)
+{
+ GabbleSlacker *s;
+
+ /* We can only cork presence updates on Google Talk. Of course, the Google
+ * Talk server doesn't advertise support for google:queue. So let's use the
+ * roster again... */
+ if (!(conn->features & GABBLE_CONNECTION_FEATURES_GOOGLE_ROSTER))
+ return;
+
+ s = conn->slacker = gabble_slacker_new ();
+
+ /* In the unlikely event of having to use an escape slide... */
+ if (G_UNLIKELY (s == NULL))
+ return;
+
+ conn->slacker_inactivity_changed_id = g_signal_connect (s,
+ "inactivity-changed", (GCallback) conn_slacker_inactivity_changed_cb,
+ conn);
+
+ /* If we're already inactive, let's cork right away. (I guess the connection
+ * flaked out in the user's pocket?) */
+ if (gabble_slacker_is_inactive (s))
+ conn_slacker_update_inactivity (conn, TRUE);
+}
+
+void
+gabble_connection_slacker_stop (GabbleConnection *conn)
+{
+ if (conn->slacker != NULL)
+ {
+ g_signal_handler_disconnect (conn->slacker,
+ conn->slacker_inactivity_changed_id);
+ conn->slacker_inactivity_changed_id = 0;
+
+ g_object_unref (conn->slacker);
+ conn->slacker = NULL;
+ }
+}
diff --git a/src/conn-slacker.h b/src/conn-slacker.h
new file mode 100644
index 000000000..c38d6cfce
--- /dev/null
+++ b/src/conn-slacker.h
@@ -0,0 +1,36 @@
+/*
+ * conn-slacker.h - Header for Gabble connection code handling device idleness
+ * Copyright (C) 2010 Collabora Ltd.
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GABBLE_CONN_SLACKER_H
+#define GABBLE_CONN_SLACKER_H
+
+#include <glib.h>
+
+#include "connection.h"
+
+G_BEGIN_DECLS
+
+void gabble_connection_slacker_start (GabbleConnection *conn);
+void gabble_connection_slacker_stop (GabbleConnection *conn);
+
+G_END_DECLS
+
+#endif /* GABBLE_CONN_SLACKER_H */
+
diff --git a/src/connection.c b/src/connection.c
index 907884f25..84011ec1e 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -53,6 +53,7 @@
#include "conn-location.h"
#include "conn-presence.h"
#include "conn-olpc.h"
+#include "conn-slacker.h"
#include "debug.h"
#include "disco.h"
#include "media-channel.h"
@@ -624,6 +625,7 @@ base_connected_cb (TpBaseConnection *base_conn)
GabbleConnection *conn = GABBLE_CONNECTION (base_conn);
gabble_connection_connected_olpc (conn);
+ gabble_connection_slacker_start (conn);
}
static void
@@ -1546,6 +1548,7 @@ connection_shut_down (TpBaseConnection *base)
g_assert (GABBLE_IS_CONNECTION (conn));
cancel_connect_timeout (conn);
+ gabble_connection_slacker_stop (conn);
/* If we're shutting down by user request, we don't want to be
* unreffed until the LM connection actually closes; the event handler
diff --git a/src/connection.h b/src/connection.h
index b2a47d0d0..ba4ecce69 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -34,6 +34,7 @@
#include "jingle-factory.h"
#include "muc-factory.h"
#include "olpc-gadget-manager.h"
+#include "slacker.h"
#include "types.h"
G_BEGIN_DECLS
@@ -173,6 +174,9 @@ struct _GabbleConnection {
GPtrArray *channel_requests;
gboolean has_tried_connection;
+ GabbleSlacker *slacker;
+ guint slacker_inactivity_changed_id;
+
GabbleConnectionPrivate *priv;
};
diff --git a/src/debug.h b/src/debug.h
index f19b7ea54..4d39a63f2 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -30,6 +30,7 @@ typedef enum
GABBLE_DEBUG_BYTESTREAM = 1 << 16,
GABBLE_DEBUG_LOCATION = 1 << 17,
GABBLE_DEBUG_FT = 1 << 18,
+ GABBLE_DEBUG_SLACKER = 1 << 19,
} GabbleDebugFlags;
void gabble_debug_set_flags_from_env (void);
diff --git a/src/namespaces.h b/src/namespaces.h
index fdf9ad8ab..5219b1e20 100644
--- a/src/namespaces.h
+++ b/src/namespaces.h
@@ -36,6 +36,7 @@
#define NS_GOOGLE_FEAT_VIDEO "http://www.google.com/xmpp/protocol/video/v1"
#define NS_GOOGLE_JINGLE_INFO "google:jingleinfo"
#define NS_GOOGLE_ROSTER "google:roster"
+#define NS_GOOGLE_QUEUE "google:queue"
#define NS_IBB "http://jabber.org/protocol/ibb"
/* Namespaces for XEP-0166 draft v0.15, the most capable Jingle dialect
diff --git a/src/slacker.c b/src/slacker.c
new file mode 100644
index 000000000..253f1842f
--- /dev/null
+++ b/src/slacker.c
@@ -0,0 +1,298 @@
+/*
+ * slacker.c - Maemo device state monitor
+ * Copyright ©2010 Collabora Ltd.
+ * Copyright ©2008-2010 Nokia Corporation
+ *
+ * Derived from code in e-book-backend-tp.c in eds-backend-telepathy; thanks!
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "slacker.h"
+#include "config.h"
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#ifdef HAVE_MCE
+#include <mce/dbus-names.h>
+#else /* HAVE_MCE */
+
+/* Use some dummy interfaces etc. for the test suite.
+ *
+ * In a perfect world of sweetness and light these would not be enabled for the
+ * real build, but we do not live in a perfect world of sweetness and light: we
+ * live below a dark cloud of bitter ash, the charred remains of a defunct
+ * economy and cygnine clothing.
+ */
+#define MCE_SERVICE "org.freedesktop.Telepathy.Gabble.Tests.MCE"
+
+#define MCE_SIGNAL_IF "org.freedesktop.Telepathy.Gabble.Tests.MCE"
+#define MCE_INACTIVITY_SIG "InactivityChanged"
+
+#define MCE_REQUEST_IF "org.freedesktop.Telepathy.Gabble.Tests.MCE"
+#define MCE_REQUEST_PATH "/org/freedesktop/Telepathy/Gabble/Tests/MCE"
+#define MCE_INACTIVITY_STATUS_GET "GetInactivity"
+
+#endif /* HAVE_MCE */
+
+#define DEBUG_FLAG GABBLE_DEBUG_SLACKER
+#include "debug.h"
+#include "gabble-signals-marshal.h"
+
+struct _GabbleSlackerPrivate {
+ DBusGConnection *bus;
+ DBusGProxy *mce_request_proxy;
+
+ gboolean is_inactive;
+};
+
+G_DEFINE_TYPE (GabbleSlacker, gabble_slacker, G_TYPE_OBJECT)
+
+enum {
+ SIG_INACTIVITY_CHANGED = 0,
+ N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+/**
+ * gabble_slacker_is_inactive:
+ * @self: do some work!
+ *
+ * <!-- -->
+ *
+ * Returns: %TRUE if the device is known to be inactive; false otherwise.
+ */
+gboolean
+gabble_slacker_is_inactive (GabbleSlacker *self)
+{
+ g_return_val_if_fail (GABBLE_IS_SLACKER (self), FALSE);
+
+ return self->priv->is_inactive;
+}
+
+static void
+slacker_inactivity_changed (
+ GabbleSlacker *self,
+ gboolean is_inactive)
+{
+ GabbleSlackerPrivate *priv = self->priv;
+ gboolean old = priv->is_inactive;
+
+ priv->is_inactive = is_inactive;
+
+ if (!!old != !!is_inactive)
+ {
+ DEBUG ("device became %s", (is_inactive ? "inactive" : "active"));
+ g_signal_emit (self, signals[SIG_INACTIVITY_CHANGED], 0, is_inactive);
+ }
+}
+
+static GQuark mce_signal_interface_quark = 0;
+static GQuark mce_inactivity_signal_quark = 0;
+
+#define INACTIVITY_MATCH_RULE \
+ "type='signal',interface='" MCE_SIGNAL_IF "',member='" MCE_INACTIVITY_SIG "'"
+
+static DBusHandlerResult
+slacker_message_filter (
+ DBusConnection *connection,
+ DBusMessage *message,
+ gpointer user_data)
+{
+ GabbleSlacker *self = GABBLE_SLACKER (user_data);
+ GQuark interface, member;
+ int message_type;
+
+ interface = g_quark_try_string (dbus_message_get_interface (message));
+ member = g_quark_try_string (dbus_message_get_member (message));
+ message_type = dbus_message_get_type (message);
+
+ if (interface == mce_signal_interface_quark &&
+ message_type == DBUS_MESSAGE_TYPE_SIGNAL &&
+ member == mce_inactivity_signal_quark)
+ {
+ gboolean is_inactive;
+
+ dbus_message_get_args (message, NULL, DBUS_TYPE_BOOLEAN, &is_inactive,
+ DBUS_TYPE_INVALID);
+ slacker_inactivity_changed (self, is_inactive);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+get_inactivity_status_cb (
+ DBusGProxy *proxy,
+ DBusGProxyCall *call,
+ gpointer user_data)
+{
+ GabbleSlacker *self = GABBLE_SLACKER (user_data);
+ gboolean is_inactive;
+
+ if (dbus_g_proxy_end_call (proxy, call, NULL /* ignore errors */,
+ G_TYPE_BOOLEAN, &is_inactive,
+ G_TYPE_INVALID))
+ slacker_inactivity_changed (self, is_inactive);
+
+ g_object_unref (self->priv->mce_request_proxy);
+ self->priv->mce_request_proxy = NULL;
+}
+
+static void
+slacker_add_filter (GabbleSlacker *self)
+{
+ GabbleSlackerPrivate *priv = self->priv;
+ DBusConnection *c = dbus_g_connection_get_connection (self->priv->bus);
+
+ dbus_connection_add_filter (c, slacker_message_filter, self, NULL);
+ dbus_bus_add_match (c, INACTIVITY_MATCH_RULE, NULL);
+
+ priv->mce_request_proxy = dbus_g_proxy_new_for_name (priv->bus,
+ MCE_SERVICE, MCE_REQUEST_PATH, MCE_REQUEST_IF);
+ dbus_g_proxy_begin_call (priv->mce_request_proxy, MCE_INACTIVITY_STATUS_GET,
+ get_inactivity_status_cb, self, NULL, G_TYPE_INVALID);
+}
+
+static void
+slacker_remove_filter (GabbleSlacker *self)
+{
+ DBusConnection *c = dbus_g_connection_get_connection (self->priv->bus);
+
+ dbus_connection_remove_filter (c, slacker_message_filter, self);
+ dbus_bus_remove_match (c, INACTIVITY_MATCH_RULE, NULL);
+}
+
+/* GObject boilerplate */
+
+static void
+gabble_slacker_init (GabbleSlacker *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GABBLE_TYPE_SLACKER,
+ GabbleSlackerPrivate);
+}
+
+static gpointer slacker = NULL;
+
+static GObject *
+gabble_slacker_constructor (
+ GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *retval;
+
+ if (slacker == NULL)
+ {
+ slacker = G_OBJECT_CLASS (gabble_slacker_parent_class)->constructor (
+ type, n_construct_properties, construct_properties);
+ retval = slacker;
+ g_object_add_weak_pointer (retval, &slacker);
+ }
+ else
+ {
+ retval = g_object_ref (slacker);
+ }
+
+ return retval;
+}
+
+static void
+gabble_slacker_constructed (GObject *object)
+{
+ GabbleSlacker *self = GABBLE_SLACKER (object);
+ GError *error = NULL;
+
+#ifdef HAVE_MCE
+ self->priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+#else
+ self->priv->bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+#endif
+
+ if (self->priv->bus == NULL)
+ {
+ g_warning ("help! where did my system bus go? %s", error->message);
+ g_clear_error (&error);
+ }
+ else
+ {
+ slacker_add_filter (self);
+ }
+}
+
+static void
+gabble_slacker_dispose (GObject *object)
+{
+ GabbleSlacker *self = GABBLE_SLACKER (object);
+ GabbleSlackerPrivate *priv = self->priv;
+
+ if (priv->mce_request_proxy != NULL)
+ {
+ g_object_unref (priv->mce_request_proxy); /* this cancels pending calls */
+ priv->mce_request_proxy = NULL;
+ }
+
+ if (priv->bus != NULL)
+ {
+ slacker_remove_filter (self);
+ dbus_g_connection_unref (priv->bus);
+ priv->bus = NULL;
+ }
+
+ ((GObjectClass *) gabble_slacker_parent_class)->dispose (object);
+}
+
+static void
+gabble_slacker_class_init (GabbleSlackerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = gabble_slacker_constructor;
+ object_class->constructed = gabble_slacker_constructed;
+ object_class->dispose = gabble_slacker_dispose;
+
+ g_type_class_add_private (klass, sizeof (GabbleSlackerPrivate));
+
+ /**
+ * GabbleSlacker::inactivity-changed:
+ * @self: what a slacker
+ * @inactive: %TRUE if the device is inactive.
+ *
+ * The ::inactivity-changed is emitted whenever MCE declares that the device
+ * has become active or inactive. Note that there is a lag (of around 30
+ * seconds, at the time of writing) between the screen blanking and MCE
+ * declaring the device inactive.
+ */
+ signals[SIG_INACTIVITY_CHANGED] = g_signal_new ("inactivity-changed",
+ GABBLE_TYPE_SLACKER, G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+ gabble_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+ if (!mce_signal_interface_quark)
+ {
+ mce_signal_interface_quark = g_quark_from_static_string (MCE_SIGNAL_IF);
+ mce_inactivity_signal_quark = g_quark_from_static_string (
+ MCE_INACTIVITY_SIG);
+ }
+}
+
+GabbleSlacker *
+gabble_slacker_new ()
+{
+ return g_object_new (GABBLE_TYPE_SLACKER, NULL);
+}
diff --git a/src/slacker.h b/src/slacker.h
new file mode 100644
index 000000000..fc57fe4ca
--- /dev/null
+++ b/src/slacker.h
@@ -0,0 +1,60 @@
+/*
+ * slacker.h - header for Maemo device state monitor
+ * Copyright ©2010 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GABBLE_SLACKER_H
+#define GABBLE_SLACKER_H
+
+#include <glib-object.h>
+
+typedef struct _GabbleSlacker GabbleSlacker;
+typedef struct _GabbleSlackerClass GabbleSlackerClass;
+typedef struct _GabbleSlackerPrivate GabbleSlackerPrivate;
+
+struct _GabbleSlackerClass {
+ GObjectClass parent_class;
+};
+
+struct _GabbleSlacker {
+ GObject parent;
+
+ GabbleSlackerPrivate *priv;
+};
+
+GType gabble_slacker_get_type (void);
+
+GabbleSlacker *gabble_slacker_new (void);
+gboolean gabble_slacker_is_inactive (GabbleSlacker *self);
+
+/* TYPE MACROS */
+#define GABBLE_TYPE_SLACKER \
+ (gabble_slacker_get_type ())
+#define GABBLE_SLACKER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_SLACKER, GabbleSlacker))
+#define GABBLE_SLACKER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_SLACKER,\
+ GabbleSlackerClass))
+#define GABBLE_IS_SLACKER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_SLACKER))
+#define GABBLE_IS_SLACKER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_SLACKER))
+#define GABBLE_SLACKER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_SLACKER, \
+ GabbleSlackerClass))
+
+#endif /* GABBLE_SLACKER_H */
diff --git a/tests/twisted/Makefile.am b/tests/twisted/Makefile.am
index f497a9a03..c899b2e2e 100644
--- a/tests/twisted/Makefile.am
+++ b/tests/twisted/Makefile.am
@@ -15,6 +15,7 @@ TWISTED_TESTS = \
caps/receive-jingle.py \
caps/trust-thyself.py \
caps/tube-caps.py \
+ device-idleness.py \
muc/name-conflict.py \
muc/renamed.py \
muc/roomlist.py \
@@ -192,12 +193,19 @@ else
ENABLE_ASSUMED_FT_CAP_PYBOOL = False
endif
+if HAVE_MCE
+HAVE_MCE_PYBOOL = True
+else
+HAVE_MCE_PYBOOL = False
+endif
+
config.py: Makefile
$(QUIET_GEN) { \
echo "PACKAGE_STRING = \"$(PACKAGE_STRING)\""; \
echo "CLIENT_TYPE = '$(CLIENT_TYPE)'"; \
echo "DEBUGGING = $(DEBUGGING_PYBOOL)"; \
echo "ENABLE_ASSUMED_FT_CAP = $(ENABLE_ASSUMED_FT_CAP_PYBOOL)"; \
+ echo "HAVE_MCE = $(HAVE_MCE_PYBOOL)"; \
} > $@
BUILT_SOURCES = config.py
diff --git a/tests/twisted/device-idleness.py b/tests/twisted/device-idleness.py
new file mode 100644
index 000000000..48e9e1069
--- /dev/null
+++ b/tests/twisted/device-idleness.py
@@ -0,0 +1,91 @@
+"""
+Test listening to device idleness status changes.
+
+When we're not building with MCE support, Gabble uses a test suite-specific
+service on the session bus. When we *are* building with MCE support, it uses
+the system bus, so we can't test it. Hence:
+"""
+
+import config
+
+if config.HAVE_MCE:
+ print "NOTE: built with real MCE support; skipping idleness test"
+ raise SystemExit(77)
+
+from functools import partial
+
+from gabbletest import exec_test, GoogleXmlStream
+from servicetest import call_async, Event, assertEquals
+import ns
+
+import dbus
+import dbus.service
+
+# Fake MCE constants, cloned from slacker.c
+MCE_SERVICE = "org.freedesktop.Telepathy.Gabble.Tests.MCE"
+
+MCE_SIGNAL_IF = "org.freedesktop.Telepathy.Gabble.Tests.MCE"
+MCE_INACTIVITY_SIG = "InactivityChanged"
+
+MCE_REQUEST_IF = "org.freedesktop.Telepathy.Gabble.Tests.MCE"
+MCE_REQUEST_PATH = "/org/freedesktop/Telepathy/Gabble/Tests/MCE"
+MCE_INACTIVITY_STATUS_GET = "GetInactivity"
+
+from twisted.internet import reactor
+
+class FakeMCE(dbus.service.Object):
+ def __init__(self, q, bus, inactive=False):
+ super(FakeMCE, self).__init__(bus, MCE_REQUEST_PATH)
+
+ self.q = q
+ self.inactive = inactive
+
+ @dbus.service.method(dbus_interface=MCE_REQUEST_IF,
+ in_signature='', out_signature='b')
+ def GetInactivity(self):
+ self.q.append(Event('get-inactivity-called'))
+ return self.inactive
+
+ @dbus.service.signal(dbus_interface=MCE_SIGNAL_IF, signature='b')
+ def InactivityChanged(self, new_value):
+ self.inactive = new_value
+
+
+def expect_command(q, name):
+ event = q.expect('stream-iq', query_name='query', query_ns=ns.GOOGLE_QUEUE)
+ command = event.query.firstChildElement()
+ assertEquals(name, command.name)
+
+def test(q, bus, conn, stream, initially_inactive=False):
+ mce = FakeMCE(q, bus, initially_inactive)
+
+ call_async(q, conn, 'Connect')
+ q.expect('get-inactivity-called')
+
+ if initially_inactive:
+ expect_command(q, 'enable')
+ else:
+ mce.InactivityChanged(True)
+ expect_command(q, 'enable')
+
+ mce.InactivityChanged(False)
+ expect_command(q, 'disable')
+ expect_command(q, 'flush')
+
+ # Just cycle it a bit to check it doesn't blow up slowly
+ mce.InactivityChanged(True)
+ expect_command(q, 'enable')
+
+ mce.InactivityChanged(False)
+ expect_command(q, 'disable')
+ expect_command(q, 'flush')
+
+ mce.remove_from_connection()
+
+if __name__ == '__main__':
+ dbus.SessionBus().request_name(MCE_SERVICE, 0)
+ try:
+ exec_test(partial(test, initially_inactive=False), protocol=GoogleXmlStream)
+ exec_test(partial(test, initially_inactive=True), protocol=GoogleXmlStream)
+ finally:
+ dbus.SessionBus().release_name(MCE_SERVICE)
diff --git a/tests/twisted/ns.py b/tests/twisted/ns.py
index 6d800360c..a36ebb198 100644
--- a/tests/twisted/ns.py
+++ b/tests/twisted/ns.py
@@ -12,6 +12,7 @@ GOOGLE_FEAT_VOICE = 'http://www.google.com/xmpp/protocol/voice/v1'
GOOGLE_FEAT_VIDEO = 'http://www.google.com/xmpp/protocol/video/v1'
GOOGLE_JINGLE_INFO = 'google:jingleinfo'
GOOGLE_P2P = "http://www.google.com/transport/p2p"
+GOOGLE_QUEUE = 'google:queue'
GOOGLE_ROSTER = 'google:roster'
GOOGLE_SESSION = "http://www.google.com/session"
GOOGLE_SESSION_PHONE = "http://www.google.com/session/phone"