[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