46
46
#include "channel-utils.h"
47
47
#include "mcd-channel-priv.h"
48
48
#include "mcd-dbusprop.h"
49
#include "mcd-master-priv.h"
49
50
#include "mcd-misc.h"
51
#include "plugin-dispatch-operation.h"
52
#include "plugin-loader.h"
51
54
#include <libmcclient/mc-errors.h>
253
256
/* If TRUE, we've tried all the BypassApproval handlers, which happens
254
257
* before we run approvers. */
255
258
gboolean tried_handlers_before_approval;
260
McdPluginDispatchOperation *plugin_api;
261
gsize plugins_pending;
262
gboolean did_post_observer_actions;
258
265
static void _mcd_dispatch_operation_check_finished (
361
368
static gboolean mcd_dispatch_operation_idle_run_approvers (gpointer p);
362
369
static void mcd_dispatch_operation_set_channel_handled_by (
363
370
McdDispatchOperation *self, McdChannel *channel, const gchar *unique_name);
371
static gboolean _mcd_dispatch_operation_handlers_can_bypass_approval (
372
McdDispatchOperation *self);
366
375
_mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
368
377
Approval *approval;
379
if (!self->priv->invoked_observers_if_needed)
381
DEBUG ("waiting for Observers to be called");
385
if (self->priv->plugins_pending > 0)
387
DEBUG ("waiting for plugins to stop delaying");
391
/* Check whether plugins' requests to close channels later should be
392
* honoured. We want to do this before running Approvers (if any). */
393
if (self->priv->observers_pending == 0 &&
394
!self->priv->did_post_observer_actions)
396
_mcd_plugin_dispatch_operation_observers_finished (
397
self->priv->plugin_api);
398
self->priv->did_post_observer_actions = TRUE;
401
/* If nobody is bypassing approval, then we want to run approvers as soon
402
* as possible, without waiting for observers, to improve responsiveness.
403
* (The regression test dispatcher/exploding-bundles.py asserts that we
406
* However, if a handler bypasses approval, we must wait til the observers
407
* return, then run that handler, then proceed with the other handlers. */
408
if (!self->priv->tried_handlers_before_approval &&
409
!_mcd_dispatch_operation_handlers_can_bypass_approval (self)
410
&& self->priv->channels != NULL &&
411
! _mcd_plugin_dispatch_operation_will_terminate (
412
self->priv->plugin_api))
414
self->priv->tried_handlers_before_approval = TRUE;
416
g_idle_add_full (G_PRIORITY_HIGH,
417
mcd_dispatch_operation_idle_run_approvers,
418
g_object_ref (self), g_object_unref);
370
421
/* we may not continue until we've called all the Observers, and they've
371
422
* all replied "I'm ready" */
372
if (!self->priv->invoked_observers_if_needed ||
373
self->priv->observers_pending > 0)
423
if (self->priv->observers_pending > 0)
375
DEBUG ("waiting for Observers");
530
579
MCD_DISPATCH_OPERATION (self)));
583
_mcd_dispatch_operation_get_cm_name (McdDispatchOperation *self)
587
g_return_val_if_fail (MCD_IS_DISPATCH_OPERATION (self), NULL);
588
g_return_val_if_fail (self->priv->account != NULL, NULL);
589
ret = mcd_account_get_manager_name (self->priv->account);
590
g_return_val_if_fail (ret != NULL, NULL);
595
_mcd_dispatch_operation_get_protocol (McdDispatchOperation *self)
599
g_return_val_if_fail (MCD_IS_DISPATCH_OPERATION (self), NULL);
600
g_return_val_if_fail (self->priv->account != NULL, NULL);
601
ret = mcd_account_get_protocol_name (self->priv->account);
602
g_return_val_if_fail (ret != NULL, NULL);
534
607
* _mcd_dispatch_operation_get_account_path:
535
608
* @operation: the #McdDispatchOperation.
745
821
McdDispatchOperation *self, const gchar *handler_name, GError **error);
748
dispatch_operation_handle_with (TpSvcChannelDispatchOperation *cdo,
749
const gchar *handler_name,
750
DBusGMethodInvocation *context)
824
dispatch_operation_handle_with_time (TpSvcChannelDispatchOperation *cdo,
825
const gchar *handler_name,
826
gint64 user_action_timestamp,
827
DBusGMethodInvocation *context)
752
829
GError *error = NULL;
753
830
McdDispatchOperation *self = MCD_DISPATCH_OPERATION (cdo);
841
self->priv->handle_with_time = user_action_timestamp;
843
g_queue_push_tail (self->priv->approvals,
844
approval_new_handle_with (handler_name, context));
845
_mcd_dispatch_operation_check_client_locks (self);
849
dispatch_operation_handle_with (TpSvcChannelDispatchOperation *cdo,
850
const gchar *handler_name,
851
DBusGMethodInvocation *context)
764
853
/* 0 is a special case for 'no user action' */
765
self->priv->handle_with_time = 0;
767
g_queue_push_tail (self->priv->approvals,
768
approval_new_handle_with (handler_name, context));
769
_mcd_dispatch_operation_check_client_locks (self);
854
dispatch_operation_handle_with_time (cdo, handler_name, 0, context);
2000
2094
if (self->priv->channels != NULL)
2096
const GList *mini_plugins;
2098
DEBUG ("Running observers");
2002
2099
_mcd_dispatch_operation_run_observers (self);
2101
for (mini_plugins = mcp_list_objects ();
2102
mini_plugins != NULL;
2103
mini_plugins = mini_plugins->next)
2105
if (MCP_IS_DISPATCH_OPERATION_POLICY (mini_plugins->data))
2107
mcp_dispatch_operation_policy_check (mini_plugins->data,
2108
MCP_DISPATCH_OPERATION (self->priv->plugin_api));
2005
2113
DEBUG ("All necessary observers invoked");
2006
2114
self->priv->invoked_observers_if_needed = TRUE;
2007
/* we call check_finished before returning */
2009
/* If nobody is bypassing approval, then we want to run approvers as soon
2010
* as possible, without waiting for observers, to improve responsiveness.
2011
* (The regression test dispatcher/exploding-bundles.py asserts that we
2014
* However, if a handler bypasses approval, we must wait til the observers
2015
* return, then run that handler, then proceed with the other handlers. */
2016
if (!_mcd_dispatch_operation_handlers_can_bypass_approval (self)
2017
&& self->priv->channels != NULL)
2019
self->priv->tried_handlers_before_approval = TRUE;
2021
g_idle_add_full (G_PRIORITY_HIGH,
2022
mcd_dispatch_operation_idle_run_approvers,
2023
g_object_ref (self), g_object_unref);
2026
2116
DEBUG ("Checking finished/locks");
2027
2117
_mcd_dispatch_operation_check_finished (self);
2155
2245
g_list_free (channels);
2249
_mcd_dispatch_operation_start_plugin_delay (McdDispatchOperation *self)
2251
g_object_ref (self);
2252
DEBUG ("%" G_GSIZE_FORMAT " -> %" G_GSIZE_FORMAT,
2253
self->priv->plugins_pending,
2254
self->priv->plugins_pending + 1);
2255
self->priv->plugins_pending++;
2259
_mcd_dispatch_operation_end_plugin_delay (McdDispatchOperation *self)
2261
DEBUG ("%" G_GSIZE_FORMAT " -> %" G_GSIZE_FORMAT,
2262
self->priv->plugins_pending,
2263
self->priv->plugins_pending - 1);
2264
g_return_if_fail (self->priv->plugins_pending > 0);
2265
self->priv->plugins_pending--;
2267
_mcd_dispatch_operation_check_client_locks (self);
2268
g_object_unref (self);
2272
_mcd_dispatch_operation_forget_channels (McdDispatchOperation *self)
2274
/* make a temporary copy, which is destroyed during the loop - otherwise
2275
* we'll be trying to iterate over the list at the same time
2276
* that mcd_mission_abort results in modifying it, which would be bad */
2277
GList *list = _mcd_dispatch_operation_dup_channels (self);
2279
while (list != NULL)
2281
mcd_mission_abort (list->data);
2282
g_object_unref (list->data);
2283
list = g_list_delete_link (list, list);
2286
/* There should now be none left (they all aborted) */
2287
g_return_if_fail (self->priv->channels == NULL);
2291
_mcd_dispatch_operation_leave_channels (McdDispatchOperation *self,
2292
TpChannelGroupChangeReason reason,
2293
const gchar *message)
2297
if (message == NULL)
2302
list = _mcd_dispatch_operation_dup_channels (self);
2304
while (list != NULL)
2306
_mcd_channel_depart (list->data, reason, message);
2307
g_object_unref (list->data);
2308
list = g_list_delete_link (list, list);
2311
_mcd_dispatch_operation_forget_channels (self);
2315
_mcd_dispatch_operation_close_channels (McdDispatchOperation *self)
2317
GList *list = _mcd_dispatch_operation_dup_channels (self);
2319
while (list != NULL)
2321
_mcd_channel_close (list->data);
2322
g_object_unref (list->data);
2323
list = g_list_delete_link (list, list);
2326
_mcd_dispatch_operation_forget_channels (self);
2330
_mcd_dispatch_operation_destroy_channels (McdDispatchOperation *self)
2332
GList *list = _mcd_dispatch_operation_dup_channels (self);
2334
while (list != NULL)
2336
_mcd_channel_undispatchable (list->data);
2337
g_object_unref (list->data);
2338
list = g_list_delete_link (list, list);
2341
_mcd_dispatch_operation_forget_channels (self);