[Telepathy-commits] [telepathy-mission-control/master] Check supported presence statuses before setting presence

Alberto Mardegan alberto.mardegan at nokia.com
Thu Nov 27 07:50:51 PST 2008


If the presence status that was requested is not support, fallback to a similar presence.
---
 src/mcd-connection.c |  126 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 118 insertions(+), 8 deletions(-)

diff --git a/src/mcd-connection.c b/src/mcd-connection.c
index 61c1df2..b69b1d6 100644
--- a/src/mcd-connection.c
+++ b/src/mcd-connection.c
@@ -101,6 +101,9 @@ struct _McdConnectionPrivate
     guint reconnect_interval;
     gboolean reconnection_requested;
 
+    /* Supported presences (values are McdPresenceInfo structs) */
+    GHashTable *recognized_presences;
+
     TpConnectionStatusReason abort_reason;
     guint got_capabilities : 1;
     guint got_contact_capabilities : 1;
@@ -124,13 +127,12 @@ struct _McdConnectionPrivate
     
 };
 
-struct presence_info
+typedef struct
 {
-    gchar *presence_str;
     TpConnectionPresenceType presence;
     guint may_set_on_self : 1;
     guint can_have_message : 1;
-};
+} McdPresenceInfo;
 
 struct param_data
 {
@@ -158,6 +160,15 @@ struct capabilities_wait_data {
     TpProxySignalConnection *signal_connection;
 };
 
+static const gchar *_available_fb[] = { NULL };
+static const gchar *_away_fb[] = { "away", NULL };
+static const gchar *_ext_away_fb[] = { "xa", "away", NULL };
+static const gchar *_hidden_fb[] = { "hidden", "dnd", "busy", "away", NULL };
+static const gchar *_busy_fb[] = { "busy", "dnd", "away", NULL };
+static const gchar **presence_fallbacks[] = {
+    _available_fb, _away_fb, _ext_away_fb, _hidden_fb, _busy_fb
+};
+
 static void request_channel_cb (TpConnection *proxy, const gchar *channel_path,
 				const GError *error, gpointer user_data,
 				GObject *weak_object);
@@ -166,6 +177,12 @@ static void _mcd_connection_setup (McdConnection * connection);
 static void _mcd_connection_release_tp_connection (McdConnection *connection);
 
 static void
+mcd_presence_info_free (McdPresenceInfo *pi)
+{
+    g_slice_free (McdPresenceInfo, pi);
+}
+
+static void
 presence_set_status_cb (TpConnection *proxy, const GError *error,
 			gpointer user_data, GObject *weak_object)
 {
@@ -201,8 +218,41 @@ presence_set_status_cb (TpConnection *proxy, const GError *error,
     }
 }
 
+static gboolean
+_check_presence (McdConnectionPrivate *priv, TpConnectionPresenceType presence,
+                 const gchar **status)
+{
+    const gchar **fallbacks;
+
+    if (g_hash_table_lookup (priv->recognized_presences, *status))
+        return TRUE;
+
+    if (presence < TP_CONNECTION_PRESENCE_TYPE_AVAILABLE ||
+        presence > TP_CONNECTION_PRESENCE_TYPE_BUSY)
+        return FALSE;
+
+    fallbacks =
+        presence_fallbacks[presence - TP_CONNECTION_PRESENCE_TYPE_AVAILABLE];
+
+    for (; *fallbacks != NULL; fallbacks++)
+        if (g_hash_table_lookup (priv->recognized_presences, *fallbacks))
+            break;
+
+    /* assume that "available" is always supported -- otherwise, an error will
+     * be returned by SetPresence, but it's not a big loss */
+    if (*fallbacks == NULL)
+        *fallbacks = "available";
+
+    g_debug ("%s: account %s: presence %s not supported, setting %s",
+             G_STRFUNC, mcd_account_get_unique_name (priv->account),
+             *status, *fallbacks);
+    *status = *fallbacks;
+    return TRUE;
+}
+
 static void
 _mcd_connection_set_presence (McdConnection * connection,
+                              TpConnectionPresenceType presence,
 			      const gchar *status, const gchar *message)
 {
     McdConnectionPrivate *priv = connection->priv;
@@ -217,13 +267,65 @@ _mcd_connection_set_presence (McdConnection * connection,
 
     if (!priv->has_presence_if) return;
 
-    tp_cli_connection_interface_simple_presence_call_set_presence
-        (priv->tp_conn, -1, status, message, presence_set_status_cb,
-         priv, NULL, (GObject *)connection);
+    if (_check_presence (priv, presence, &status))
+        tp_cli_connection_interface_simple_presence_call_set_presence
+            (priv->tp_conn, -1, status, message, presence_set_status_cb,
+             priv, NULL, (GObject *)connection);
 }
 
 
 static void
+presence_get_statuses_cb (TpProxy *proxy, const GValue *v_statuses,
+			  const GError *error, gpointer user_data,
+			  GObject *weak_object)
+{
+    McdConnectionPrivate *priv = user_data;
+    McdConnection *connection = MCD_CONNECTION (weak_object);
+    TpConnectionPresenceType presence;
+    const gchar *status, *message;
+    GHashTable *statuses;
+    GHashTableIter iter;
+    gpointer ht_key, ht_value;
+
+    if (error)
+    {
+        g_warning ("%s: Get statuses failed for account %s: %s", G_STRFUNC,
+                   mcd_account_get_unique_name (priv->account),
+                   error->message);
+        return;
+    }
+
+    if (!priv->recognized_presences)
+        priv->recognized_presences =
+            g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
+                                   (GDestroyNotify)mcd_presence_info_free);
+
+    g_debug ("%s: account %s:",
+             G_STRFUNC, mcd_account_get_unique_name (priv->account));
+    statuses = g_value_get_boxed (v_statuses);
+    g_hash_table_iter_init (&iter, statuses);
+    while (g_hash_table_iter_next (&iter, &ht_key, &ht_value))
+    {
+        const gchar *status = ht_key;
+        GValueArray *va = ht_value;
+        McdPresenceInfo *pi;
+
+        g_debug ("  %s", status);
+        pi = g_slice_new (McdPresenceInfo);
+        pi->presence = g_value_get_uint (va->values);
+        pi->may_set_on_self = g_value_get_boolean (va->values + 1);
+        pi->can_have_message = g_value_get_boolean (va->values + 2);
+        g_hash_table_insert (priv->recognized_presences,
+                             g_strdup (status), pi);
+    }
+
+    /* Now the presence info is ready. We can set the presence */
+    mcd_account_get_requested_presence (priv->account, &presence,
+                                        &status, &message);
+    _mcd_connection_set_presence (connection, presence, status, message);
+}
+
+static void
 on_presences_changed (TpConnection *proxy, GHashTable *presences,
                       gpointer user_data, GObject *weak_object)
 {
@@ -250,6 +352,10 @@ _mcd_connection_setup_presence (McdConnection *connection)
 {
     McdConnectionPrivate *priv =  connection->priv;
 
+    tp_cli_dbus_properties_call_get
+        (priv->tp_conn, -1, TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
+         "Statuses", presence_get_statuses_cb, priv, NULL,
+         (GObject *)connection);
     tp_cli_connection_interface_simple_presence_connect_to_presences_changed
         (priv->tp_conn, on_presences_changed, priv, NULL,
          (GObject *)connection, NULL);
@@ -312,8 +418,7 @@ on_presence_requested (McdAccount *account,
     }
     else
     {
-	if (mcd_connection_get_connection_status (connection) == TP_CONNECTION_STATUS_CONNECTED)
-            _mcd_connection_set_presence (connection, status, message);
+        _mcd_connection_set_presence (connection, presence, status, message);
     }
 }
 
@@ -1451,6 +1556,8 @@ _mcd_connection_finalize (GObject * object)
     McdConnectionPrivate *priv = MCD_CONNECTION_PRIV (connection);
 
     g_free (priv->alias);
+    if (priv->recognized_presences)
+        g_hash_table_destroy (priv->recognized_presences);
 
     G_OBJECT_CLASS (mcd_connection_parent_class)->finalize (object);
 }
@@ -1487,6 +1594,9 @@ _mcd_connection_release_tp_connection (McdConnection *connection)
      */
     g_free (priv->alias);
     priv->alias = NULL;
+
+    if (priv->recognized_presences)
+        g_hash_table_remove_all (priv->recognized_presences);
 }
 
 static void
-- 
1.5.6.5




More information about the Telepathy-commits mailing list