/*
 * wpa_gui - AddInterface class
 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Alternatively, this software may be distributed under the terms of BSD
 * license.
 *
 * See README and COPYING for more details.
 */

#include <cstdio>
#include "wpa_ctrl.h"

#include <QMessageBox>

#include "wpagui.h"
#include "addinterface.h"

#ifdef CONFIG_NATIVE_WINDOWS
#include <windows.h>

#ifndef WPA_KEY_ROOT
#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
#endif
#ifndef WPA_KEY_PREFIX
#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
#endif
#endif /* CONFIG_NATIVE_WINDOWS */


AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent)
	: QDialog(parent), wpagui(_wpagui)
{
	setWindowTitle("Select network interface to add");
	resize(400, 200);
	vboxLayout = new QVBoxLayout(this);

	interfaceWidget = new QTreeWidget(this);
	interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
	interfaceWidget->setUniformRowHeights(true);
	interfaceWidget->setSortingEnabled(true);
	interfaceWidget->setColumnCount(3);
	interfaceWidget->headerItem()->setText(0, "driver");
	interfaceWidget->headerItem()->setText(1, "interface");
	interfaceWidget->headerItem()->setText(2, "description");
	interfaceWidget->setItemsExpandable(FALSE);
	interfaceWidget->setRootIsDecorated(FALSE);
	vboxLayout->addWidget(interfaceWidget);

	connect(interfaceWidget,
		SIGNAL(itemActivated(QTreeWidgetItem *, int)), this,
		SLOT(interfaceSelected(QTreeWidgetItem *)));

	addInterfaces();
}


void AddInterface::addInterfaces()
{
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
	struct wpa_ctrl *ctrl;
	int ret;
	char buf[2048];
	size_t len;

	ctrl = wpa_ctrl_open(NULL);
	if (ctrl == NULL)
		return;

	len = sizeof(buf) - 1;
	ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL);
	if (ret < 0) {
		wpa_ctrl_close(ctrl);
		return;
	}
	buf[len] = '\0';

	wpa_ctrl_close(ctrl);

	QString ifaces(buf);
	QStringList lines = ifaces.split(QRegExp("\\n"));
	for (QStringList::Iterator it = lines.begin();
	     it != lines.end(); it++) {
		QStringList arg = (*it).split(QChar('\t'));
		if (arg.size() < 3)
			continue;
		QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget);
		if (!item)
			break;

		item->setText(0, arg[0]);
		item->setText(1, arg[1]);
		item->setText(2, arg[2]);
	}

	interfaceWidget->resizeColumnToContents(0);
	interfaceWidget->resizeColumnToContents(1);
	interfaceWidget->resizeColumnToContents(2);
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
}


#ifdef CONFIG_NATIVE_WINDOWS
bool AddInterface::addRegistryInterface(const QString &ifname)
{
	HKEY hk, ihk;
	LONG ret;
	int id, tmp;
	TCHAR name[10];
	DWORD val, i;

	ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"),
			   0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY,
			   &hk);
	if (ret != ERROR_SUCCESS)
		return false;

	id = -1;

	for (i = 0; ; i++) {
		TCHAR name[255];
		DWORD namelen;

		namelen = 255;
		ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
				   NULL);

		if (ret == ERROR_NO_MORE_ITEMS)
			break;

		if (ret != ERROR_SUCCESS)
			break;

		if (namelen >= 255)
			namelen = 255 - 1;
		name[namelen] = '\0';

#ifdef UNICODE
		QString s((QChar *) name, namelen);
#else /* UNICODE */
		QString s(name);
#endif /* UNICODE */
		tmp = s.toInt();
		if (tmp > id)
			id = tmp;
	}

	id += 1;

#ifdef UNICODE
	wsprintf(name, L"%04d", id);
#else /* UNICODE */
	os_snprintf(name, sizeof(name), "%04d", id);
#endif /* UNICODE */
	ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk,
			     NULL);
	RegCloseKey(hk);
	if (ret != ERROR_SUCCESS)
		return false;

#ifdef UNICODE
	RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
		      (LPBYTE) ifname.unicode(),
		      (ifname.length() + 1) * sizeof(TCHAR));

#else /* UNICODE */
	RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
		      (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1);
#endif /* UNICODE */
	RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ,
		      (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR));
	RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ,
		      (LPBYTE) TEXT(""), 1 * sizeof(TCHAR));
	val = 1;
	RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val,
		      sizeof(val));

	RegCloseKey(ihk);
	return true;
}
#endif /* CONFIG_NATIVE_WINDOWS */


void AddInterface::interfaceSelected(QTreeWidgetItem *sel)
{
	if (!sel)
		return;

#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
	struct wpa_ctrl *ctrl;
	int ret;
	char buf[20], cmd[256];
	size_t len;

	/*
	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
	 * <driver_param>TAB<bridge_name>
	 */
	snprintf(cmd, sizeof(cmd),
		 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
		 sel->text(1).toAscii().constData(),
		 "default",
		 sel->text(0).toAscii().constData(),
		 "yes", "", "");
	cmd[sizeof(cmd) - 1] = '\0';

	ctrl = wpa_ctrl_open(NULL);
	if (ctrl == NULL)
		return;

	len = sizeof(buf) - 1;
	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL);
	wpa_ctrl_close(ctrl);

	if (ret < 0) {
		QMessageBox::warning(this, "wpa_gui",
				     "Add interface command could not be "
				     "completed.");
		return;
	}

	buf[len] = '\0';
	if (buf[0] != 'O' || buf[1] != 'K') {
		QMessageBox::warning(this, "wpa_gui",
				     "Failed to add the interface.");
		return;
	}

#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */

#ifdef CONFIG_NATIVE_WINDOWS
	if (!addRegistryInterface(sel->text(1))) {
		QMessageBox::information(this, "wpa_gui",
					 "Failed to add the interface into "
					 "registry.");
	}
#endif /* CONFIG_NATIVE_WINDOWS */

	wpagui->selectAdapter(sel->text(1));
	close();
}