~ubuntu-branches/ubuntu/precise/telepathy-mission-control-5/precise

« back to all changes in this revision

Viewing changes to src/mcd-dispatch-operation.c

Tags: upstream-5.5.2
ImportĀ upstreamĀ versionĀ 5.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
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"
50
53
 
51
54
#include <libmcclient/mc-errors.h>
52
55
 
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;
 
259
 
 
260
    McdPluginDispatchOperation *plugin_api;
 
261
    gsize plugins_pending;
 
262
    gboolean did_post_observer_actions;
256
263
};
257
264
 
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);
364
373
 
365
374
static void
366
375
_mcd_dispatch_operation_check_client_locks (McdDispatchOperation *self)
367
376
{
368
377
    Approval *approval;
369
378
 
 
379
    if (!self->priv->invoked_observers_if_needed)
 
380
    {
 
381
        DEBUG ("waiting for Observers to be called");
 
382
        return;
 
383
    }
 
384
 
 
385
    if (self->priv->plugins_pending > 0)
 
386
    {
 
387
        DEBUG ("waiting for plugins to stop delaying");
 
388
        return;
 
389
    }
 
390
 
 
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)
 
395
    {
 
396
        _mcd_plugin_dispatch_operation_observers_finished (
 
397
            self->priv->plugin_api);
 
398
        self->priv->did_post_observer_actions = TRUE;
 
399
    }
 
400
 
 
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
 
404
     * do this.)
 
405
     *
 
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))
 
413
    {
 
414
        self->priv->tried_handlers_before_approval = TRUE;
 
415
 
 
416
        g_idle_add_full (G_PRIORITY_HIGH,
 
417
                         mcd_dispatch_operation_idle_run_approvers,
 
418
                         g_object_ref (self), g_object_unref);
 
419
    }
 
420
 
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)
374
424
    {
375
 
        DEBUG ("waiting for Observers");
376
425
        return;
377
426
    }
378
427
 
501
550
 * Returns: the D-Bus object path of the Connection associated with @self,
502
551
 *    or "/" if none.
503
552
 */
504
 
static const gchar *
 
553
const gchar *
505
554
_mcd_dispatch_operation_get_connection_path (McdDispatchOperation *self)
506
555
{
507
556
    const gchar *path;
530
579
            MCD_DISPATCH_OPERATION (self)));
531
580
}
532
581
 
 
582
const gchar *
 
583
_mcd_dispatch_operation_get_cm_name (McdDispatchOperation *self)
 
584
{
 
585
    const gchar *ret;
 
586
 
 
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);
 
591
    return ret;
 
592
}
 
593
 
 
594
const gchar *
 
595
_mcd_dispatch_operation_get_protocol (McdDispatchOperation *self)
 
596
{
 
597
    const gchar *ret;
 
598
 
 
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);
 
603
    return ret;
 
604
}
 
605
 
533
606
/*
534
607
 * _mcd_dispatch_operation_get_account_path:
535
608
 * @operation: the #McdDispatchOperation.
537
610
 * Returns: the D-Bus object path of the Account associated with @operation,
538
611
 *    or "/" if none.
539
612
 */
540
 
static const gchar *
 
613
const gchar *
541
614
_mcd_dispatch_operation_get_account_path (McdDispatchOperation *self)
542
615
{
543
616
    const gchar *path;
663
736
    }
664
737
 
665
738
    va_start (ap, format);
666
 
    priv->result = _mcd_g_error_new_valist (domain, code, format, ap);
 
739
    priv->result = g_error_new_valist (domain, code, format, ap);
667
740
    va_end (ap);
668
741
    DEBUG ("Result: %s", priv->result->message);
669
742
 
696
769
                    {
697
770
                        DEBUG ("successful HandleWith, channel went to %s",
698
771
                               successful_handler);
 
772
 
 
773
                        /* HandleWith and HandleWithTime both return void, so
 
774
                         * it's OK to not distinguish */
699
775
                        tp_svc_channel_dispatch_operation_return_from_handle_with (
700
776
                            approval->context);
701
777
                    }
745
821
    McdDispatchOperation *self, const gchar *handler_name, GError **error);
746
822
 
747
823
static void
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)
751
828
{
752
829
    GError *error = NULL;
753
830
    McdDispatchOperation *self = MCD_DISPATCH_OPERATION (cdo);
761
838
        return;
762
839
    }
763
840
 
 
841
    self->priv->handle_with_time = user_action_timestamp;
 
842
 
 
843
    g_queue_push_tail (self->priv->approvals,
 
844
                       approval_new_handle_with (handler_name, context));
 
845
    _mcd_dispatch_operation_check_client_locks (self);
 
846
}
 
847
 
 
848
static void
 
849
dispatch_operation_handle_with (TpSvcChannelDispatchOperation *cdo,
 
850
    const gchar *handler_name,
 
851
    DBusGMethodInvocation *context)
 
852
{
764
853
    /* 0 is a special case for 'no user action' */
765
 
    self->priv->handle_with_time = 0;
766
 
 
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);
770
855
}
771
856
 
772
857
static void
800
885
    iface, dispatch_operation_##x)
801
886
    IMPLEMENT(handle_with);
802
887
    IMPLEMENT(claim);
 
888
    IMPLEMENT(handle_with_time);
803
889
#undef IMPLEMENT
804
890
}
805
891
 
883
969
        g_object_unref (dbus_daemon);
884
970
    }
885
971
 
 
972
    priv->plugin_api = _mcd_plugin_dispatch_operation_new (operation);
 
