static void
impl_ppp_manager_need_secrets (NMPPPManager *manager,
                               DBusGMethodInvocation *context)
{
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
	NMConnection *connection;
	const char *setting_name;
	const char *username = NULL;
	const char *password = NULL;
	guint32 tries;
	GPtrArray *hints = NULL;
	GError *error = NULL;
	NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION;

	connection = nm_act_request_get_connection (priv->act_req);

	nm_connection_clear_secrets (connection);
	setting_name = nm_connection_need_secrets (connection, &hints);
	if (!setting_name) {
		/* Use existing secrets from the connection */
		if (extract_details_from_connection (connection, &username, &password, &error)) {
			/* Send existing secrets to the PPP plugin */
			priv->pending_secrets_context = context;
			ppp_secrets_cb (priv->act_req, priv->secrets_id, connection, NULL, manager);
		} else {
			nm_log_warn (LOGD_PPP, "%s", error->message);
			dbus_g_method_return_error (priv->pending_secrets_context, error);
			g_clear_error (&error);
		}
		return;
	}

	/* Only ask for completely new secrets after retrying them once; some devices
	 * appear to ask a few times when they actually don't even care what you
	 * pass back.
	 */
	tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES));
	if (tries > 1)
		flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW;

	priv->secrets_id = nm_act_request_get_secrets (priv->act_req,
	                                               setting_name,
	                                               flags,
	                                               hints ? g_ptr_array_index (hints, 0) : NULL,
	                                               ppp_secrets_cb,
	                                               manager);
	g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, GUINT_TO_POINTER (++tries));
	priv->pending_secrets_context = context;

	if (hints)
		g_ptr_array_free (hints, TRUE);
}
static void
ppp_secrets_cb (NMActRequest *req,
                NMActRequestGetSecretsCallId call_id,
                NMSettingsConnection *settings_connection, /* unused (we pass NULL here) */
                GError *error,
                gpointer user_data)
{
	NMPPPManager *self = NM_PPP_MANAGER (user_data);
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self);
	const char *username = NULL;
	const char *password = NULL;
	GError *local = NULL;
	NMConnection *applied_connection;

	g_return_if_fail (priv->pending_secrets_context != NULL);
	g_return_if_fail (req == priv->act_req);
	g_return_if_fail (call_id == priv->secrets_id);

	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		goto out;

	if (error) {
		_LOGW ("%s", error->message);
		g_dbus_method_invocation_return_gerror (priv->pending_secrets_context, error);
		goto out;
	}

	applied_connection = nm_act_request_get_applied_connection (req);

	if (!extract_details_from_connection (applied_connection, priv->secrets_setting_name, &username, &password, &local)) {
		_LOGW ("%s", local->message);
		g_dbus_method_invocation_take_error (priv->pending_secrets_context, local);
		goto out;
	}

	/* This is sort of a hack but...
	 * pppd plugin only ever needs username and password. Passing the full
	 * connection there would mean some bloat: the plugin would need to link
	 * against libnm just to parse this. So instead, let's just send what
	 * it needs.
	 */
	g_dbus_method_invocation_return_value (
		priv->pending_secrets_context,
		g_variant_new ("(ss)", username ? username : "", password ? password : ""));

 out:
	priv->pending_secrets_context = NULL;
	priv->secrets_id = NULL;
	priv->secrets_setting_name = NULL;
}
static void
ppp_secrets_cb (NMActRequest *req,
                guint32 call_id,
                NMConnection *connection,
                GError *error,
                gpointer user_data)
{
	NMPPPManager *self = NM_PPP_MANAGER (user_data);
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self);
	const char *username = NULL;
	const char *password = NULL;
	GError *local = NULL;

	g_return_if_fail (priv->pending_secrets_context != NULL);
	g_return_if_fail (req == priv->act_req);
	g_return_if_fail (call_id == priv->secrets_id);

	if (error) {
		nm_log_warn (LOGD_PPP, "%s", error->message);
		dbus_g_method_return_error (priv->pending_secrets_context, error);
		goto out;
	}

	if (!extract_details_from_connection (connection, &username, &password, &local)) {
		nm_log_warn (LOGD_PPP, "%s", local->message);
		dbus_g_method_return_error (priv->pending_secrets_context, local);
		g_clear_error (&local);
		goto out;
	}

	/* This is sort of a hack but...
	 * pppd plugin only ever needs username and password. Passing the full
	 * connection there would mean some bloat: the plugin would need to link
	 * against libnm-util just to parse this. So instead, let's just send what
	 * it needs.
	 */
	dbus_g_method_return (priv->pending_secrets_context, username, password);

out:
	priv->pending_secrets_context = NULL;
	priv->secrets_id = 0;
}