[Telepathy-commits] [telepathy-mission-control/master] Implement ChannelRequests.Create and EnsureChannel

Alberto Mardegan alberto.mardegan at nokia.com
Mon Nov 17 00:05:22 PST 2008


Implement ChannelRequests.Create and temporarily have EnsureChannel behave in
the same way.
Also implement two support functions that are needed by these methods: a
function to deep-copy a GHashTable (because dbus-glib destroys its hash-tables
after invoking the service methods, rather then just unreferencing them) and a
function to return the error code as D-Bus error string.
---
 src/mcd-account-requests.c |  144 +++++++++++++++++++++++++++++++++++++++++++-
 src/mcd-channel.c          |    2 +
 src/mcd-misc.c             |   91 ++++++++++++++++++++++++++++
 src/mcd-misc.h             |    4 +
 4 files changed, 239 insertions(+), 2 deletions(-)

diff --git a/src/mcd-account-requests.c b/src/mcd-account-requests.c
index 1b3d9ff..281e3cd 100644
--- a/src/mcd-account-requests.c
+++ b/src/mcd-account-requests.c
@@ -37,8 +37,141 @@
 #include "mcd-account-priv.h"
 #include "mcd-account-requests.h"
 #include "mcd-account-manager.h"
+#include "mcd-misc.h"
 #include "_gen/interfaces.h"
 
