[Telepathy-commits] [telepathy-gabble/master] commit initial location interface implemenation

Dafydd Harries daf at rhydd.org
Sun Feb 1 05:23:54 PST 2009


---
 src/Makefile.am        |    2 +
 src/conn-location.c    |  237 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/conn-location.h    |   14 +++
 src/connection.c       |    5 +-
 tests/test-location.py |   46 +++++++++
 5 files changed, 303 insertions(+), 1 deletions(-)
 create mode 100644 src/conn-location.c
 create mode 100644 src/conn-location.h
 create mode 100644 tests/test-location.py

diff --git a/src/Makefile.am b/src/Makefile.am
index 619d9ee..b2549d9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,6 +33,8 @@ libgabble_convenience_la_SOURCES = \
     conn-aliasing.c \
     conn-avatars.h \
     conn-avatars.c \
+    conn-location.h \
+    conn-location.c \
     conn-olpc.h \
     conn-olpc.c \
     conn-presence.h \
diff --git a/src/conn-location.c b/src/conn-location.c
new file mode 100644
index 0000000..f962e65
--- /dev/null
+++ b/src/conn-location.c
@@ -0,0 +1,237 @@
+
+#include "config.h"
+#include "conn-location.h"
+
+#include <stdlib.h>
+
+#include "namespaces.h"
+#include "pubsub.h"
+
+struct request_location_ctx
+{
+  DBusGMethodInvocation *call;
+  guint pending_replies;
+  GHashTable *results;
+};
+
+/* XXX: similar to conn-olpc.c's inspect_contact(), except that it assumes
+ * that the handle is valid. (Does tp_handle_inspect check validity anyway?)
+ * Reduce duplication.
+ */
+static const gchar *
+inspect_contact (TpBaseConnection *base,
+                 guint contact)
+{
+  TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+      base, TP_HANDLE_TYPE_CONTACT);
+
+  return tp_handle_inspect (contact_repo, contact);
+}
+
+static gboolean
+validate_contacts (TpBaseConnection *base,
+                   DBusGMethodInvocation *context,
+                   const GArray *contacts)
+{
+  TpHandleRepoIface *contact_handles = tp_base_connection_get_handles (base,
+      TP_HANDLE_TYPE_CONTACT);
+  GError *error;
+
+  if (!tp_handles_are_valid (contact_handles, contacts, TRUE, &error))
+    {
+      dbus_g_method_return_error (context, error);
+      g_error_free (error);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+lm_message_node_get_double (LmMessageNode *node,
+                            gdouble *d)
+{
+  const gchar *value;
+  gchar *end;
+
+  value = lm_message_node_get_value (node);
+
+  if (value == NULL)
+    return FALSE;
+
+  *d = strtod (value, &end);
+
+  if (end == value)
+    return FALSE;
+
+  return TRUE;
+}
+
+static LmHandlerResult
+pep_reply_cb (GabbleConnection *conn,
+              LmMessage *sent_msg,
+              LmMessage *reply_msg,
+              GObject *object,
+              gpointer user_data)
+{
+  TpBaseConnection *base = (TpBaseConnection *) conn;
+  TpHandleRepoIface *contact_repo =
+      tp_base_connection_get_handles (base, TP_HANDLE_TYPE_CONTACT);
+  LmMessageNode *geoloc;
+  LmMessageNode *lat_node;
+  LmMessageNode *lon_node;
+  GHashTable *result = NULL;
+  struct request_location_ctx *ctx = user_data;
+  const gchar *from;
+  gdouble lat;
+  gdouble lon;
+  guint contact;
+
+  ctx->pending_replies--;
+  result = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+      (GDestroyNotify) tp_g_value_slice_free);
+  from = lm_message_node_get_attribute (reply_msg->node, "from");
+
+  if (from == NULL)
+    goto FAIL;
+
+  contact = tp_handle_lookup (contact_repo, from, NULL, NULL);
+  /* XXX: ref all the handles */
+  g_assert (contact);
+  geoloc = lm_message_node_find_child (reply_msg->node, "geoloc");
+
+  if (geoloc == NULL)
+    goto FAIL;
+
+  lat_node = lm_message_node_find_child (geoloc, "lat");
+  lon_node = lm_message_node_find_child (geoloc, "lon");
+
+  if (lat_node == NULL &&
+      lon_node == NULL)
+    goto FAIL;
+
+  if (lat_node != NULL && lm_message_node_get_double (lat_node, &lat))
+    {
+      GValue *value = g_slice_new0 (GValue);
+
+      g_value_init (value, G_TYPE_DOUBLE);
+      g_value_set_double (value, lat);
+      g_hash_table_insert (result, g_strdup ("lat"), value);
+    }
+
+  if (lon_node != NULL && lm_message_node_get_double (lon_node, &lon))
+    {
+      GValue *value = g_slice_new0 (GValue);
+
+      g_value_init (value, G_TYPE_DOUBLE);
+      g_value_set_double (value, lon);
+      g_hash_table_insert (result, g_strdup ("lon"), value);
+    }
+
+  g_hash_table_insert (ctx->results, GINT_TO_POINTER (contact), result);
+  goto END;
+
+FAIL:
+  g_hash_table_destroy (result);
+
+END:
+  if (ctx->pending_replies == 0)
+    {
+      gabble_svc_location_return_from_request_locations (ctx->call, ctx->results);
+      g_hash_table_destroy (ctx->results);
+      g_slice_free (struct request_location_ctx, ctx);
+    }
+
+  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+static void
+location_request_locations (GabbleSvcLocation *iface,
+                        const GArray *contacts,
+                        DBusGMethodInvocation *context)
+{
+  GabbleConnection *conn = GABBLE_CONNECTION (iface);
+  TpBaseConnection *base = (TpBaseConnection *) conn;
+  struct request_location_ctx *ctx = NULL;
+  guint i;
+
+  if (!validate_contacts (base, context, contacts))
+    return;
+
+  ctx = g_slice_new0 (struct request_location_ctx);
+  ctx->call = context;
+  ctx->pending_replies = contacts->len;
+  ctx->results = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
+      (GDestroyNotify) g_hash_table_destroy);
+
+  for (i = 0; i < contacts->len; i++)
+    {
+      GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR,
+          "Sending PEP location query failed" };
+      guint contact = g_array_index (contacts, guint, i);
+      const gchar *jid = inspect_contact (base, contact);
+
+      if (!pubsub_query (conn, jid, NS_GEOLOC, pep_reply_cb, ctx))
+        {
+          dbus_g_method_return_error (context, &error);
+          g_hash_table_destroy (ctx->results);
+          g_slice_free (struct request_location_ctx, ctx);
+          return;
+        }
+    }
+}
+
+static void
+location_set_location (GabbleSvcLocation *iface,
+                       GHashTable *location,
+                       DBusGMethodInvocation *context)
+{
+  GabbleConnection *conn = GABBLE_CONNECTION (iface);
+  LmMessage *msg;
+  LmMessageNode *geoloc;
+  GValue *lat_val;
+  GValue *lon_val;
+
+  msg = pubsub_make_publish_msg (NULL, NS_GEOLOC, NS_GEOLOC, "geoloc",
+      &geoloc);
+
+  lat_val = g_hash_table_lookup (location, "lat");
+  lon_val = g_hash_table_lookup (location, "lon");
+
+  if (lat_val && G_VALUE_TYPE (lat_val) == G_TYPE_DOUBLE)
+    {
+      gchar *lat_str;
+
+      lat_str = g_strdup_printf ("%.6f", g_value_get_double (lat_val));
+      lm_message_node_add_child (geoloc, "lat", lat_str);
+      g_free (lat_str);
+    }
+
+  if (lon_val && G_VALUE_TYPE (lon_val) == G_TYPE_DOUBLE)
+    {
+      gchar *lon_str;
+
+      lon_str = g_strdup_printf ("%.6f", g_value_get_double (lon_val));
+      lm_message_node_add_child (geoloc, "lon", lon_str);
+      g_free (lon_str);
+    }
+
+  /* XXX: use _ignore_reply */
+  if (!_gabble_connection_send (conn, msg, NULL))
+    /* XXX: return error */
+    return;
+
+  dbus_g_method_return (context);
+}
+
+void
+location_iface_init (gpointer g_iface, gpointer iface_data)
+{
+  GabbleSvcLocationClass *klass = g_iface;
+
+#define IMPLEMENT(x) gabble_svc_location_implement_##x (klass, location_##x)
+  IMPLEMENT(request_locations);
+  IMPLEMENT(set_location);
+#undef IMPLEMENT
+}
+
diff --git a/src/conn-location.h b/src/conn-location.h
new file mode 100644
index 0000000..3ec03e0
--- /dev/null
+++ b/src/conn-location.h
@@ -0,0 +1,14 @@
+
+#ifndef __CONN_LOCATION_H__
+#define __CONN_LOCATION_H__
+
+#include <extensions/extensions.h>
+
+G_BEGIN_DECLS
+
+void
+location_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_END_DECLS
+
+#endif /* __CONN_LOCATION_H__ */
diff --git a/src/connection.c b/src/connection.c
index 5f71e72..f6ae00e 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -50,6 +50,7 @@
 #include "caps-hash.h"
 #include "conn-aliasing.h"
 #include "conn-avatars.h"
