[Telepathy-commits] [telepathy-mission-control/master] Invoke new-style channel handlers
Alberto Mardegan
alberto.mardegan at nokia.com
Mon Nov 17 00:05:19 PST 2008
If a Client.Handler matching the HandlerChannelFilter rules is found, call
HandleChannels on it. Currently this is limited to one channel at a time.
---
.../libmissioncontrol-server/tmpl/mcd-channel.sgml | 3 +-
.../tmpl/mcd-dispatcher-context.sgml | 2 +-
src/mcd-dispatcher-context.h | 5 +-
src/mcd-dispatcher.c | 304 +++++++++++++++++---
4 files changed, 265 insertions(+), 49 deletions(-)
diff --git a/doc/reference/libmissioncontrol-server/tmpl/mcd-channel.sgml b/doc/reference/libmissioncontrol-server/tmpl/mcd-channel.sgml
index 1454fbf..2555295 100644
--- a/doc/reference/libmissioncontrol-server/tmpl/mcd-channel.sgml
+++ b/doc/reference/libmissioncontrol-server/tmpl/mcd-channel.sgml
@@ -123,7 +123,8 @@ McdChannel
</para>
- at MCD_CHANNEL_PENDING:
+ at MCD_CHANNEL_UNDISPATCHED:
+ at MCD_CHANNEL_NO_PROXY:
@MCD_CHANNEL_DISPATCHING:
@MCD_CHANNEL_DISPATCHED:
@MCD_CHANNEL_FAILED:
diff --git a/doc/reference/libmissioncontrol-server/tmpl/mcd-dispatcher-context.sgml b/doc/reference/libmissioncontrol-server/tmpl/mcd-dispatcher-context.sgml
index 50e58f1..1d0f963 100644
--- a/doc/reference/libmissioncontrol-server/tmpl/mcd-dispatcher-context.sgml
+++ b/doc/reference/libmissioncontrol-server/tmpl/mcd-dispatcher-context.sgml
@@ -173,7 +173,7 @@ mcd-dispatcher-context
</para>
- at ctx:
+ at context:
@Returns:
diff --git a/src/mcd-dispatcher-context.h b/src/mcd-dispatcher-context.h
index e70c8b1..db0a8c9 100644
--- a/src/mcd-dispatcher-context.h
+++ b/src/mcd-dispatcher-context.h
@@ -93,13 +93,16 @@ TpConnection *mcd_dispatcher_context_get_connection_object (McdDispatcherContext
McdChannel * mcd_dispatcher_context_get_channel (McdDispatcherContext * ctx);
-McdConnection * mcd_dispatcher_context_get_connection (McdDispatcherContext * ctx);
+McdConnection *mcd_dispatcher_context_get_connection
+ (McdDispatcherContext *context);
McdChannelHandler * mcd_dispatcher_context_get_chan_handler (McdDispatcherContext * ctx);
/*Returns an array of the gchar * addresses of participants in the channel*/
GPtrArray *mcd_dispatcher_context_get_members (McdDispatcherContext * ctx);
+GPtrArray *mcd_dispatcher_context_get_channels_dbus
+ (McdDispatcherContext *context);
/* Statemachine API section */
diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
index d6fc7be..0274fd4 100644
--- a/src/mcd-dispatcher.c
+++ b/src/mcd-dispatcher.c
@@ -44,9 +44,12 @@
#include "mcd-chan-handler.h"
#include "mcd-dispatcher-context.h"
#include "mcd-misc.h"
-#include "_gen/interfaces.h"
#include <telepathy-glib/interfaces.h>
#include <telepathy-glib/proxy-subclass.h>
+#include "_gen/interfaces.h"
+#include "_gen/gtypes.h"
+#include "_gen/cli-client.h"
+#include "_gen/cli-client-body.h"
#include <libmcclient/mc-errors.h>
@@ -61,9 +64,9 @@ G_DEFINE_TYPE (McdDispatcher, mcd_dispatcher, MCD_TYPE_MISSION);
struct _McdDispatcherContext
{
McdDispatcher *dispatcher;
-
- /*The actual channel */
- McdChannel *channel;
+
+ GList *channels;
+ GPtrArray *channels_dbus;
gchar *protocol;
@@ -81,9 +84,9 @@ typedef struct _McdDispatcherArgs
GPtrArray *channel_handler_caps;
} McdDispatcherArgs;
-#define MCD_FILTER_CHANNEL_TYPE 0x1
-#define MCD_FILTER_HANDLE_TYPE 0x2
-#define MCD_FILTER_REQUESTED 0x4
+#define MCD_CLIENT_FILTER_CHANNEL_TYPE 0x1
+#define MCD_CLIENT_FILTER_HANDLE_TYPE 0x2
+#define MCD_CLIENT_FILTER_REQUESTED 0x4
typedef struct _McdClientFilter
{
guint field_mask;
@@ -613,12 +616,12 @@ _mcd_dispatcher_handle_channel_async_cb (DBusGProxy * proxy, GError * error,
"Handle channel failed: %s", error->message);
g_signal_emit_by_name (context->dispatcher, "dispatch-failed",
- context->channel, mc_error);
+ channel, mc_error);
g_error_free (mc_error);
g_error_free (error);
- if (context->channel)
- mcd_mission_abort (MCD_MISSION (context->channel));
+ if (channel)
+ mcd_mission_abort (MCD_MISSION (channel));
return;
}
@@ -645,8 +648,8 @@ _mcd_dispatcher_handle_channel_async_cb (DBusGProxy * proxy, GError * error,
g_signal_connect (unique_name_proxy,
"destroy",
G_CALLBACK (_mcd_dispatcher_channel_handler_destroy_cb),
- context->channel);
- g_signal_connect (context->channel, "abort",
+ channel);
+ g_signal_connect (channel, "abort",
G_CALLBACK(disconnect_proxy_destry_cb),
unique_name_proxy);
}
@@ -656,11 +659,8 @@ _mcd_dispatcher_handle_channel_async_cb (DBusGProxy * proxy, GError * error,
mcd_dispatcher_context_free (context);
}
-/* Happens at the end of successful filter chain execution (empty chain
- * is always successful)
- */
static void
-_mcd_dispatcher_start_channel_handler (McdDispatcherContext * context)
+start_old_channel_handler (McdDispatcherContext *context)
{
McdChannelHandler *chandler;
McdDispatcherPrivate *priv;
@@ -778,22 +778,173 @@ _mcd_dispatcher_start_channel_handler (McdDispatcherContext * context)
}
}
+static gboolean
+match_filters (McdChannel *channel, GList *filters)
+{
+ gboolean matched = FALSE;
+ GList *list;
+
+ for (list = filters; list != NULL; list = list->next)
+ {
+ McdClientFilter *filter = list->data;
+
+ if (filter->field_mask & MCD_CLIENT_FILTER_CHANNEL_TYPE)
+ {
+ g_debug ("channel type: %u, filter %u",
+ mcd_channel_get_channel_type_quark (channel),
+ filter->channel_type);
+ if (mcd_channel_get_channel_type_quark (channel) !=
+ filter->channel_type)
+ continue;
+ }
+
+ if (filter->field_mask & MCD_CLIENT_FILTER_REQUESTED)
+ {
+ /* TODO */
+ }
+
+ if (filter->field_mask & MCD_CLIENT_FILTER_HANDLE_TYPE)
+ {
+ g_debug ("handle type: %u, filter %u",
+ mcd_channel_get_handle_type (channel),
+ filter->handle_type);
+ if (mcd_channel_get_handle_type (channel) != filter->handle_type)
+ continue;
+ }
+ matched = TRUE;
+ break;
+ }
+
+ return matched;
+}
+
+static void
+handle_channels_cb (TpProxy *proxy, const GError *error, gpointer user_data,
+ GObject *weak_object)
+{
+ McdDispatcherContext *context = user_data;
+ McdChannel *channel;
+
+ /* TODO: don't assume we have only one channel */
+ channel = mcd_dispatcher_context_get_channel (context);
+
+ if (error)
+ {
+ GError *mc_error = NULL;
+
+ g_warning ("%s got error: %s", G_STRFUNC, error->message);
+
+ /* We can't reliably map channel handler error codes to MC error
+ * codes. So just using generic error message.
+ */
+ mc_error = g_error_new (MC_ERROR, MC_CHANNEL_REQUEST_GENERIC_ERROR,
+ "Handle channel failed: %s", error->message);
+
+ g_signal_emit_by_name (context->dispatcher, "dispatch-failed",
+ channel, mc_error);
+
+ g_error_free (mc_error);
+ mcd_mission_abort (MCD_MISSION (channel));
+ return;
+ }
+
+ /* TODO: abort the channel if the handler dies */
+
+ g_signal_emit_by_name (context->dispatcher, "dispatched", channel);
+ mcd_dispatcher_context_free (context);
+}
+
+static void
+mcd_dispatcher_run_handler (McdDispatcherContext *context)
+{
+ McdDispatcherPrivate *priv = MCD_DISPATCHER_PRIV (context->dispatcher);
+ McdClient *handler = NULL;
+ GList *list;
+
+ /* TODO: in the McdDispatcherContext there should be a hint on what handler
+ * to invoke */
+ for (list = priv->clients; list != NULL; list = list->next)
+ {
+ McdClient *client = list->data;
+ McdChannel *channel;
+
+ /* TODO: support more than one channel */
+ channel = mcd_dispatcher_context_get_channel (context);
+
+ if (client->proxy &&
+ client->interfaces & MCD_CLIENT_HANDLER &&
+ match_filters (channel, client->handler_filters))
+ {
+ handler = client;
+ break;
+ }
+ }
+
+ if (handler)
+ {
+ guint64 user_action_time;
+ McdConnection *connection;
+ McdAccount *account;
+ const gchar *account_path, *connection_path;
+ GPtrArray *channels, *satisfied_requests;
+
+ connection = mcd_dispatcher_context_get_connection (context);
+ g_assert (connection != NULL);
+ connection_path = mcd_connection_get_object_path (connection);
+
+ account = mcd_connection_get_account (connection);
+ g_assert (account != NULL);
+ account_path = mcd_account_get_object_path (account);
+
+ channels = mcd_dispatcher_context_get_channels_dbus (context);
+
+ satisfied_requests = g_ptr_array_new (); /* TODO */
+ user_action_time = 0; /* TODO: if we have a CDO, get it from there */
+ mc_cli_client_handler_call_handle_channels (handler->proxy, -1,
+ account_path, connection_path,
+ channels, satisfied_requests, user_action_time,
+ handle_channels_cb, context, NULL, (GObject *)context->dispatcher);
+
+ g_ptr_array_free (satisfied_requests, TRUE);
+ }
+ else
+ {
+ g_debug ("Client.Handler not found, invoking old-style handler");
+ start_old_channel_handler (context);
+ }
+}
+
+/* Happens at the end of successful filter chain execution (empty chain
+ * is always successful)
+ */
+static void
+mcd_dispatcher_run_clients (McdDispatcherContext *context)
+{
+ /* TODO: start observers */
+
+ /* TODO: for non requested channels, start approvers */
+
+ mcd_dispatcher_run_handler (context);
+}
+
static void
_mcd_dispatcher_drop_channel_handler (McdDispatcherContext * context)
{
+ McdChannel *channel;
+
g_return_if_fail(context);
-
+
/* drop from the queue and close channel */
/* FIXME: The queue functionality is still missing. Add support for
it, once it's available. */
-
- if (context->channel != NULL)
+ channel = mcd_dispatcher_context_get_channel (context);
+ if (channel != NULL)
{
/* Context will be destroyed on this emission, so be careful
* not to access it after this.
*/
- mcd_mission_abort (MCD_MISSION (context->channel));
+ mcd_mission_abort (MCD_MISSION (channel));
}
}
@@ -846,7 +997,7 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
/* Preparing and filling the context */
context = g_new0 (McdDispatcherContext, 1);
context->dispatcher = dispatcher;
- context->channel = channel;
+ context->channels = g_list_prepend (NULL, channel);
context->chain = chain;
/* Context must be destroyed when the channel is destroyed */
@@ -866,14 +1017,14 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
else
{
g_debug ("No filters found for type %s, starting the channel handler", g_quark_to_string (chan_type_quark));
- _mcd_dispatcher_start_channel_handler (context);
+ mcd_dispatcher_run_clients (context);
}
}
static gint
channel_on_state_machine (McdDispatcherContext *context, McdChannel *channel)
{
- return (context->channel == channel) ? 0 : 1;
+ return (mcd_dispatcher_context_get_channel (context) == channel) ? 0 : 1;
}
static void
@@ -927,7 +1078,7 @@ _mcd_dispatcher_send (McdDispatcher * dispatcher, McdChannel * channel)
* machine state list ourselves.
* The filters should connect to the "dispatched" signal to
* catch this particular situation and clean-up gracefully. */
- _mcd_dispatcher_start_channel_handler (context);
+ mcd_dispatcher_run_clients (context);
priv->state_machine_list =
g_slist_remove(priv->state_machine_list, context);
@@ -944,12 +1095,12 @@ _mcd_dispatcher_send (McdDispatcher * dispatcher, McdChannel * channel)
/* Preparing and filling the context */
context = g_new0 (McdDispatcherContext, 1);
context->dispatcher = dispatcher;
- context->channel = channel;
+ context->channels = g_list_prepend (NULL, channel);
/* We must ref() the channel, because mcd_dispatcher_context_free()
* will unref() it */
g_object_ref (channel);
- _mcd_dispatcher_start_channel_handler (context);
+ mcd_dispatcher_run_clients (context);
}
return;
}
@@ -1097,19 +1248,19 @@ parse_client_filter (GKeyFile *file, const gchar *group)
filter->channel_type = g_quark_from_string (string);
g_free (string);
- filter->field_mask |= MCD_FILTER_CHANNEL_TYPE;
+ filter->field_mask |= MCD_CLIENT_FILTER_CHANNEL_TYPE;
}
else if (strcmp (key, TP_IFACE_CHANNEL ".TargetHandleType u") == 0)
{
filter->handle_type =
(guint) g_key_file_get_integer (file, group, key, NULL);
- filter->field_mask |= MCD_FILTER_HANDLE_TYPE;
+ filter->field_mask |= MCD_CLIENT_FILTER_HANDLE_TYPE;
}
else if (strcmp (key, TP_IFACE_CHANNEL ".Requested b") == 0)
{
filter->requested =
g_key_file_get_boolean (file, group, key, NULL);
- filter->field_mask |= MCD_FILTER_REQUESTED;
+ filter->field_mask |= MCD_CLIENT_FILTER_REQUESTED;
}
else
{
@@ -1136,6 +1287,8 @@ create_client_proxy (McdDispatcherPrivate *priv, McdClient *client)
"object-path", object_path,
"bus-name", bus_name,
NULL);
+ /* call this empty auto-generated function or it will be unused */
+ mc_cli_client_add_signals(NULL, 0, NULL, NULL);
g_free (object_path);
g_free (bus_name);
@@ -1399,7 +1552,7 @@ mcd_dispatcher_context_process (McdDispatcherContext * context, gboolean result)
else
{
/* Context would be destroyed somewhere in this call */
- _mcd_dispatcher_start_channel_handler (context);
+ mcd_dispatcher_run_clients (context);
}
}
else
@@ -1419,16 +1572,29 @@ mcd_dispatcher_context_process (McdDispatcherContext * context, gboolean result)
static void
mcd_dispatcher_context_free (McdDispatcherContext * context)
{
+ GList *list;
+ GValue value = { 0, };
+
/* FIXME: check for leaks */
g_return_if_fail (context);
/* Freeing context data */
- if (context->channel)
+ for (list = context->channels; list != NULL; list = list->next)
{
- g_signal_handlers_disconnect_by_func (context->channel,
+ McdChannel *channel = MCD_CHANNEL (list->data);
+ g_signal_handlers_disconnect_by_func (channel,
G_CALLBACK (on_channel_abort_context),
context);
- g_object_unref (context->channel);
+ g_object_unref (channel);
+ }
+ g_list_free (context->channels);
+
+ /* to free the array of channels_dbus, put it into a GValue */
+ if (context->channels_dbus)
+ {
+ g_value_init (&value, MC_ARRAY_TYPE_CHANNEL_DETAILS_LIST);
+ g_value_take_boxed (&value, context->channels_dbus);
+ g_value_unset (&value);
}
g_free (context->protocol);
g_free (context);
@@ -1442,7 +1608,8 @@ mcd_dispatcher_context_get_channel_object (McdDispatcherContext * ctx)
{
TpChannel *tp_chan;
g_return_val_if_fail (ctx, 0);
- g_object_get (G_OBJECT (ctx->channel), "tp-channel", &tp_chan, NULL);
+ g_object_get (G_OBJECT (mcd_dispatcher_context_get_channel (ctx)),
+ "tp-channel", &tp_chan, NULL);
g_object_unref (G_OBJECT (tp_chan));
return tp_chan;
}
@@ -1453,19 +1620,19 @@ mcd_dispatcher_context_get_dispatcher (McdDispatcherContext * ctx)
return ctx->dispatcher;
}
+/**
+ * mcd_dispatcher_context_get_connection:
+ * @context: the #McdDispatcherContext.
+ *
+ * Returns: the #McdConnection.
+ */
McdConnection *
-mcd_dispatcher_context_get_connection (McdDispatcherContext * context)
+mcd_dispatcher_context_get_connection (McdDispatcherContext *context)
{
- McdConnection *connection;
-
g_return_val_if_fail (context, NULL);
-
- g_object_get (G_OBJECT (context->channel),
- "connection", &connection,
- NULL);
- g_object_unref (G_OBJECT (connection));
-
- return connection;
+ g_return_val_if_fail (context->channels != NULL, NULL);
+ return MCD_CONNECTION (mcd_mission_get_parent
+ (MCD_MISSION (context->channels->data)));
}
TpConnection *
@@ -1486,7 +1653,7 @@ McdChannel *
mcd_dispatcher_context_get_channel (McdDispatcherContext * ctx)
{
g_return_val_if_fail (ctx, 0);
- return ctx->channel;
+ return ctx->channels ? MCD_CHANNEL (ctx->channels->data) : NULL;
}
McdChannelHandler *
@@ -1517,7 +1684,7 @@ mcd_dispatcher_context_get_chan_handler (McdDispatcherContext * ctx)
GPtrArray *
mcd_dispatcher_context_get_members (McdDispatcherContext * ctx)
{
- return mcd_channel_get_members (ctx->channel);
+ return mcd_channel_get_members (mcd_dispatcher_context_get_channel (ctx));
}
GPtrArray *mcd_dispatcher_get_channel_capabilities (McdDispatcher * dispatcher,
@@ -1553,3 +1720,48 @@ mcd_dispatcher_context_get_protocol_name (McdDispatcherContext *context)
return context->protocol;
}
+static void
+mcd_dispatcher_context_build_channels_dbus (McdDispatcherContext *context)
+{
+ GPtrArray *channels;
+ GList *list;
+
+ channels = g_ptr_array_sized_new (g_list_length (context->channels));
+ for (list = context->channels; list != NULL; list = list->next)
+ {
+ McdChannel *channel = MCD_CHANNEL (list->data);
+ GHashTable *properties;
+ GValue channel_val = { 0, };
+ GType type;
+
+ properties = _mcd_channel_get_immutable_properties (channel);
+
+ type = MC_STRUCT_TYPE_CHANNEL_DETAILS;
+ g_value_init (&channel_val, type);
+ g_value_take_boxed (&channel_val,
+ dbus_g_type_specialized_construct (type));
+ dbus_g_type_struct_set (&channel_val,
+ 0, mcd_channel_get_object_path (channel),
+ 1, properties,
+ G_MAXUINT);
+
+ g_ptr_array_add (channels, g_value_get_boxed (&channel_val));
+ }
+
+ context->channels_dbus = channels;
+}
+
+/**
+ * mcd_dispatcher_context_get_channels_dbus:
+ * @context: the #McdDispatcherContext.
+ *
+ * Returns: the a(oa{sv}) of channels.
+ */
+GPtrArray *
+mcd_dispatcher_context_get_channels_dbus (McdDispatcherContext *context)
+{
+ if (!context->channels_dbus)
+ mcd_dispatcher_context_build_channels_dbus (context);
+ return context->channels_dbus;
+}
+
--
1.5.6.5
More information about the Telepathy-commits
mailing list