[Telepathy-commits] [telepathy-mission-control/master] Invoke approvers

Alberto Mardegan alberto.mardegan at nokia.com
Mon Nov 3 05:58:12 PST 2008


If we have a CDO (i.e., the channels were not requested), invoke the approvers.
If the approver calls HandleWith, the result is ignored; invoking the preferred
handler is still to be done.
---
 src/mcd-dispatcher.c |  156 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 155 insertions(+), 1 deletions(-)

diff --git a/src/mcd-dispatcher.c b/src/mcd-dispatcher.c
index d5b0438..373ffbf 100644
--- a/src/mcd-dispatcher.c
+++ b/src/mcd-dispatcher.c
@@ -77,6 +77,9 @@ struct _McdDispatcherContext
      * When the variable gets back to 0, handlers are run. */
     gint client_locks;
 
+    /* Number of approvers that we invoked */
+    gint approvers_invoked;
+
     gchar *protocol;
 
     /* State-machine internal data fields: */
@@ -202,6 +205,8 @@ static void mcd_dispatcher_context_unref (McdDispatcherContext * ctx);
 static void mcd_dispatcher_context_set_channel (McdDispatcherContext *context,
                                                 McdChannel *channel);
 static void mcd_dispatcher_leave_state_machine (McdDispatcherContext *context);
+static void on_operation_finished (McdDispatchOperation *operation,
+                                   McdDispatcherContext *context);
 
 typedef void (*tp_ch_handle_channel_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
 
@@ -1199,6 +1204,101 @@ mcd_dispatcher_run_observers (McdDispatcherContext *context)
     }
 }
 
+/*
+ * mcd_dispatcher_context_approver_not_invoked:
+ * @context: the #McdDispatcherContext.
+ *
+ * This function is called when an approver returned error on
+ * AddDispatchOperation(), and is used to keep track of how many approvers we
+ * have contacted. If all of them fail, then we continue the dispatching.
+ */
+static void
+mcd_dispatcher_context_approver_not_invoked (McdDispatcherContext *context)
+{
+    g_return_if_fail (context->approvers_invoked > 0);
+    context->approvers_invoked--;
+
+    if (context->approvers_invoked == 0)
+        mcd_dispatcher_context_release_client_lock (context);
+}
+
+static void
+add_dispatch_operation_cb (TpProxy *proxy, const GError *error,
+                           gpointer user_data, GObject *weak_object)
+{
+    McdDispatcherContext *context = user_data;
+
+    if (error)
+    {
+        g_debug ("Failed to add DO on approver: %s", error->message);
+
+        /* if all approvers fail to add the DO, then we behave as if no
+         * approver was registered: i.e., we continue dispatching */
+        context->approvers_invoked--;
+        if (context->approvers_invoked == 0)
+            mcd_dispatcher_context_release_client_lock (context);
+    }
+}
+
+static void
+mcd_dispatcher_run_approvers (McdDispatcherContext *context)
+{
+    McdDispatcherPrivate *priv = context->dispatcher->priv;
+    McdClient *handler = NULL;
+    const GList *cl, *channels;
+    GList *list;
+
+    g_return_if_fail (context->operation != NULL);
+
+    /* we temporarily increment this count and decrement it at the end of the
+     * function, to make sure it won't become 0 while we are still invoking
+     * approvers */
+    context->approvers_invoked = 1;
+
+    context->client_locks++;
+    channels = context->channels;
+    for (list = priv->clients; list != NULL; list = list->next)
+    {
+        McdClient *client = list->data;
+        const gchar *dispatch_operation;
+        GHashTable *properties;
+        gboolean matched = FALSE;
+
+        if (!client->proxy ||
+            !(client->interfaces & MCD_CLIENT_APPROVER))
+            continue;
+
+        for (cl = channels; cl != NULL; cl = cl->next)
+        {
+            McdChannel *channel = MCD_CHANNEL (cl->data);
+
+            if (match_filters (channel, client->handler_filters))
+            {
+                matched = TRUE;
+                break;
+            }
+        }
+        if (!matched) continue;
+
+        dispatch_operation =
+            mcd_dispatch_operation_get_path (context->operation);
+        properties =
+            mcd_dispatch_operation_get_properties (context->operation);
+
+        context->approvers_invoked++;
+        mcd_dispatcher_context_ref (context);
+        mc_cli_client_approver_call_add_dispatch_operation (handler->proxy, -1,
+            dispatch_operation, properties,
+            add_dispatch_operation_cb,
+            context, (GDestroyNotify)mcd_dispatcher_context_unref,
+            (GObject *)context->dispatcher);
+    }
+
+    /* This matches the approvers count set to 1 at the beginning of the
+     * function */
+    mcd_dispatcher_context_approver_not_invoked (context);
+}
+
 /* Happens at the end of successful filter chain execution (empty chain
  * is always successful)
  */
