static void
interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *variant = NULL;
	gs_free_error GError *error = NULL;
	const char *path;

	variant = _nm_dbus_proxy_call_finish (proxy, result,
	                                      G_VARIANT_TYPE ("(o)"),
	                                      &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (variant) {
		g_variant_get (variant, "(&o)", &path);
		interface_add_done (self, path);
	} else {
		g_dbus_error_strip_remote_error (error);
		nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s", priv->dev, error->message);
		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
	}
}
static void
iface_check_ap_mode_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *variant = NULL;
	gs_free_error GError *error = NULL;
	const char *data;

	/* The ProbeRequest method only exists if AP mode has been enabled */
	variant = _nm_dbus_proxy_call_finish (proxy, result,
	                                      G_VARIANT_TYPE ("(s)"),
	                                      &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (variant) {
		g_variant_get (variant, "(&s)", &data);
		if (strstr (data, "ProbeRequest"))
			priv->ap_support = AP_SUPPORT_YES;
	}

	iface_check_ready (self);
}
static void
default_adapter_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
{
	NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data);
	NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self);
	GVariant *ret;
	GError *err = NULL;

	ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
	                                  G_VARIANT_TYPE ("(o)"), &err);
	if (ret) {
		const char *default_adapter;

		g_variant_get (ret, "(&o)", &default_adapter);
		default_adapter_changed (priv->proxy, default_adapter, self);
		g_variant_unref (ret);
	} else {
		/* Ignore "No such adapter" errors; just means bluetooth isn't active */
		if (   !_nm_dbus_error_has_name (err, "org.bluez.Error.NoSuchAdapter")
		    && !_nm_dbus_error_has_name (err, "org.freedesktop.systemd1.LoadFailed")
		    && !g_error_matches (err, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) {
			g_dbus_error_strip_remote_error (err);
			nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s",
			             err->message);
		}
		g_error_free (err);
	}
}
static void
dispatcher_done_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
{
	DispatchInfo *info = user_data;
	GVariant *ret;
	GVariantIter *results;
	GError *error = NULL;

	ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
	                                  G_VARIANT_TYPE ("(a(sus))"),
	                                  &error);
	if (ret) {
		g_variant_get (ret, "(a(sus))", &results);
		dispatcher_results_process (info->request_id, info->action, results);
		g_variant_iter_free (results);
		g_variant_unref (ret);
	} else {
		if (_nm_dbus_error_has_name (error, "org.freedesktop.systemd1.LoadFailed")) {
			g_dbus_error_strip_remote_error (error);
			_LOGW ("(%u) failed to call dispatcher scripts: %s",
			       info->request_id, error->message);
		} else {
			_LOGD ("(%u) failed to call dispatcher scripts: %s",
			       info->request_id, error->message);
		}
		g_clear_error (&error);
	}

	if (info->callback)
		info->callback (info->request_id, info->user_data);

	dispatcher_info_cleanup (info);
}
static void
get_managed_objects_cb (GDBusProxy *proxy,
                        GAsyncResult *res,
                        NMBluez5Manager *self)
{
	GVariant *variant, *ifaces;
	GVariantIter i;
	GError *error = NULL;
	const char *path;

	variant = _nm_dbus_proxy_call_finish (proxy, res,
	                                      G_VARIANT_TYPE ("(a{oa{sa{sv}}})"),
	                                      &error);
	if (!variant) {
		if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD))
			nm_log_warn (LOGD_BT, "Couldn't get managed objects: not running Bluez5?");
		else {
			g_dbus_error_strip_remote_error (error);
			nm_log_warn (LOGD_BT, "Couldn't get managed objects: %s", error->message);
		}
		g_clear_error (&error);
		return;
	}
	g_variant_iter_init (&i, g_variant_get_child_value (variant, 0));
	while ((g_variant_iter_next (&i, "{&o*}", &path, &ifaces))) {
		if (g_variant_lookup_value (ifaces, BLUEZ5_DEVICE_INTERFACE,
		                            G_VARIANT_TYPE_DICTIONARY)) {
			device_added (proxy, path, self);
		}
		g_variant_unref (ifaces);
	}

	g_variant_unref (variant);
}
static void
add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_unref_variant GVariant *reply = NULL;
	gs_free_error GError *error = NULL;
	GHashTable *blobs;
	GHashTableIter iter;
	const char *blob_name;
	GByteArray *blob_data;

	reply = _nm_dbus_proxy_call_finish (proxy, result,
	                                    G_VARIANT_TYPE ("(o)"),
	                                    &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	g_free (priv->net_path);
	priv->net_path = NULL;

	if (error) {
		g_dbus_error_strip_remote_error (error);
		nm_log_warn (LOGD_SUPPLICANT, "Adding network to supplicant failed: %s.", error->message);
		emit_error_helper (self, error);
		return;
	}

	g_variant_get (reply, "(o)", &priv->net_path);

	/* Send blobs first; otherwise jump to selecting the network */
	blobs = nm_supplicant_config_get_blobs (priv->cfg);
	priv->blobs_left = g_hash_table_size (blobs);

	g_hash_table_iter_init (&iter, blobs);
	while (g_hash_table_iter_next (&iter, (gpointer) &blob_name, (gpointer) &blob_data)) {
		g_dbus_proxy_call (priv->iface_proxy,
		                   "AddBlob",
		                   g_variant_new ("(s@ay)",
		                                  blob_name,
		                                  g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
		                                                             blob_data->data, blob_data->len, 1)),
		                   G_DBUS_CALL_FLAGS_NONE,
		                   -1,
		                   priv->assoc_cancellable,
		                   (GAsyncReadyCallback) add_blob_cb,
		                   self);
	}

	call_select_network (self);
}
static void
interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data)
{
	NMSupplicantInterface *self;
	NMSupplicantInterfacePrivate *priv;
	gs_free_error GError *error = NULL;
	gs_unref_variant GVariant *variant = NULL;
	const char *path;

	variant = _nm_dbus_proxy_call_finish (proxy, result,
	                                      G_VARIANT_TYPE ("(o)"),
	                                      &error);
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return;

	self = NM_SUPPLICANT_INTERFACE (user_data);
	priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self);

	if (variant) {
		g_variant_get (variant, "(&o)", &path);
		interface_add_done (self, path);
	} else if (_nm_dbus_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) {
		/* Interface already added, just get its object path */
		g_dbus_proxy_call (priv->wpas_proxy,
		                   "GetInterface",
		                   g_variant_new ("(s)", priv->dev),
		                   G_DBUS_CALL_FLAGS_NONE,
		                   -1,
		                   priv->init_cancellable,
		                   (GAsyncReadyCallback) interface_get_cb,
		                   self);
	} else if (   g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMED_OUT)
	           || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) {
		/* Supplicant wasn't running and could not be launched via service
		 * activation.  Wait for it to start by moving back to the INIT
		 * state.
		 */
		g_dbus_error_strip_remote_error (error);
		nm_log_dbg (LOGD_SUPPLICANT, "(%s): failed to activate supplicant: %s",
		            priv->dev, error->message);
		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_INIT);
	} else {
		g_dbus_error_strip_remote_error (error);
		nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s", priv->dev, error->message);
		set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN);
	}
}