/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2018 Red Hat, Inc.
 */

#include "src/core/nm-default-daemon.h"

#include "nm-wifi-common.h"

#include "devices/nm-device.h"
#include "nm-wifi-ap.h"
#include "nm-device-wifi.h"
#include "nm-dbus-manager.h"

#if WITH_IWD
#include "nm-device-iwd.h"
#endif

/*****************************************************************************/

void
nm_device_wifi_emit_signal_access_point(NMDevice *device,
                                        NMWifiAP *ap,
                                        gboolean  is_added /* or else is_removed */)
{
    nm_dbus_object_emit_signal(NM_DBUS_OBJECT(device),
                               &nm_interface_info_device_wireless,
                               is_added ? &nm_signal_info_wireless_access_point_added
                                        : &nm_signal_info_wireless_access_point_removed,
                               "(o)",
                               nm_dbus_object_get_path(NM_DBUS_OBJECT(ap)));
}

/*****************************************************************************/

static const CList *
_dispatch_get_aps(NMDevice *device)
{
#if WITH_IWD
    if (NM_IS_DEVICE_IWD(device))
        return _nm_device_iwd_get_aps(NM_DEVICE_IWD(device));
#endif
    return _nm_device_wifi_get_aps(NM_DEVICE_WIFI(device));
}

static void
_dispatch_request_scan(NMDevice *device, GVariant *options, GDBusMethodInvocation *invocation)
{
#if WITH_IWD
    if (NM_IS_DEVICE_IWD(device)) {
        _nm_device_iwd_request_scan(NM_DEVICE_IWD(device), options, invocation);
        return;
    }
#endif
    _nm_device_wifi_request_scan(NM_DEVICE_WIFI(device), options, invocation);
}
char * get_interface_path(char *device_iface)//get device object_path
{
	if(!device_iface)
	{
		return NULL;
	}
	GDBusProxy *proxy;
	GError *error = NULL;
	GVariant *ret;
	char *object_path = NULL;
	proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
	                                       G_DBUS_PROXY_FLAGS_NONE,
	                                       NULL,
	                                       "fi.w1.wpa_supplicant1",
	                                       "/fi/w1/wpa_supplicant1",
	                                       "fi.w1.wpa_supplicant1",
	                                       NULL, &error);

	if(proxy == NULL)
	{
		return object_path;
	}
	
	ret = g_dbus_proxy_call_sync (proxy,
	                              "GetInterface",
	                              g_variant_new ("(s)", device_iface),
	                              G_DBUS_CALL_FLAGS_NONE, -1,
	                              NULL, &error);
	if (!ret) {
		g_dbus_error_strip_remote_error (error);
		g_print ("Error adding connection: %s\n", error->message);
		g_clear_error (&error);
		return object_path;
	} 

	g_variant_get (ret, "(&o)", &object_path);
	g_print ("object_path: %s\n", object_path);
	g_object_unref (proxy);
	return object_path;
}
gint32 nm_device_wifi_hotspot_channel(NMDBusObject *obj)
{
	GDBusProxy *proxy;
	GError *error = NULL;
	GVariant *ret = NULL;
	guint32 freq_allow = 0;
	char *device_iface= nm_device_get_iface (NM_DEVICE (obj));
	char *device_object_path = get_interface_path(device_iface);
	proxy = g_dbus_proxy_new_for_bus_sync(G_BUS_TYPE_SYSTEM,
										  G_DBUS_PROXY_FLAGS_NONE,
										  NULL,
										  "fi.w1.wpa_supplicant1",
										  device_object_path,
										  "fi.w1.wpa_supplicant1.Interface",
										  NULL, NULL);
	if (proxy == NULL)
	{
		return;
	}
	ret = g_dbus_proxy_call_sync(proxy,
								 "GetChannelFreq",
								 NULL,
								 G_DBUS_CALL_FLAGS_NONE, -1,
								 NULL, &error);
	if (!ret)
	{
		g_dbus_error_strip_remote_error(error);
		g_warning("Failed to get ActiveConnections sta_info: %s\n", error->message);
		g_error_free(error);
		return;
	}
	char *freq_value = calloc(1024, sizeof(char *));
	if (!g_variant_is_of_type(ret, G_VARIANT_TYPE("()")))
	{
		g_variant_get(ret, "(&s)", &freq_value);
		if (freq_value)
		{
			char **split = g_strsplit(freq_value, " ", 0);
			char **d = NULL;
			for (d = split; *d; d++)
			{
				if (*d !=NULL && strlen(*d) >1 && strstr(*d, "[") == NULL)
				{
					freq_allow = 1;
					g_object_unref(proxy);
					return freq_allow;
				}
			}
		}
	}
	g_object_unref(proxy);
	return freq_allow;
}
static void
impl_device_wifi_get_hotspot_capabilities (NMDBusObject *obj,
                                    const NMDBusInterfaceInfoExtended *interface_info,
                                    const NMDBusMethodInfoExtended *method_info,
                                    GDBusConnection *connection,
                                    const char *sender,
                                    GDBusMethodInvocation *invocation,
                                    GVariant *parameters)
{
	gint32 result = nm_device_wifi_hotspot_channel(obj);
	g_dbus_method_invocation_return_value (invocation,
	                                        g_variant_new("(u)", result));
}
static void
impl_device_wifi_get_access_points(NMDBusObject                      *obj,
                                   const NMDBusInterfaceInfoExtended *interface_info,
                                   const NMDBusMethodInfoExtended    *method_info,
                                   GDBusConnection                   *connection,
                                   const char                        *sender,
                                   GDBusMethodInvocation             *invocation,
                                   GVariant                          *parameters)
{
    gs_free const char **list = NULL;
    GVariant            *v;
    const CList         *all_aps;

    /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */

    all_aps = _dispatch_get_aps(NM_DEVICE(obj));
    list    = nm_wifi_aps_get_paths(all_aps, FALSE);
    v       = g_variant_new_objv(list, -1);
    g_dbus_method_invocation_return_value(invocation, g_variant_new_tuple(&v, 1));
}