+#include "conn-location.h"
 #include "conn-presence.h"
 #include "conn-olpc.h"
 #include "debug.h"
@@ -101,6 +102,8 @@ G_DEFINE_TYPE_WITH_CODE(GabbleConnection,
       tp_presence_mixin_simple_presence_iface_init);
     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
       conn_presence_iface_init);
+    G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_LOCATION,
+      location_iface_init);
     G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_OLPC_BUDDY_INFO,
       olpc_buddy_info_iface_init);
     G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_OLPC_ACTIVITY_PROPERTIES,
@@ -2028,7 +2031,7 @@ connection_disco_cb (GabbleDisco *disco,
   if (conn->features & GABBLE_CONNECTION_FEATURES_PEP)
     {
       const gchar *ifaces[] = { GABBLE_IFACE_OLPC_BUDDY_INFO,
-          GABBLE_IFACE_OLPC_ACTIVITY_PROPERTIES, NULL };
+          GABBLE_IFACE_OLPC_ACTIVITY_PROPERTIES, GABBLE_IFACE_LOCATION, NULL };
 
       tp_base_connection_add_interfaces ((TpBaseConnection *) conn, ifaces);
     }
diff --git a/tests/test-location.py b/tests/test-location.py
new file mode 100644
index 0000000..43845aa
--- /dev/null
+++ b/tests/test-location.py
@@ -0,0 +1,46 @@
+
+from gabbletest import exec_test, make_result_iq
+from servicetest import call_async
+
+def test(q, bus, conn, stream):
+    # hack
+    import dbus
+    conn.interfaces['Location'] = \
+        dbus.Interface(conn, 'org.freedesktop.Telepathy.Location')
+
+    conn.Connect()
+    q.expect('dbus-signal', signal='StatusChanged', args=[0, 1])
+
+    # discard activities request
+    q.expect('stream-iq', iq_type='set',
+        query_ns='http://jabber.org/protocol/pubsub')
+
+    conn.Location.SetLocation({
+        'lat': dbus.Double(0.0, variant_level=1), 'lon': 0.0})
+
+    event = q.expect('stream-iq', iq_type='set',
+        query_ns='http://jabber.org/protocol/pubsub')
+
+    handle = conn.RequestHandles(1, ['bob at foo.com'])[0]
+    call_async(q, conn.Location, 'GetLocations', [handle])
+
+    # XXX this is made up
+    event = q.expect('stream-iq', iq_type='get',
+        query_ns='http://jabber.org/protocol/pubsub')
+    result = make_result_iq(stream, event.stanza)
+    result['from'] = 'bob at foo.com'
+    query = result.firstChildElement()
+    geoloc = query.addElement(('http://jabber.org/protocol/geoloc', 'geoloc'))
+    geoloc.addElement('lat', content='1.234')
+    geoloc.addElement('lon', content='5.678')
+    stream.send(result)
+
+    q.expect('dbus-return', method='GetLocations')
+
+    conn.Disconnect()
+    q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
+    return True
+
+if __name__ == '__main__':
+    exec_test(test)
+
-- 
1.5.6.5




More information about the Telepathy-commits mailing list