+#define REQUEST_OBJ_BASE "/com/nokia/MissionControl/requests/r"
+
+typedef struct
+{
+    gchar *id;
+    gchar *requestor_client_id;
+} McdRequestData;
+
+static guint last_prop_id = 1;
+
+#define REQUEST_DATA "request_data"
+
+static inline McdRequestData *
+get_request_data (McdChannel *channel)
+{
+    g_return_val_if_fail (MCD_IS_CHANNEL (channel), NULL);
+    return g_object_get_data ((GObject *)channel, REQUEST_DATA);
+}
+
+static const gchar *
+get_request_id (McdChannel *channel)
+{
+    McdRequestData *rd;
+
+    rd = get_request_data (channel);
+    return rd->id;
+}
+
+static void
+online_request_cb (McdAccount *account, gpointer userdata, const GError *error)
+{
+    McdChannel *channel = MCD_CHANNEL (userdata);
+    McdConnection *connection;
+
+    if (error)
+    {
+        g_warning ("%s: got error: %s", G_STRFUNC, error->message);
+        _mcd_channel_set_error (channel, g_error_copy (error));
+        /* no unref here, as this will invoke our handler which will
+         * unreference the channel */
+        return;
+    }
+    g_debug ("%s called", G_STRFUNC);
+    connection = mcd_account_get_connection (account);
+    g_return_if_fail (connection != NULL);
+    g_return_if_fail (mcd_connection_get_connection_status (connection)
+                      == TP_CONNECTION_STATUS_CONNECTED);
+
+    /* the connection will take ownership of the channel, so let's keep a
+     * reference to it to make sure it's not destroyed while we are using it */
+    g_object_ref (channel);
+    mcd_connection_request_channel (connection, channel, NULL);
+}
+
+static void
+request_data_free (McdRequestData *rd)
+{
+    g_free (rd->id);
+    g_free (rd->requestor_client_id);
+    g_slice_free (McdRequestData, rd);
+}
+
+static void
+on_channel_status_changed (McdChannel *channel, McdChannelStatus status,
+                           McdAccount *account)
+{
+    const GError *error;
+
+    if (status == MCD_CHANNEL_FAILED)
+    {
+        const gchar *err_string;
+        error = _mcd_channel_get_error (channel);
+        g_warning ("Channel request %s failed, error: %s",
+                   get_request_id (channel), error->message);
+
+        err_string = _mcd_get_error_string (error);
+        mc_svc_account_interface_channelrequests_emit_failed (account,
+            get_request_id (channel), err_string, error->message);
+
+        g_object_unref (channel);
+    }
+    else if (status == MCD_CHANNEL_DISPATCHED)
+    {
+        mc_svc_account_interface_channelrequests_emit_succeeded (account,
+            get_request_id (channel));
+
+        /* free the request data, it's no longer useful */
+        g_object_set_data ((GObject *)channel, REQUEST_DATA, NULL);
+
+        g_object_unref (channel);
+    }
+}
+
+static McdChannel *
+create_request (McdAccount *account, GHashTable *properties,
+                guint64 user_time, const gchar *preferred_handler,
+                DBusGMethodInvocation *context, gboolean use_existing)
+{
+    McdChannel *channel;
+    McdRequestData *rd;
+    GError *error = NULL;
+    GHashTable *props;
+
+    /* TODO: handle use_existing */
+
+    /* We MUST deep-copy the hash-table, as we don't know how dbus-glib will
+     * free it */
+    props = _mcd_deepcopy_asv (properties);
+    channel = mcd_channel_new_request (props, user_time,
+                                       preferred_handler);
+    g_hash_table_unref (props);
+
+    rd = g_slice_new (McdRequestData);
+    rd->id = g_strdup_printf (REQUEST_OBJ_BASE "%u", last_prop_id++);
+    rd->requestor_client_id = dbus_g_method_get_sender (context);
+    g_object_set_data_full ((GObject *)channel, REQUEST_DATA, rd,
+                            (GDestroyNotify)request_data_free);
+
+    g_signal_connect (channel, "status-changed",
+                      G_CALLBACK (on_channel_status_changed), account);
+
+    _mcd_account_online_request (account, online_request_cb, channel, &error);
+    if (error)
+    {
+        g_warning ("%s: _mcd_account_online_request: %s", G_STRFUNC,
+                   error->message);
+        _mcd_channel_set_error (channel, error);
+        /* no unref here, as this will invoke our handler which will
+         * unreference the channel */
+    }
+    return channel;
+}
 
 const McdDBusProp account_channelrequests_properties[] = {
     { 0 },
@@ -52,14 +185,17 @@ account_request_create (McSvcAccountInterfaceChannelRequests *self,
 {
     GError *error = NULL;
     const gchar *request_id;
+    McdChannel *channel;
 
+    channel = create_request (MCD_ACCOUNT (self), properties, user_time,
+                              preferred_handler, context, FALSE);
     if (error)
     {
         dbus_g_method_return_error (context, error);
         g_error_free (error);
         return;
     }
-    request_id = "/com/nokia/chavo/request/r3";
+    request_id = get_request_id (channel);
     mc_svc_account_interface_channelrequests_return_from_create (context,
                                                                  request_id);
 }
@@ -72,6 +208,10 @@ account_request_ensure_channel (McSvcAccountInterfaceChannelRequests *self,
 {
     GError *error = NULL;
     const gchar *request_id;
+    McdChannel *channel;
+
+    channel = create_request (MCD_ACCOUNT (self), properties, user_time,
+                              preferred_handler, context, TRUE);
 
     if (error)
     {
@@ -79,7 +219,7 @@ account_request_ensure_channel (McSvcAccountInterfaceChannelRequests *self,
         g_error_free (error);
         return;
     }
-    request_id = "/com/nokia/chavo/request/r4";
+    request_id = get_request_id (channel);
     mc_svc_account_interface_channelrequests_return_from_ensure_channel
         (context, request_id);
 }
diff --git a/src/mcd-channel.c b/src/mcd-channel.c
index 2a6edf4..c756862 100644
--- a/src/mcd-channel.c
+++ b/src/mcd-channel.c
@@ -921,8 +921,10 @@ void
 mcd_channel_set_status (McdChannel *channel, McdChannelStatus status)
 {
     g_return_if_fail(MCD_IS_CHANNEL(channel));
+    g_object_ref (channel);
     g_signal_emit_by_name (channel, "status-changed", status);
     channel->priv->status = status;
+    g_object_unref (channel);
 }
 
 McdChannelStatus
diff --git a/src/mcd-misc.c b/src/mcd-misc.c
index 4ec79de..0ab033b 100644
--- a/src/mcd-misc.c
+++ b/src/mcd-misc.c
@@ -24,6 +24,9 @@
  */
 
 #include "mcd-misc.h"
+#include <telepathy-glib/errors.h>
+#include <telepathy-glib/util.h>
+#include <libmcclient/mc-errors.h>
 
 /*
  * Miscellaneus functions
@@ -87,3 +90,91 @@ _mcd_xdg_data_subdir_foreach (const gchar *subdir,
     }
 }
 
+GHashTable *
+_mcd_deepcopy_asv (GHashTable *asv)
+{
+    GHashTable *copy;
+    GHashTableIter iter;
+    gpointer ht_key, ht_value;
+
+    copy = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                  g_free,
+                                  (GDestroyNotify)tp_g_value_slice_free);
+    g_hash_table_iter_init (&iter, asv);
+    while (g_hash_table_iter_next (&iter, &ht_key, &ht_value))
+    {
+        GValue *value = g_slice_new0 (GValue);
+        g_value_init (value, G_VALUE_TYPE (ht_value));
+        g_value_copy (ht_value, value);
+
+        g_hash_table_insert (copy, g_strdup (ht_key), value);
+    }
+    return copy;
+}
+
+#define MC_ERROR_PREFIX "com.nokia.MissionControl.Errors"
+
+const gchar *
+_mcd_get_error_string (const GError *error)
+{
+    if (error->domain == TP_ERRORS)
+    {
+        switch (error->code)
+        {
+        case TP_ERROR_NETWORK_ERROR:
+            return TP_ERROR_PREFIX ".NetworkError";
+        case TP_ERROR_NOT_IMPLEMENTED:
+            return TP_ERROR_PREFIX ".NotImplemented";
+        case TP_ERROR_INVALID_ARGUMENT:
+            return TP_ERROR_PREFIX ".InvalidArgument";
+        case TP_ERROR_NOT_AVAILABLE:
+            return TP_ERROR_PREFIX ".NotAvailable";
+        case TP_ERROR_PERMISSION_DENIED:
+            return TP_ERROR_PREFIX ".PermissionDenied";
+        case TP_ERROR_DISCONNECTED:
+            return TP_ERROR_PREFIX ".Disconnected";
+        case TP_ERROR_INVALID_HANDLE:
+            return TP_ERROR_PREFIX ".InvalidHandle";
+        case TP_ERROR_CHANNEL_BANNED:
+            return TP_ERROR_PREFIX ".Banned";
+        case TP_ERROR_CHANNEL_FULL:
+            return TP_ERROR_PREFIX ".Full";
+        case TP_ERROR_CHANNEL_INVITE_ONLY:
+            return TP_ERROR_PREFIX ".InviteOnly";
+        }
+    }
+    else if (error->domain == MC_ERROR)
+    {
+        switch (error->code)
+        {
+        case MC_DISCONNECTED_ERROR:
+            return MC_ERROR_PREFIX ".Disconnected";
+        case MC_INVALID_HANDLE_ERROR:
+            return MC_ERROR_PREFIX ".InvalidHandle";
+        case MC_NO_MATCHING_CONNECTION_ERROR:
+            return MC_ERROR_PREFIX ".NoMatchingConnection";
+        case MC_INVALID_ACCOUNT_ERROR:
+            return MC_ERROR_PREFIX ".InvalidAccount";
+        case MC_PRESENCE_FAILURE_ERROR:
+            return MC_ERROR_PREFIX ".PresenceFailure";
+        case MC_NO_ACCOUNTS_ERROR:
+            return MC_ERROR_PREFIX ".NoAccounts";
+        case MC_NETWORK_ERROR:
+            return MC_ERROR_PREFIX ".Network";
+        case MC_CONTACT_DOES_NOT_SUPPORT_VOICE_ERROR:
+            return MC_ERROR_PREFIX ".ContactDoesNotSupportVoice";
+        case MC_LOWMEM_ERROR:
+            return MC_ERROR_PREFIX ".Lowmem";
+        case MC_CHANNEL_REQUEST_GENERIC_ERROR:
+            return MC_ERROR_PREFIX ".Generic";
+        case MC_CHANNEL_BANNED_ERROR:
+            return MC_ERROR_PREFIX ".ChannelBanned";
+        case MC_CHANNEL_FULL_ERROR:
+            return MC_ERROR_PREFIX ".ChannelFull";
+        case MC_CHANNEL_INVITE_ONLY_ERROR:
+            return MC_ERROR_PREFIX ".ChannelInviteOnly";
+        }
+    }
+    return NULL;
+}
+
diff --git a/src/mcd-misc.h b/src/mcd-misc.h
index 7185041..d4314b1 100644
--- a/src/mcd-misc.h
+++ b/src/mcd-misc.h
@@ -38,5 +38,9 @@ void _mcd_xdg_data_subdir_foreach (const gchar *subdir,
                                    McdXdgDataSubdirFunc callback,
                                    gpointer user_data);
 
+GHashTable *_mcd_deepcopy_asv (GHashTable *asv);
+
+const gchar *_mcd_get_error_string (const GError *error);
+
 G_END_DECLS
 #endif /* MCD_MISC_H */
-- 
1.5.6.5




More information about the Telepathy-commits mailing list