static void
impl_device_wifi_get_all_access_points(NMDBusObject                      *obj,
                                       const NMDBusInterfaceInfoExtended *interface_info,
                                       const NMDBusMethodInfoExtended    *method_info,
                                       GDBusConnection                   *connection,
                                       const char                        *sender,
                                       GDBusMethodInvocation             *invocation,
                                       GVariant                          *parameters)
{
    gs_free const char **list = NULL;
    GVariant            *v;
    const CList         *all_aps;

    /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */

    all_aps = _dispatch_get_aps(NM_DEVICE(obj));
    list    = nm_wifi_aps_get_paths(all_aps, TRUE);
    v       = g_variant_new_objv(list, -1);
    g_dbus_method_invocation_return_value(invocation, g_variant_new_tuple(&v, 1));
}

static void
impl_device_wifi_request_scan(NMDBusObject                      *obj,
                              const NMDBusInterfaceInfoExtended *interface_info,
                              const NMDBusMethodInfoExtended    *method_info,
                              GDBusConnection                   *connection,
                              const char                        *sender,
                              GDBusMethodInvocation             *invocation,
                              GVariant                          *parameters)
{
    gs_unref_variant GVariant *options = NULL;

    /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */

    g_variant_get(parameters, "(@a{sv})", &options);

    _dispatch_request_scan(NM_DEVICE(obj), options, invocation);
}

const GDBusSignalInfo nm_signal_info_wireless_access_point_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(
    "AccessPointAdded",
    .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("access_point", "o"), ), );

const GDBusSignalInfo nm_signal_info_wireless_access_point_removed =
    NM_DEFINE_GDBUS_SIGNAL_INFO_INIT(
        "AccessPointRemoved",
        .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("access_point", "o"), ), );

const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = {
    .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT(
        NM_DBUS_INTERFACE_DEVICE_WIRELESS,
        .methods = NM_DEFINE_GDBUS_METHOD_INFOS(
            NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(
                NM_DEFINE_GDBUS_METHOD_INFO_INIT(
                    "GetAccessPoints",
                    .out_args = NM_DEFINE_GDBUS_ARG_INFOS(
                        NM_DEFINE_GDBUS_ARG_INFO("access_points", "ao"), ),
                    .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ),
                .handle = impl_device_wifi_get_access_points, ),
            NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(
                NM_DEFINE_GDBUS_METHOD_INFO_INIT(
					"GetHotspotCapabilities",
					.out_args = NM_DEFINE_GDBUS_ARG_INFOS (
						NM_DEFINE_GDBUS_ARG_INFO ("result", "u"),
					),
					.annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), 
				),
				.handle = impl_device_wifi_get_hotspot_capabilities,
			),
            NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(
                NM_DEFINE_GDBUS_METHOD_INFO_INIT(
                    "GetAllAccessPoints",
                    .out_args = NM_DEFINE_GDBUS_ARG_INFOS(
                        NM_DEFINE_GDBUS_ARG_INFO("access_points", "ao"), ), ),
                .handle = impl_device_wifi_get_all_access_points, ),
            NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(
                NM_DEFINE_GDBUS_METHOD_INFO_INIT(
                    "RequestScan",
                    .in_args = NM_DEFINE_GDBUS_ARG_INFOS(
                        NM_DEFINE_GDBUS_ARG_INFO("options", "a{sv}"), ), ),
                .handle = impl_device_wifi_request_scan, ), ),
        .signals    = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_wireless_access_point_added,
                                                &nm_signal_info_wireless_access_point_removed, ),
        .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS(
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS),
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(
                "PermHwAddress",
                "s",
                NM_DEVICE_PERM_HW_ADDRESS,
                .annotations = NM_GDBUS_ANNOTATION_INFO_LIST_DEPRECATED(), ),
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Mode", "u", NM_DEVICE_WIFI_MODE),
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Bitrate", "u", NM_DEVICE_WIFI_BITRATE),
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AccessPoints",
                                                           "ao",
                                                           NM_DEVICE_WIFI_ACCESS_POINTS),
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ActiveAccessPoint",
                                                           "o",
                                                           NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT),
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WirelessCapabilities",
                                                           "u",
                                                           NM_DEVICE_WIFI_CAPABILITIES),
            NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastScan",
                                                           "x",
                                                           NM_DEVICE_WIFI_LAST_SCAN), ), ),
};
