telepathygabble/src/gabble-presence-cache.c
branchRCL_3
changeset 11 3404599e4dda
parent 9 46cc8e302e43
--- a/telepathygabble/src/gabble-presence-cache.c	Wed Mar 31 22:32:38 2010 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1267 +0,0 @@
-/*
- * gabble-presence-cache.c - Gabble's contact presence cache
- * Copyright (C) 2005 Collabora Ltd.
- *  and/or its subsidiaries. All rights reserved.
- *
- * 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 <stdlib.h>
-#include <string.h>
-
-#include "debug.h"
-#include "disco.h" /* \o\ \o/ /o/ */
-#include "gabble-presence.h"
-#include "namespaces.h"
-#include "util.h"
-#include "handle-set.h"
-#include "gintset.h"
-
-#include "gabble-presence-cache.h"
-
-#include "gabble-presence-cache-signals-marshal.h"
-
-#include "gabble_enums.h"
-
-#ifndef EMULATOR
-G_DEFINE_TYPE (GabblePresenceCache, gabble_presence_cache, G_TYPE_OBJECT);
-#endif
-
-/* when five DIFFERENT guys report the same caps for a given bundle, it'll be enough */
-#define CAPABILITY_BUNDLE_ENOUGH_TRUST 5
-#define DEBUG_FLAG GABBLE_DEBUG_PRESENCE
-
-#ifdef DEBUG_FLAG
-//#define DEBUG(format, ...)
-#define DEBUGGING 0
-#define NODE_DEBUG(n, s)
-#endif /* DEBUG_FLAG */
-
-/* properties */
-enum
-{
-  PROP_CONNECTION = 1,
-  LAST_PROPERTY
-};
-
-/* signal enum */
-enum
-{
-  PRESENCE_UPDATE,
-  NICKNAME_UPDATE,
-  CAPABILITIES_UPDATE,
-  LAST_SIGNAL 
-#ifdef EMULATOR  
-  = LAST_SIGNAL_PRE_CACHE
-#endif
-  
-};
-
-
-#ifdef EMULATOR
-#include "libgabble_wsd_solution.h"
-
-	GET_STATIC_ARRAY_FROM_TLS(signals,gabble_pre_cache,guint)
-	#define signals (GET_WSD_VAR_NAME(signals,gabble_pre_cache, s)())
-	
-    GET_STATIC_VAR_FROM_TLS(gabble_presence_cache_parent_class,gabble_pre_cache,gpointer)
-	#define gabble_presence_cache_parent_class (*GET_WSD_VAR_NAME(gabble_presence_cache_parent_class,gabble_pre_cache,s)())
-	
-	GET_STATIC_VAR_FROM_TLS(g_define_type_id,gabble_pre_cache,GType)
-	#define g_define_type_id (*GET_WSD_VAR_NAME(g_define_type_id,gabble_pre_cache,s)())
-
-		
-static void gabble_presence_cache_init (GabblePresenceCache *self); 
-static void gabble_presence_cache_class_init (GabblePresenceCacheClass *klass);
-static void gabble_presence_cache_class_intern_init (gpointer klass)
- { 
- gabble_presence_cache_parent_class = g_type_class_peek_parent (klass); 
- gabble_presence_cache_class_init ((GabblePresenceCacheClass*) klass);
- } 
- EXPORT_C GType gabble_presence_cache_get_type (void) 
- { 
- if ((g_define_type_id == 0))
- 	{ static const GTypeInfo g_define_type_info = { sizeof (GabblePresenceCacheClass), (GBaseInitFunc) ((void *)0), (GBaseFinalizeFunc) ((void *)0), (GClassInitFunc) gabble_presence_cache_class_intern_init, (GClassFinalizeFunc) ((void *)0), ((void *)0), sizeof (GabblePresenceCache), 0, (GInstanceInitFunc) gabble_presence_cache_init, ((void *)0) }; g_define_type_id = g_type_register_static ( ((GType) ((20) << (2))), g_intern_static_string ("GabblePresenceCache"), &g_define_type_info, (GTypeFlags) 0); { {} ; } } return g_define_type_id; 
- };
-	
-		
-#else
-
-	static guint signals[LAST_SIGNAL] = {0};
-
-#endif
-
-
-#define GABBLE_PRESENCE_CACHE_PRIV(account) ((GabblePresenceCachePrivate *)account->priv)
-
-typedef struct _GabblePresenceCachePrivate GabblePresenceCachePrivate;
-
-struct _GabblePresenceCachePrivate
-{
-  GabbleConnection *conn;
-
-  gulong status_changed_cb;
-  LmMessageHandler *lm_message_cb;
-
-  GHashTable *presence;
-  GabbleHandleSet *presence_handles;
-
-  GHashTable *capabilities;
-  GHashTable *disco_pending;
-  guint caps_serial;
-
-  gboolean dispose_has_run;
-};
-
-typedef struct _DiscoWaiter DiscoWaiter;
-
-struct _DiscoWaiter
-{
-  GabbleHandleRepo *repo;
-  GabbleHandle handle;
-  gchar *resource;
-  guint serial;
-  gboolean disco_requested;
-};
-
-/**
- * disco_waiter_new ()
- */
-static DiscoWaiter *
-disco_waiter_new (GabbleHandleRepo *repo, GabbleHandle handle, const gchar *resource, guint serial)
-{
-  DiscoWaiter *waiter;
-
-  g_assert (repo);
-  gabble_handle_ref (repo, TP_HANDLE_TYPE_CONTACT, handle);
-
-  waiter = g_new0 (DiscoWaiter, 1);
-  waiter->repo = repo;
-  waiter->handle = handle;
-  waiter->resource = g_strdup (resource);
-  waiter->serial = serial;
-
-  gabble_debug (DEBUG_FLAG, "created waiter %p for handle %u with serial %u", waiter, handle, serial);
-
-  return waiter;
-}
-
-static void
-disco_waiter_free (DiscoWaiter *waiter)
-{
-  g_assert (NULL != waiter);
-
-  gabble_debug (DEBUG_FLAG, "freeing waiter %p for handle %u with serial %u", waiter, waiter->handle, waiter->serial);
-
-  gabble_handle_unref (waiter->repo, TP_HANDLE_TYPE_CONTACT, waiter->handle);
-
-  g_free (waiter->resource);
-  g_free (waiter);
-}
-
-static void
-disco_waiter_list_free (GSList *list)
-{
-  GSList *i;
-
-  gabble_debug (DEBUG_FLAG, "list %p", list);
-
-  for (i = list; NULL != i; i = i->next)
-    disco_waiter_free ((DiscoWaiter *) i->data);
-
-  g_slist_free (list);
-}
-
-static guint
-disco_waiter_list_get_request_count (GSList *list)
-{
-  guint c = 0;
-  GSList *i;
-
-  for (i = list; i; i = i->next)
-    {
-      DiscoWaiter *waiter = (DiscoWaiter *) i->data;
-
-      if (waiter->disco_requested)
-        c++;
-    }
-
-  return c;
-}
-
-typedef struct _CapabilityInfo CapabilityInfo;
-
-struct _CapabilityInfo
-{
-  GabblePresenceCapabilities caps;
-  GIntSet *guys;
-  guint trust;
-};
-
-static CapabilityInfo *
-capability_info_get (GabblePresenceCache *cache, const gchar *node,
-    GabblePresenceCapabilities caps)
-{
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  CapabilityInfo *info = g_hash_table_lookup (priv->capabilities, node);
-
-  if (NULL == info)
-    {
-      info = g_new0 (CapabilityInfo, 1);
-      info->caps = caps;
-      info->guys = g_intset_new ();
-      g_hash_table_insert (priv->capabilities, g_strdup (node), info);
-    }
-
-  return info;
-}
-
-static guint
-capability_info_recvd (GabblePresenceCache *cache, const gchar *node,
-        GabbleHandle handle, GabblePresenceCapabilities caps)
-{
-  CapabilityInfo *info = capability_info_get (cache, node, caps);
-
-  /* Detect inconsistency in reported caps */
-  if (info->caps != caps)
-    {
-      g_intset_clear (info->guys);
-      info->caps = caps;
-      info->trust = 0;
-    }
-
-  if (!g_intset_is_member (info->guys, handle))
-    {
-      g_intset_add (info->guys, handle);
-      info->trust++;
-    }
-
-  return info->trust;
-}
-
-static void gabble_presence_cache_init (GabblePresenceCache *presence_cache);
-static GObject * gabble_presence_cache_constructor (GType type, guint n_props,
-    GObjectConstructParam *props);
-static void gabble_presence_cache_dispose (GObject *object);
-static void gabble_presence_cache_finalize (GObject *object);
-static void gabble_presence_cache_set_property (GObject *object, guint
-    property_id, const GValue *value, GParamSpec *pspec);
-static void gabble_presence_cache_get_property (GObject *object, guint
-    property_id, GValue *value, GParamSpec *pspec);
-static GabblePresence *_cache_insert (GabblePresenceCache *cache,
-    GabbleHandle handle);
-
-static void gabble_presence_cache_status_changed_cb (GabbleConnection *,
-    TpConnectionStatus, TpConnectionStatusReason, gpointer);
-static LmHandlerResult gabble_presence_cache_lm_message_cb (LmMessageHandler*,
-    LmConnection*, LmMessage*, gpointer);
-
-static void
-gabble_presence_cache_class_init (GabblePresenceCacheClass *klass)
-{
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-  GParamSpec *param_spec;
-
-  g_type_class_add_private (object_class, sizeof (GabblePresenceCachePrivate));
-
-  object_class->constructor = gabble_presence_cache_constructor;
-
-  object_class->dispose = gabble_presence_cache_dispose;
-  object_class->finalize = gabble_presence_cache_finalize;
-
-  object_class->get_property = gabble_presence_cache_get_property;
-  object_class->set_property = gabble_presence_cache_set_property;
-
-  param_spec = g_param_spec_object ("connection", "GabbleConnection object",
-                                    "Gabble connection object that owns this "
-                                    "presence cache.",
-                                    GABBLE_TYPE_CONNECTION,
-                                    G_PARAM_CONSTRUCT_ONLY |
-                                    G_PARAM_READWRITE |
-                                    G_PARAM_STATIC_NICK |
-                                    G_PARAM_STATIC_BLURB);
-  g_object_class_install_property (object_class,
-                                   PROP_CONNECTION,
-                                   param_spec);
-
-  signals[PRESENCE_UPDATE] = g_signal_new (
-    "presence-update",
-    G_TYPE_FROM_CLASS (klass),
-    G_SIGNAL_RUN_LAST,
-    0,
-    NULL, NULL,
-    g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
-  signals[NICKNAME_UPDATE] = g_signal_new (
-    "nickname-update",
-    G_TYPE_FROM_CLASS (klass),
-    G_SIGNAL_RUN_LAST,
-    0,
-    NULL, NULL,
-    g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
-  signals[CAPABILITIES_UPDATE] = g_signal_new (
-    "capabilities-update",
-    G_TYPE_FROM_CLASS (klass),
-    G_SIGNAL_RUN_LAST,
-    0,
-    NULL, NULL,
-    gabble_presence_cache_marshal_VOID__UINT_UINT_UINT, G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
-}
-
-static void
-gabble_presence_cache_init (GabblePresenceCache *cache)
-{
-  GabblePresenceCachePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (cache,
-      GABBLE_TYPE_PRESENCE_CACHE, GabblePresenceCachePrivate);
-
-  cache->priv = priv;
-
-  priv->presence = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
-  priv->capabilities = g_hash_table_new (g_str_hash, g_str_equal);
-  priv->disco_pending = g_hash_table_new_full (g_str_hash, g_str_equal,
-    g_free, (GDestroyNotify) disco_waiter_list_free);
-  priv->caps_serial = 1;
-}
-
-static GObject *
-gabble_presence_cache_constructor (GType type, guint n_props,
-                                   GObjectConstructParam *props)
-{
-  GObject *obj;
-  GabblePresenceCachePrivate *priv;
-
-  obj = G_OBJECT_CLASS (gabble_presence_cache_parent_class)->
-           constructor (type, n_props, props);
-  priv = GABBLE_PRESENCE_CACHE_PRIV (GABBLE_PRESENCE_CACHE (obj));
-
-  priv->status_changed_cb = g_signal_connect (priv->conn, "status-changed",
-      G_CALLBACK (gabble_presence_cache_status_changed_cb), obj);
-
-  return obj;
-}
-
-static void
-gabble_presence_cache_dispose (GObject *object)
-{
-  GabblePresenceCache *self = GABBLE_PRESENCE_CACHE (object);
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (self);
-
-  if (priv->dispose_has_run)
-    return;
-
-  gabble_debug (DEBUG_FLAG, "dispose called");
-
-  priv->dispose_has_run = TRUE;
-
-  g_assert (priv->lm_message_cb == NULL);
-
-  g_signal_handler_disconnect (priv->conn, priv->status_changed_cb);
-
-  g_hash_table_destroy (priv->presence);
-  priv->presence = NULL;
-
-  handle_set_destroy (priv->presence_handles);
-  priv->presence_handles = NULL;
-
-  if (G_OBJECT_CLASS (gabble_presence_cache_parent_class)->dispose)
-    G_OBJECT_CLASS (gabble_presence_cache_parent_class)->dispose (object);
-}
-
-static void
-gabble_presence_cache_finalize (GObject *object)
-{
-  gabble_debug (DEBUG_FLAG, "called with %p", object);
-
-  G_OBJECT_CLASS (gabble_presence_cache_parent_class)->finalize (object);
-}
-
-static void
-gabble_presence_cache_get_property (GObject    *object,
-                                    guint       property_id,
-                                    GValue     *value,
-                                    GParamSpec *pspec)
-{
-  GabblePresenceCache *cache = GABBLE_PRESENCE_CACHE (object);
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-
-  switch (property_id) {
-    case PROP_CONNECTION:
-      g_value_set_object (value, priv->conn);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-  }
-}
-
-static void
-gabble_presence_cache_set_property (GObject     *object,
-                                    guint        property_id,
-                                    const GValue *value,
-                                    GParamSpec   *pspec)
-{
-  GabblePresenceCache *cache = GABBLE_PRESENCE_CACHE (object);
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  GabbleHandleSet *new_presence_handles;
-
-  switch (property_id) {
-    case PROP_CONNECTION:
-      priv->conn = g_value_get_object (value);
-      new_presence_handles = handle_set_new (priv->conn->handles, TP_HANDLE_TYPE_CONTACT);
-
-      if (priv->presence_handles)
-        {
-          const GIntSet *add;
-          GIntSet *tmp;
-          add = handle_set_peek (priv->presence_handles);
-          tmp = handle_set_update (new_presence_handles, add);
-          handle_set_destroy (priv->presence_handles);
-          g_intset_destroy (tmp);
-        }
-      priv->presence_handles = new_presence_handles;
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-  }
-}
-
-#if 0
-static gboolean
-_presence_node_has_google_voice (LmMessageNode *pres_node)
-{
-  LmMessageNode *node;
-  const gchar *cap_ext;
-  gchar **features, **tmp;
-  gboolean found = FALSE;
-
-  node = lm_message_node_get_child_with_namespace (pres_node, "c", NS_CAPS);
-
-  if (node == NULL);
-    return FALSE;
-
-  cap_ext = lm_message_node_get_attribute (node, "ext");
-
-  if (cap_ext == NULL);
-    return FALSE;
-
-  features = g_strsplit (cap_ext, " ", 0);
-
-  for (tmp = features; *tmp; tmp++)
-    {
-      if (!g_strdiff (tmp, "voice-v1"))
-        {
-          found = TRUE;
-          break;
-        }
-    }
-
-  g_strfreev (features);
-
-  return found;
-}
-#endif
-
-static void
-gabble_presence_cache_status_changed_cb (GabbleConnection *conn,
-                                         TpConnectionStatus status,
-                                         TpConnectionStatusReason reason,
-                                         gpointer data)
-{
-  GabblePresenceCache *cache = GABBLE_PRESENCE_CACHE (data);
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-
-  g_assert (conn == priv->conn);
-
-  switch (status)
-    {
-    case TP_CONN_STATUS_CONNECTING:
-      g_assert (priv->lm_message_cb == NULL);
-
-      priv->lm_message_cb = lm_message_handler_new (gabble_presence_cache_lm_message_cb,
-                                                    cache, NULL);
-      lm_connection_register_message_handler (priv->conn->lmconn,
-                                              priv->lm_message_cb,
-                                              LM_MESSAGE_TYPE_PRESENCE,
-                                              LM_HANDLER_PRIORITY_LAST);
-      lm_connection_register_message_handler (priv->conn->lmconn,
-                                              priv->lm_message_cb,
-                                              LM_MESSAGE_TYPE_MESSAGE,
-                                              LM_HANDLER_PRIORITY_FIRST);
-      break;
-    case TP_CONN_STATUS_CONNECTED:
-      /* TODO: emit self presence */
-      break;
-    case TP_CONN_STATUS_DISCONNECTED:
-      g_assert (priv->lm_message_cb != NULL);
-
-      lm_connection_unregister_message_handler (conn->lmconn,
-                                                priv->lm_message_cb,
-                                                LM_MESSAGE_TYPE_PRESENCE);
-      lm_connection_unregister_message_handler (conn->lmconn,
-                                                priv->lm_message_cb,
-                                                LM_MESSAGE_TYPE_MESSAGE);
-      lm_message_handler_unref (priv->lm_message_cb);
-      priv->lm_message_cb = NULL;
-      break;
-    default:
-      g_assert_not_reached ();
-    }
-}
-
-static GabblePresenceId
-_presence_node_get_status (LmMessageNode *pres_node)
-{
-  const gchar *presence_show;
-  LmMessageNode *child_node = lm_message_node_get_child (pres_node, "show");
-
-  if (!child_node)
-    {
-      /*
-      NODE_DEBUG (pres_node,
-        "<presence> without <show> received from server, "
-        "setting presence to available");
-      */
-      return GABBLE_PRESENCE_AVAILABLE;
-    }
-
-  presence_show = lm_message_node_get_value (child_node);
-
-  if (!presence_show)
-    {
-      /*
-      NODE_DEBUG (pres_node,
-        "empty <show> tag received from server, "
-        "setting presence to available");
-      */
-      return GABBLE_PRESENCE_AVAILABLE;
-    }
-
-  if (0 == strcmp (presence_show, JABBER_PRESENCE_SHOW_AWAY))
-    return GABBLE_PRESENCE_AWAY;
-  else if (0 == strcmp (presence_show, JABBER_PRESENCE_SHOW_CHAT))
-    return GABBLE_PRESENCE_CHAT;
-  else if (0 == strcmp (presence_show, JABBER_PRESENCE_SHOW_DND))
-    return GABBLE_PRESENCE_DND;
-  else if (0 == strcmp (presence_show, JABBER_PRESENCE_SHOW_XA))
-    return GABBLE_PRESENCE_XA;
-  else
-    {
-       NODE_DEBUG (pres_node,
-        "unrecognised <show/> value received from server, "
-        "setting presence to available");
-      return GABBLE_PRESENCE_AVAILABLE;
-    }
-}
-
-static void
-_grab_nickname (GabblePresenceCache *cache,
-                GabbleHandle handle,
-                const gchar *from,
-                LmMessageNode *node)
-{
-  const gchar *nickname;
-  GabblePresence *presence;
-
-  node = lm_message_node_get_child_with_namespace (node, "nick", NS_NICK);
-
-  if (NULL == node)
-    return;
-
-  presence = gabble_presence_cache_get (cache, handle);
-
-  if (NULL == presence)
-    return;
-
-  nickname = lm_message_node_get_value (node);
-  gabble_debug (DEBUG_FLAG, "got nickname \"%s\" for %s", nickname, from);
-
-  if (g_strdiff (presence->nickname, nickname))
-    {
-      if (NULL != presence->nickname)
-        g_free (presence->nickname);
-
-      presence->nickname = g_strdup (nickname);
-      g_signal_emit (cache, signals[NICKNAME_UPDATE], 0, handle);
-    }
-}
-
-static GSList *
-_extract_cap_bundles (LmMessageNode *lm_node)
-{
-  const gchar *node, *ver, *ext;
-  GSList *uris = NULL;
-  LmMessageNode *cap_node;
-
-  cap_node = lm_message_node_get_child_with_namespace (lm_node, "c", NS_CAPS);
-
-  if (NULL == cap_node)
-    return NULL;
-
-  node = lm_message_node_get_attribute (cap_node, "node");
-
-  if (NULL == node)
-    return NULL;
-
-  ver = lm_message_node_get_attribute (cap_node, "ver");
-
-  if (NULL != ver)
-    uris = g_slist_prepend (uris, g_strdup_printf ("%s#%s", node, ver));
-
-  ext = lm_message_node_get_attribute (cap_node, "ext");
-
-  if (NULL != ext)
-    {
-      gchar **exts, **i;
-
-      exts = g_strsplit (ext, " ", 0);
-
-      for (i = exts; NULL != *i; i++)
-        uris = g_slist_prepend (uris, g_strdup_printf ("%s#%s", node, *i));
-
-      g_strfreev (exts);
-    }
-
-  return uris;
-}
-
-static void
-_caps_disco_cb (GabbleDisco *disco,
-                GabbleDiscoRequest *request,
-                const gchar *jid,
-                const gchar *node,
-                LmMessageNode *query_result,
-                GError *error,
-                gpointer user_data)
-{
-  GSList *waiters, *i;
-  LmMessageNode *child;
-  GabblePresenceCache *cache;
-  GabblePresenceCachePrivate *priv;
-  gchar *full_jid = NULL;
-  GabblePresenceCapabilities caps = 0;
-  guint trust;
-  GabbleHandle handle;
-
-  cache = GABBLE_PRESENCE_CACHE (user_data);
-  priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-
-  if (NULL == node)
-    {
-      g_warning ("got disco response with NULL node, ignoring");
-      return;
-    }
-
-  waiters = g_hash_table_lookup (priv->disco_pending, node);
-
-  if (NULL != error)
-    {
-      DiscoWaiter *waiter = NULL;
-
-      gabble_debug (DEBUG_FLAG, "disco query failed: %s", error->message);
-
-      for (i = waiters; NULL != i; i = i->next)
-        {
-          waiter = (DiscoWaiter *) i->data;
-
-          if (!waiter->disco_requested)
-            {
-              const gchar *jid;
-
-              jid = gabble_handle_inspect (priv->conn->handles,
-                                           TP_HANDLE_TYPE_CONTACT,
-                                           waiter->handle);
-              full_jid = g_strdup_printf ("%s/%s", jid, waiter->resource);
-
-              gabble_disco_request (disco, GABBLE_DISCO_TYPE_INFO, full_jid, node,
-                                    _caps_disco_cb, cache, G_OBJECT(cache), NULL);
-              waiter->disco_requested = TRUE;
-              break;
-            }
-        }
-
-      if (NULL != i)
-        {
-          gabble_debug (DEBUG_FLAG, "sent a retry disco request to %s for URI %s", full_jid, node);
-        }
-      else
-        {
-          gabble_debug (DEBUG_FLAG, "failed to find a suitable candidate to retry disco request for URI %s", node);
-          /* FIXME do something very clever here? */
-          g_hash_table_remove (priv->disco_pending, node);
-        }
-
-      goto OUT;
-    }
-
-  for (child = query_result->children; NULL != child; child = child->next)
-    {
-      const gchar *var;
-
-      if (0 != strcmp (child->name, "feature"))
-        continue;
-
-      var = lm_message_node_get_attribute (child, "var");
-
-      if (NULL == var)
-        continue;
-
-      /* TODO: use a table that equates disco features to caps */
-      if (0 == strcmp (var, NS_GOOGLE_TRANSPORT_P2P))
-        caps |= PRESENCE_CAP_GOOGLE_TRANSPORT_P2P;
-      else if (0 == strcmp (var, NS_GOOGLE_FEAT_VOICE))
-        caps |= PRESENCE_CAP_GOOGLE_VOICE;
-      else if (0 == strcmp (var, NS_JINGLE))
-        caps |= PRESENCE_CAP_JINGLE;
-      else if (0 == strcmp (var, NS_JINGLE_DESCRIPTION_AUDIO))
-        caps |= PRESENCE_CAP_JINGLE_DESCRIPTION_AUDIO;
-      else if (0 == strcmp (var, NS_JINGLE_DESCRIPTION_VIDEO))
-        caps |= PRESENCE_CAP_JINGLE_DESCRIPTION_VIDEO;
-    }
-
-  handle = gabble_handle_for_contact (priv->conn->handles, jid, FALSE);
-  trust = capability_info_recvd (cache, node, handle, caps);
-
-  for (i = waiters; NULL != i;)
-    {
-      DiscoWaiter *waiter;
-      GabblePresence *presence;
-
-      waiter = (DiscoWaiter *) i->data;
-
-      if (trust >= CAPABILITY_BUNDLE_ENOUGH_TRUST || waiter->handle == handle)
-        {
-          GSList *tmp;
-          /* trusted reply */
-          presence = gabble_presence_cache_get (cache, waiter->handle);
-
-          if (presence)
-          {
-            GabblePresenceCapabilities save_caps = presence->caps;
-            gabble_debug (DEBUG_FLAG, "setting caps for %d (%s) to %d", handle, jid, caps);
-            gabble_presence_set_capabilities (presence, waiter->resource,caps,
-              waiter->serial);
-            gabble_debug (DEBUG_FLAG, "caps for %d (%s) now %d", handle, jid, presence->caps);
-            g_signal_emit (cache, signals[CAPABILITIES_UPDATE], 0,
-              waiter->handle, save_caps, presence->caps);
-          }
-
-          tmp = i;
-          i = i->next;
-
-          waiters = g_slist_delete_link (waiters, tmp);
-
-          g_hash_table_steal (priv->disco_pending, node);
-          g_hash_table_insert (priv->disco_pending, g_strdup (node), waiters);
-
-          disco_waiter_free (waiter);
-        }
-      else if (trust + disco_waiter_list_get_request_count (waiters) - 1
-          < CAPABILITY_BUNDLE_ENOUGH_TRUST)
-        {
-          /* if the possible trust, not counting this guy, is too low,
-           * we have been poisoned and reset our trust meters - disco
-           * anybody we still haven't to be able to get more trusted replies */
-
-          if (!waiter->disco_requested)
-            {
-              const gchar *jid;
-
-              jid = gabble_handle_inspect (priv->conn->handles,
-                TP_HANDLE_TYPE_CONTACT, waiter->handle);
-              full_jid = g_strdup_printf ("%s/%s", jid, waiter->resource);
-
-              gabble_disco_request (disco, GABBLE_DISCO_TYPE_INFO, full_jid,
-                  node, _caps_disco_cb, cache, G_OBJECT(cache), NULL);
-              waiter->disco_requested = TRUE;
-
-              g_free (full_jid);
-              full_jid = NULL;
-            }
-
-          i = i->next;
-        }
-      else
-        {
-          /* trust level still uncertain, don't do nothing */
-          i = i->next;
-        }
-    }
-
-  if (trust >= CAPABILITY_BUNDLE_ENOUGH_TRUST)
-    g_hash_table_remove (priv->disco_pending, node);
-
-OUT:
-
-  g_free (full_jid);
-}
-
-static void
-_process_caps_uri (GabblePresenceCache *cache,
-                   const gchar *from,
-                   const gchar *uri,
-                   GabbleHandle handle,
-                   const gchar *resource,
-                   guint serial)
-{
-  CapabilityInfo *info;
-  gpointer value;
-  GabblePresenceCachePrivate *priv;
-
-  priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  info = capability_info_get (cache, uri, 0);
-
-  if (info->trust >= CAPABILITY_BUNDLE_ENOUGH_TRUST
-      || g_intset_is_member (info->guys, handle))
-    {
-      /* we already have enough trust for this node; apply the cached value to
-       * the (handle, resource) */
-
-      GabblePresence *presence = gabble_presence_cache_get (cache, handle);
-      gabble_debug (DEBUG_FLAG, "enough trust for URI %s, setting caps for %u (%s) to %u",
-          uri, handle, from, info->caps);
-
-      if (presence)
-        {
-          GabblePresenceCapabilities save_caps = presence->caps;
-          gabble_presence_set_capabilities (presence, resource, info->caps, serial);
-          g_signal_emit (cache, signals[CAPABILITIES_UPDATE], 0,
-              handle, save_caps, presence->caps);
-          gabble_debug (DEBUG_FLAG, "caps for %d (%s) now %d", handle, from, presence->caps);
-        }
-      else
-        {
-          gabble_debug (DEBUG_FLAG, "presence not found");
-        }
-    }
-  else
-    {
-      /* Append the (handle, resource) pair to the list of such pairs
-       * waiting for capabilities for this uri, and send a disco request
-       * if we don't have enough possible trust yet */
-
-      GSList *waiters;
-      DiscoWaiter *waiter;
-      guint possible_trust;
-
-      gabble_debug (DEBUG_FLAG, "not enough trust for URI %s", uri);
-      value = g_hash_table_lookup (priv->disco_pending, uri);
-
-      if (value)
-        g_hash_table_steal (priv->disco_pending, uri);
-
-      waiters = (GSList *) value;
-      waiter = disco_waiter_new (priv->conn->handles, handle, resource, serial);
-      waiters = g_slist_prepend (waiters, waiter);
-      g_hash_table_insert (priv->disco_pending, g_strdup (uri), waiters);
-
-      possible_trust = disco_waiter_list_get_request_count (waiters);
-
-      if (!value || info->trust + possible_trust < CAPABILITY_BUNDLE_ENOUGH_TRUST)
-        {
-          /* DISCO */
-          gabble_debug (DEBUG_FLAG, "only %u trust out of %u possible thus far, sending disco for URI %s",
-              info->trust + possible_trust, CAPABILITY_BUNDLE_ENOUGH_TRUST, uri);
-          gabble_disco_request (priv->conn->disco, GABBLE_DISCO_TYPE_INFO,
-              from, uri, _caps_disco_cb, cache, G_OBJECT (cache), NULL);
-          /* enough DISCO for you, buddy */
-          waiter->disco_requested = TRUE;
-        }
-    }
-}
-
-static void
-_process_caps (GabblePresenceCache *cache,
-               GabbleHandle handle,
-               const gchar *from,
-               LmMessageNode *lm_node)
-{
-  gchar *resource;
-  GSList *uris, *i;
-  GabblePresenceCachePrivate *priv;
-  guint serial;
-
-  priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  serial = priv->caps_serial++;
-
-  gabble_decode_jid (from, NULL, NULL, &resource);
-
-  if (NULL == resource)
-    return;
-
-  uris = _extract_cap_bundles (lm_node);
-
-  for (i = uris; NULL != i; i = i->next)
-    {
-      _process_caps_uri (cache, from, (gchar *) i->data, handle, resource, serial);
-      g_free (i->data);
-    }
-
-  g_free (resource);
-  g_slist_free (uris);
-}
-
-static void
-_grab_avatar_sha1 (GabblePresenceCache *cache,
-                   GabbleHandle handle,
-                   const gchar *from,
-                   LmMessageNode *node)
-{
-  const gchar *sha1;
-  LmMessageNode *x_node, *photo_node;
-  GabblePresence *presence;
-  //LIB_TRACE( ELibTraceTypeInfo, "%s",  "Out _grab_avatar_sha1" );
-  presence = gabble_presence_cache_get (cache, handle);
-
-  if (NULL == presence)
-    return;
-
-  x_node = lm_message_node_get_child_with_namespace (node, "x",
-      NS_VCARD_TEMP_UPDATE);
-
-  if (NULL == x_node)
-    {
-#if 0
-      if (handle == priv->conn->parent.self_handle)
-        {
-          /* One of my other resources does not support XEP-0153. As per that
-           * XEP, I MUST stop advertising the image hash, at least until all
-           * instances of non-conforming resources have gone offline.
-           * However, we're going to ignore this requirement and hope that
-           * non-conforming clients won't alter the <PHOTO>, which should
-           * in practice be true.
-           */
-          presence->avatar_sha1 = NULL;
-        }
-#endif
-      return;
-    }
-
-  photo_node = lm_message_node_get_child (x_node, "photo");
-
-  /* If there is no photo node, the resource supports XEP-0153, but has
-   * nothing in particular to say about the avatar. */
-  if (NULL == photo_node)
-    return;
-
-  sha1 = lm_message_node_get_value (photo_node);
-
-  if (g_strdiff (presence->avatar_sha1, sha1))
-    {
-      g_free (presence->avatar_sha1);
-      presence->avatar_sha1 = g_strdup (sha1);
-
-#if 0
-      if (handle == priv->conn->parent.self_handle)
-        {
-          /* that would be us, then. According to XEP-0153, we MUST
-           * immediately send a presence update with an empty update child
-           * element (no photo node), then re-download our own vCard;
-           * when that arrives, we may start setting the photo node in our
-           * presence again.
-           *
-           * For the moment I'm going to ignore that requirement and
-           * trust that our other resource is getting its sha1 right!
-           */
-          /* TODO: I don't trust anyone to get XMPP right, so let's do
-           * this. :D */
-        }
-#endif
-      //LIB_TRACE( ELibTraceTypeInfo, "%s",  "AVATAR_UPDATE _grab_avatar_sha1" );
-      //g_signal_emit (cache, signals[AVATAR_UPDATE], 0, handle);
-    }
-  //LIB_TRACE( ELibTraceTypeInfo, "%s",  "Out _grab_avatar_sha1" );
-}
-
-static LmHandlerResult
-_parse_presence_message (GabblePresenceCache *cache,
-                         GabbleHandle handle,
-                         const gchar *from,
-                         LmMessage *message)
-{
-  gint8 priority = 0;
-  gchar *resource = NULL;
-  const gchar *status_message = NULL;
-  LmMessageNode *presence_node, *child_node;
-  LmHandlerResult ret = LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-  GabblePresenceId presence_id;
-  GabblePresence *presence;
-
-  presence_node = message->node;
-  g_assert (0 == strcmp (presence_node->name, "presence"));
-
-  gabble_decode_jid (from, NULL, NULL, &resource);
-
-  presence = gabble_presence_cache_get (cache, handle);
-
-  if (NULL != presence)
-      presence->keep_unavailable = FALSE;
-
-  child_node = lm_message_node_get_child (presence_node, "status");
-
-  if (child_node)
-    status_message = lm_message_node_get_value (child_node);
-
-  child_node = lm_message_node_get_child (presence_node, "priority");
-
-  if (child_node)
-    {
-      const gchar *prio = lm_message_node_get_value (child_node);
-
-      if (prio != NULL)
-        priority = CLAMP (atoi (prio), G_MININT8, G_MAXINT8);
-    }
-
-  switch (lm_message_get_sub_type (message))
-    {
-    case LM_MESSAGE_SUB_TYPE_NOT_SET:
-    case LM_MESSAGE_SUB_TYPE_AVAILABLE:
-      presence_id = _presence_node_get_status (presence_node);
-      gabble_presence_cache_update (cache, handle, resource, presence_id,
-          status_message, priority);
-
-#if 0
-      if (_presence_node_has_google_voice (presence_node))
-        {
-          presence = gabble_presence_cache_get (cache, handle);
-          g_assert (NULL != presence);
-          gabble_debug (DEBUG_FLAG, "%s has voice-v1 support", from);
-          gabble_presence_set_capabilities (presence, resource,
-              PRESENCE_CAP_GOOGLE_VOICE);
-        }
-#endif
-
-      ret = LM_HANDLER_RESULT_REMOVE_MESSAGE;
-      break;
-
-    case LM_MESSAGE_SUB_TYPE_ERROR:
-      NODE_DEBUG (presence_node, "setting contact offline due to error");
-      /* fall through */
-
-    case LM_MESSAGE_SUB_TYPE_UNAVAILABLE:
-      gabble_presence_cache_update (cache, handle, resource,
-          GABBLE_PRESENCE_OFFLINE, status_message, priority);
-
-      ret = LM_HANDLER_RESULT_REMOVE_MESSAGE;
-      break;
-
-    default:
-      break;
-    }
-
-  _grab_avatar_sha1 (cache, handle, from, presence_node);
-  _grab_nickname (cache, handle, from, presence_node);
-  _process_caps (cache, handle, from, presence_node);
-
-  g_free (resource);
-
-  return ret;
-}
-
-static LmHandlerResult
-_parse_message_message (GabblePresenceCache *cache,
-                        GabbleHandle handle,
-                        const gchar *from,
-                        LmMessage *message)
-{
-  LmMessageNode *node;
-  GabblePresence *presence;
-
-  presence = gabble_presence_cache_get (cache, handle);
-
-  if (NULL == presence)
-    {
-      presence = _cache_insert (cache, handle);
-      presence->keep_unavailable = TRUE;
-    }
-
-  node = lm_message_get_node (message);
-
-  _grab_nickname (cache, handle, from, node);
-  _process_caps (cache, handle, from, node);
-
-  return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-}
-
-
-/**
- * gabble_presence_cache_lm_message_cb:
- * @handler: #LmMessageHandler for this message
- * @connection: #LmConnection that originated the message
- * @message: the presence message
- * @user_data: callback data
- *
- * Called by loudmouth when we get an incoming <presence>.
- */
-static LmHandlerResult
-gabble_presence_cache_lm_message_cb (LmMessageHandler *handler,
-                                     LmConnection *lmconn,
-                                     LmMessage *message,
-                                     gpointer user_data)
-{
-  GabblePresenceCache *cache = GABBLE_PRESENCE_CACHE (user_data);
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  const char *from;
-  GabbleHandle handle;
-
-  g_assert (lmconn == priv->conn->lmconn);
-
-  from = lm_message_node_get_attribute (message->node, "from");
-
-  if (NULL == from)
-    {
-     NODE_DEBUG (message->node, "message without from attribute, ignoring");
-      return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-    }
-
-  handle = gabble_handle_for_contact (priv->conn->handles, from, FALSE);
-
-  if (0 == handle)
-    {
-      NODE_DEBUG (message->node, "ignoring message from malformed jid");
-      return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-    }
-
-  if (handle == priv->conn->self_handle)
-    {
-      NODE_DEBUG (message->node,
-        "ignoring message from ourselves on another resource");
-      return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-    }
-
-  switch (lm_message_get_type (message))
-    {
-    case LM_MESSAGE_TYPE_PRESENCE:
-      return _parse_presence_message (cache, handle, from, message);
-    case LM_MESSAGE_TYPE_MESSAGE:
-      return _parse_message_message (cache, handle, from, message);
-    default:
-      return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-    }
-}
-
-
-GabblePresenceCache *
-gabble_presence_cache_new (GabbleConnection *conn)
-{
-  return g_object_new (GABBLE_TYPE_PRESENCE_CACHE,
-                       "connection", conn,
-                       NULL);
-}
-
-GabblePresence *
-gabble_presence_cache_get (GabblePresenceCache *cache, GabbleHandle handle)
-{
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-
-  
-//  g_assert (gabble_handle_is_valid (priv->conn->handles,
-//        TP_HANDLE_TYPE_CONTACT, handle, NULL));
-  if(priv)
-    if(priv->conn)
-      if(priv->conn->handles){
-  if ( gabble_handle_is_valid (priv->conn->handles,
-          TP_HANDLE_TYPE_CONTACT, handle, NULL) )
-      {
-        return g_hash_table_lookup (priv->presence, GINT_TO_POINTER (handle));  
-      }
-  else
-      {
-      return NULL;
-      }
-  }
-  return NULL;
-}
-
-void
-gabble_presence_cache_maybe_remove (
-    GabblePresenceCache *cache,
-    GabbleHandle handle)
-{
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  GabblePresence *presence;
-
-  presence = gabble_presence_cache_get (cache, handle);
-
-  if (NULL == presence)
-    return;
-
-  if (presence->status == GABBLE_PRESENCE_OFFLINE &&
-      presence->status_message == NULL &&
-      !presence->keep_unavailable)
-    {
-      const gchar *jid;
-
-      jid = gabble_handle_inspect (priv->conn->handles, TP_HANDLE_TYPE_CONTACT,
-          handle);
-      gabble_debug (DEBUG_FLAG, "discarding cached presence for unavailable jid %s", jid);
-      g_hash_table_remove (priv->presence, GINT_TO_POINTER (handle));
-      handle_set_remove (priv->presence_handles, handle);
-    }
-}
-
-static GabblePresence *
-_cache_insert (
-    GabblePresenceCache *cache,
-    GabbleHandle handle)
-{
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  GabblePresence *presence;
-
-  presence = gabble_presence_new ();
-  g_hash_table_insert (priv->presence, GINT_TO_POINTER (handle), presence);
-  handle_set_add (priv->presence_handles, handle);
-  return presence;
-}
-
-void
-gabble_presence_cache_update (
-    GabblePresenceCache *cache,
-    GabbleHandle handle,
-    const gchar *resource,
-    GabblePresenceId presence_id,
-    const gchar *status_message,
-    gint8 priority)
-{
-  GabblePresenceCachePrivate *priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
-  const gchar *jid;
-  GabblePresence *presence;
-
-  jid = gabble_handle_inspect (priv->conn->handles, TP_HANDLE_TYPE_CONTACT,
-      handle);
-  gabble_debug (DEBUG_FLAG, "%s (%d) resource %s prio %d presence %d message \"%s\"",
-      jid, handle, resource, priority, presence_id, status_message);
-
-  presence = gabble_presence_cache_get (cache, handle);
-
-  if (presence == NULL)
-    presence = _cache_insert (cache, handle);
-
-  if (gabble_presence_update (presence, resource, presence_id, status_message,
-        priority))
-    g_signal_emit (cache, signals[PRESENCE_UPDATE], 0, handle);
-
-  gabble_presence_cache_maybe_remove (cache, handle);
-}
-
-void gabble_presence_cache_add_bundle_caps (GabblePresenceCache *cache,
-    const gchar *node, GabblePresenceCapabilities new_caps)
-{
-  CapabilityInfo *info;
-
-  info = capability_info_get (cache, node, 0);
-  info->trust = CAPABILITY_BUNDLE_ENOUGH_TRUST;
-  info->caps |= new_caps;
-}
-