973
 
886
974
    return object;
887
975
error:
888
976
    g_object_unref (object);
1093
1181
    McdDispatchOperationPrivate *priv = MCD_DISPATCH_OPERATION_PRIV (object);
1094
1182
    GList *list;
1095
1183
 
 
1184
    if (priv->plugin_api != NULL)
 
1185
    {
 
1186
        g_object_unref (priv->plugin_api);
 
1187
        priv->plugin_api = NULL;
 
1188
    }
 
1189
 
1096
1190
    if (priv->successful_handler != NULL)
1097
1191
    {
1098
1192
        g_object_unref (priv->successful_handler);
1999
2093
 
2000
2094
    if (self->priv->channels != NULL)
2001
2095
    {
 
2096
        const GList *mini_plugins;
 
2097
 
 
2098
        DEBUG ("Running observers");
2002
2099
        _mcd_dispatch_operation_run_observers (self);
 
2100
 
 
2101
        for (mini_plugins = mcp_list_objects ();
 
2102
             mini_plugins != NULL;
 
2103
             mini_plugins = mini_plugins->next)
 
2104
        {
 
2105
            if (MCP_IS_DISPATCH_OPERATION_POLICY (mini_plugins->data))
 
2106
            {
 
2107
                mcp_dispatch_operation_policy_check (mini_plugins->data,
 
2108
                    MCP_DISPATCH_OPERATION (self->priv->plugin_api));
 
2109
            }
 
2110
        }
2003
2111
    }
2004
2112
 
2005
2113
    DEBUG ("All necessary observers invoked");
2006
2114
    self->priv->invoked_observers_if_needed = TRUE;
2007
 
    /* we call check_finished before returning */
2008
 
 
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
2012
 
     * do this.)
2013
 
     *
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)
2018
 
    {
2019
 
        self->priv->tried_handlers_before_approval = TRUE;
2020
 
 
2021
 
        g_idle_add_full (G_PRIORITY_HIGH,
2022
 
                         mcd_dispatch_operation_idle_run_approvers,
2023
 
                         g_object_ref (self), g_object_unref);
2024
 
    }
2025
2115
 
2026
2116
    DEBUG ("Checking finished/locks");
2027
2117
    _mcd_dispatch_operation_check_finished (self);
2154
2244
 
2155
2245
    g_list_free (channels);
2156
2246
}
 
2247
 
 
2248
void
 
2249
_mcd_dispatch_operation_start_plugin_delay (McdDispatchOperation *self)
 
2250
{
 
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++;
 
2256
}
 
2257
 
 
2258
void
 
2259
_mcd_dispatch_operation_end_plugin_delay (McdDispatchOperation *self)
 
2260
{
 
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--;
 
2266
 
 
2267
    _mcd_dispatch_operation_check_client_locks (self);
 
2268
    g_object_unref (self);
 
2269
}
 
2270
 
 
2271
void
 
2272
_mcd_dispatch_operation_forget_channels (McdDispatchOperation *self)
 
2273
{
 
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);
 
2278
 
 
2279
    while (list != NULL)
 
2280
    {
 
2281
        mcd_mission_abort (list->data);
 
2282
        g_object_unref (list->data);
 
2283
        list = g_list_delete_link (list, list);
 
2284
    }
 
2285
 
 
2286
    /* There should now be none left (they all aborted) */
 
2287
    g_return_if_fail (self->priv->channels == NULL);
 
2288
}
 
2289
 
 
2290
void
 
2291
_mcd_dispatch_operation_leave_channels (McdDispatchOperation *self,
 
2292
                                        TpChannelGroupChangeReason reason,
 
2293
                                        const gchar *message)
 
2294
{
 
2295
    GList *list;
 
2296
 
 
2297
    if (message == NULL)
 
2298
    {
 
2299
        message = "";
 
2300
    }
 
2301
 
 
2302
    list = _mcd_dispatch_operation_dup_channels (self);
 
2303
 
 
2304
    while (list != NULL)
 
2305
    {
 
2306
        _mcd_channel_depart (list->data, reason, message);
 
2307
        g_object_unref (list->data);
 
2308
        list = g_list_delete_link (list, list);
 
2309
    }
 
2310
 
 
2311
    _mcd_dispatch_operation_forget_channels (self);
 
2312
}
 
2313
 
 
2314
void
 
2315
_mcd_dispatch_operation_close_channels (McdDispatchOperation *self)
 
2316
{
 
2317
    GList *list = _mcd_dispatch_operation_dup_channels (self);
 
2318
 
 
2319
    while (list != NULL)
 
2320
    {
 
2321
        _mcd_channel_close (list->data);
 
2322
        g_object_unref (list->data);
 
2323
        list = g_list_delete_link (list, list);
 
2324
    }
 
2325
 
 
2326
    _mcd_dispatch_operation_forget_channels (self);
 
2327
}
 
2328
 
 
2329
void
 
2330
_mcd_dispatch_operation_destroy_channels (McdDispatchOperation *self)
 
2331
{
 
2332
    GList *list = _mcd_dispatch_operation_dup_channels (self);
 
2333
 
 
2334
    while (list != NULL)
 
2335
    {
 
2336
        _mcd_channel_undispatchable (list->data);
 
2337
        g_object_unref (list->data);
 
2338
        list = g_list_delete_link (list, list);
 
2339
    }
 
2340
 
 
2341
    _mcd_dispatch_operation_forget_channels (self);
 
2342
}