static gboolean
delayed_abort (gpointer data G_GNUC_UNUSED)
{
    g_message ("Aborting by popular request");
    mcd_mission_abort ((McdMission *) mcd);
    return FALSE;
}
static void
_mcd_channel_request_cancelling_cb (McdRequest *request,
                                    McdChannel *self)
{
    McdChannelStatus status = mcd_channel_get_status (self);

    g_object_ref (self);
    DEBUG ("%p in status %u", self, status);

    mcd_channel_take_error (self, g_error_new (TP_ERROR,
                                               TP_ERROR_CANCELLED,
                                               "Cancelled"));

    /* If we're coming from state REQUEST, the call to the CM hasn't
     * happened yet; now that we're in state FAILED, it never will,
     * because mcd_connection_request_channel() now checks that.
     *
     * If we're coming from state REQUESTED, we need to close the channel
     * when the CM tells us where it is, so we can't now.
     *
     * If we're coming from state DISPATCHING, we need to shoot it down
     * now.
     *
     * Anything else is too late.
     */
    if (status == MCD_CHANNEL_STATUS_DISPATCHING)
    {
        _mcd_channel_close (self);
        mcd_mission_abort ((McdMission *) self);
    }

    g_object_unref (self);
}
static void
copy_status (McdChannel *source, McdChannel *dest)
{
    McdChannelPrivate *src_priv, *dst_priv;

    src_priv = source->priv;
    dst_priv = dest->priv;
    if (dst_priv->status != src_priv->status)
    {
        DEBUG ("source is %d, dest is %d", src_priv->status, dst_priv->status);
        if (src_priv->status == MCD_CHANNEL_STATUS_FAILED)
        {
            const GError *error;

            error = mcd_channel_get_error (source);
            /* this also takes care of setting the status */
            mcd_channel_take_error (dest, g_error_copy (error));
        }
        else
            _mcd_channel_set_status (dest, src_priv->status);
    }

    if (dst_priv->status == MCD_CHANNEL_STATUS_FAILED ||
        dst_priv->status == MCD_CHANNEL_STATUS_DISPATCHED)
    {
        /* the request is completed, we are not interested in monitor the
         * channel anymore */
        g_signal_handlers_disconnect_by_func
            (source, on_proxied_channel_status_changed, dest);
        mcd_mission_abort (MCD_MISSION (dest));
    }
}
static void
_mcd_operation_abort (McdOperation * operation)
{
    const GList *node;
    
    DEBUG ("Operation abort received, aborting all children");
    node = MCD_OPERATION_PRIV (operation)->missions;
    while (node)
    {
	McdMission *mission = MCD_MISSION (node->data);
	/* We don't want to hear it ourself so that we still hold the
	 * final reference to our children.
	 */
	g_signal_handlers_disconnect_by_func (mission,
					      G_CALLBACK (on_mission_abort),
					      operation);
	mcd_mission_abort (mission);
	
	/* Restore the handler so that we continue listing for destroy
	 * notify for our children.
	 */
	g_signal_connect (mission, "abort",
			  G_CALLBACK (on_mission_abort), operation);
	node = g_list_next (node);
    }
}
static void
proxy_destroyed (TpProxy *self, guint domain, gint code, gchar *message,
		 gpointer user_data)
{
    McdChannel *channel = user_data;

    DEBUG ("Channel proxy invalidated: %s %d: %s",
           g_quark_to_string (domain), code, message);
    mcd_mission_abort (MCD_MISSION (channel));
}
static gboolean
_mcd_master_exit_by_timeout (gpointer data)
{
    McdMaster *self = MCD_MASTER (data);
    McdMasterPrivate *priv = MCD_MASTER_PRIV (self);

    priv->shutdown_timeout_id = 0;

    /* Notify sucide */
    mcd_mission_abort (MCD_MISSION (self));
    return FALSE;
}
static DBusHandlerResult
dbus_filter_function (DBusConnection *connection,
                      DBusMessage *message,
                      void *user_data)
{
  if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected") &&
      !tp_strdiff (dbus_message_get_path (message), DBUS_PATH_LOCAL))
    {
      /* MC initialization sets exit on disconnect - turn it off again, so we
       * get a graceful exit instead (to keep gcov happy) */
      dbus_connection_set_exit_on_disconnect (connection, FALSE);

      g_message ("Got disconnected from the session bus");

      mcd_mission_abort ((McdMission *) mcd);
    }
  else if (dbus_message_is_method_call (message,
        "org.freedesktop.Telepathy.MissionControl5.RegressionTests",
        "Abort"))
    {
      DBusMessage *reply;

      g_idle_add (delayed_abort, NULL);

      reply = dbus_message_new_method_return (message);

      if (reply == NULL || !dbus_connection_send (connection, reply, NULL))
        g_error ("Out of memory");

      dbus_message_unref (reply);

      return DBUS_HANDLER_RESULT_HANDLED;
    }
  else if (dbus_message_is_method_call (message,
        "org.freedesktop.Telepathy.MissionControl5.RegressionTests",
        "BillyIdle"))
    {
      /* Used to drive a souped-up version of sync_dbus(), where we need to
       * ensure that all idles have fired, on top of the D-Bus queue being
       * drained.
       */
      DBusMessage *reply = dbus_message_new_method_return (message);
      GVariant *variant;
      GDBusConnection *system_bus;

      if (reply == NULL)
        g_error ("Out of memory");

      /* Sync GDBus, too, to make sure we have received any pending
       * FakeNetworkMonitor messages. */
      system_bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
      g_assert (system_bus != NULL);
      variant = g_dbus_connection_call_sync (system_bus,
          "org.freedesktop.DBus", "/org/freedesktop/DBus",
          "org.freedesktop.DBus", "ListNames",
          NULL, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
      g_assert (variant != NULL);
      g_variant_unref (variant);
      g_object_unref (system_bus);

      g_idle_add_full (G_PRIORITY_LOW, billy_idle, reply,
          (GDestroyNotify) dbus_message_unref);

      return DBUS_HANDLER_RESULT_HANDLED;
    }

  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}