@@ -1211,7 +1311,12 @@ mcd_dispatcher_run_clients (McdDispatcherContext *context)
 
     mcd_dispatcher_run_observers (context);
 
-    /* TODO: for non requested channels, start approvers */
+    if (context->operation)
+    {
+        /* if we have a dispatch operation, it means that the channels were not
+         * requested: start the Approvers */
+        mcd_dispatcher_run_approvers (context);
+    }
 
     mcd_dispatcher_context_release_client_lock (context);
     mcd_dispatcher_context_unref (context);
@@ -1264,6 +1369,46 @@ on_channel_abort_context (McdChannel *channel, McdDispatcherContext *context)
      */
 }
 
+static void
+on_operation_finished (McdDispatchOperation *operation,
+                       McdDispatcherContext *context)
+{
+    /* This is emitted when the HandleWith() or Claimed() are invoked on the
+     * CDO: according to which of these have happened, we run the choosen
+     * handler or we don't. */
+
+    if (mcd_dispatch_operation_is_claimed (operation))
+    {
+        GList *list;
+
+        /* we don't release the client lock, in order to not run the handlers.
+         * But we have to mark all channels as dispatched, and free the
+         * @context */
+        for (list = context->channels; list != NULL; list = list->next)
+        {
+            McdChannel *channel = MCD_CHANNEL (list->data);
+
+            /* TODO: abort the channel if the handler dies */
+            mcd_channel_set_status (channel, MCD_CHANNEL_DISPATCHED);
+            g_signal_emit_by_name (context->dispatcher, "dispatched", channel);
+        }
+
+        mcd_dispatcher_context_handler_done (context);
+    }
+    else
+    {
+        const gchar *handler;
+
+        handler = mcd_dispatch_operation_get_handler (operation);
+
+        /* TODO: set this handler as the preferred handler for the context */
+
+        /* this is the lock set in mcd_dispatcher_run_approvers(): releasing
+         * this will make the handlers run */
+        mcd_dispatcher_context_release_client_lock (context);
+    }
+}
+
 /* Entering the state machine */
 static void
 _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
@@ -1314,8 +1459,12 @@ _mcd_dispatcher_enter_state_machine (McdDispatcher *dispatcher,
     context->channels = channels;
     context->chain = chain;
     if (!requested)
+    {
         context->operation =
             _mcd_dispatch_operation_new (priv->dbus_daemon, channels);
+        g_signal_connect (context->operation, "finished",
+                          G_CALLBACK (on_operation_finished), context);
+    }
 
     for (list = channels; list != NULL; list = list->next)
     {
@@ -1950,7 +2099,12 @@ mcd_dispatcher_context_unref (McdDispatcherContext * context)
         }
         /* disposing the dispatch operation also frees the channels list */
         if (context->operation)
+        {
+            g_signal_handlers_disconnect_by_func (context->operation,
+                                                  on_operation_finished,
+                                                  context);
             g_object_unref (context->operation);
+        }
         else
             g_list_free (context->channels);
 
-- 
1.5.6.5




More information about the Telepathy-commits mailing list