/***************************************************************************
 *
 * knetworkmanager-connection_setting_wireless_security_widget.cpp
 * - A NetworkManager frontend for KDE
 *
 * Copyright (C) 2005, 2006 Novell, Inc.
 *
 * Author: Helmut Schaa <hschaa@suse.de>, <Helmut.Schaa@gmx.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 **************************************************************************/

/* qt headers */
#include <qwidget.h>
#include <qlineedit.h>
#include <qgroupbox.h>
#include <qbuttongroup.h>
#include <qwidgetstack.h>
#include <qcombobox.h>
#include <qradiobutton.h>
#include <qlayout.h>
#include <qcheckbox.h>

/* kde headers */
#include <kurlrequester.h>
#include <klocale.h>
#include <kdebug.h>
#include <kpassdlg.h>

/* knetworkmanager headers */
#include "knetworkmanager-accesspoint.h"
#include "knetworkmanager-wireless_device.h"
#include "knetworkmanager-device.h"
#include "knetworkmanager-connection.h"
#include "knetworkmanager-connection_setting_wireless_security_widget.h"
#include "knetworkmanager-connection_setting_wireless_security.h"
#include "knetworkmanager-connection_setting_wireless.h"
#include "knetworkmanager-connection_setting_8021x.h"
#include "sha1.h"
#include "md5.h"
#include "knetworkmanager-wireless_manager.h"

#define WPA_PMK_LEN 32

using namespace ConnectionSettings;

/*
	class WirelessSecurityWEPImpl
*/
WirelessSecurityWEPImpl::WirelessSecurityWEPImpl(WirelessSecurity* sec, QWidget* parent, const char* name, WFlags fl)
	: ConnectionSettingWirelessSecurityWEP(parent, name, fl)
	, _security_setting(sec)
	, _wepKeyType( WEPKEY_TYPE_HEX )
{
	cboAuthentication->insertItem(i18n("Open System"), 0);
	cboAuthentication->insertItem(i18n("Shared Key"), 1);
	if (_security_setting->getAuthAlg() == WirelessSecurity::AUTH_ALG_OPEN)
		cboAuthentication->setCurrentItem(0);
	else if (_security_setting->getAuthAlg() == WirelessSecurity::AUTH_ALG_SHARED)
		cboAuthentication->setCurrentItem(1);

	cbKeyType->insertItem(i18n("WEP 40/128-bit ASCII"), WEPKEY_TYPE_ASCII);
	cbKeyType->insertItem(i18n("WEP 40/128-bit Hexadecimal"), WEPKEY_TYPE_HEX);
	cbKeyType->insertItem(i18n("WEP 128-bit passphrase"), WEPKEY_TYPE_PASSPHRASE);
	cbKeyType->setCurrentItem(_wepKeyType );

	txtWEPKey0->setText(_security_setting->getWepKey(0));
	txtWEPKey1->setText(_security_setting->getWepKey(1));
	txtWEPKey2->setText(_security_setting->getWepKey(2));
	txtWEPKey3->setText(_security_setting->getWepKey(3));

	switch(_security_setting->getWepTxidx())
	{
		case 0:
			rbKeyIdx0->setChecked(true);
			break;
		case 1:
			rbKeyIdx1->setChecked(true);
			break;
		case 2:
			rbKeyIdx2->setChecked(true);
			break;
		case 3:
			rbKeyIdx3->setChecked(true);
			break;
		default:
			rbKeyIdx0->setChecked(true);
			break;
	}

	connect(cboAuthentication, SIGNAL(activated(int)), this, SLOT(slotAuthAlgChanged(int)));
	connect(cbKeyType, SIGNAL(activated(int)), this, SLOT(slotKeyTypeChanged(int)));
	connect(txtWEPKey0, SIGNAL(textChanged(const QString&)), this, SLOT(slotWepKey0Changed(const QString&)));
	connect(txtWEPKey1, SIGNAL(textChanged(const QString&)), this, SLOT(slotWepKey1Changed(const QString&)));
	connect(txtWEPKey2, SIGNAL(textChanged(const QString&)), this, SLOT(slotWepKey2Changed(const QString&)));
	connect(txtWEPKey3, SIGNAL(textChanged(const QString&)), this, SLOT(slotWepKey3Changed(const QString&)));

	connect(rbKeyIdx0, SIGNAL(toggled(bool)), this, SLOT(slotWepIdx0Checked(bool)));
	connect(rbKeyIdx1, SIGNAL(toggled(bool)), this, SLOT(slotWepIdx1Checked(bool)));
	connect(rbKeyIdx2, SIGNAL(toggled(bool)), this, SLOT(slotWepIdx2Checked(bool)));
	connect(rbKeyIdx3, SIGNAL(toggled(bool)), this, SLOT(slotWepIdx3Checked(bool)));
}

void WirelessSecurityWEPImpl::slotAuthAlgChanged(int index)
{
	if (index == 0)
		_security_setting->setAuthAlg(WirelessSecurity::AUTH_ALG_OPEN);
	else if (index == 1)
		_security_setting->setAuthAlg(WirelessSecurity::AUTH_ALG_SHARED);
}

void WirelessSecurityWEPImpl::slotKeyTypeChanged(int index)
{
	_wepKeyType = (WEPKEY_TYPE)index;

	// update all WEP-Keys here due to the new key_type
}

void WirelessSecurityWEPImpl::slotWepKey0Changed(const QString &key)
{
	QCString hashed = getHashedWEPKey(key, _wepKeyType);
	_security_setting->setWepKey(0, hashed);
}

void WirelessSecurityWEPImpl::slotWepKey1Changed(const QString &key)
{
	QCString hashed = getHashedWEPKey(key, _wepKeyType);
	_security_setting->setWepKey(1, hashed);
}

void WirelessSecurityWEPImpl::slotWepKey2Changed(const QString &key)
{
	QCString hashed = getHashedWEPKey(key, _wepKeyType);
	_security_setting->setWepKey(2, hashed);
}

void WirelessSecurityWEPImpl::slotWepKey3Changed(const QString& key)
{
	QCString hashed = getHashedWEPKey(key, _wepKeyType);
	_security_setting->setWepKey(3, hashed);
}

void WirelessSecurityWEPImpl::slotWepIdx0Checked(bool check)
{
	if (check)
		_security_setting->setWepTxidx(0);
}

void WirelessSecurityWEPImpl::slotWepIdx1Checked(bool check)
{
	if (check)
		_security_setting->setWepTxidx(1);
}

void WirelessSecurityWEPImpl::slotWepIdx2Checked(bool check)
{
	if (check)
		_security_setting->setWepTxidx(2);
}

void WirelessSecurityWEPImpl::slotWepIdx3Checked(bool check)
{
	if (check)
		_security_setting->setWepTxidx(3);
}

QCString
WirelessSecurityWEPImpl::getHashedWEPKey(QString key, WEPKEY_TYPE type) const
{
	QCString hashed;
	switch(type)
	{
		case WEPKEY_TYPE_HEX:
			return QCString(key);
			break;
		case WEPKEY_TYPE_ASCII:
			hashed = String2Hex(QCString(key), key.length() * 2);
			return hashed;
			break;
		case WEPKEY_TYPE_PASSPHRASE:
			return getWEP128PassphraseHash(QCString(key));
			break;
	}
	return hashed;
}

QCString
WirelessSecurityWEPImpl::getWEP128PassphraseHash(QCString input) const
{
	char md5_data[65];
	QCString digest(16);
	int input_len;
	int i;

	if (input.isNull()) return input;

	input_len = input.length();
	if (input_len < 1)
		return QCString();

	/* Get at least 64 bytes */
	for (i = 0; i < 64; i++)
		md5_data [i] = input [i % input_len];

	/* Null terminate md5 seed data and hash it */
	md5_data[64] = 0;
	gnome_keyring_md5_string (md5_data, (unsigned char*)digest.data());
	return (String2Hex(QByteArray(digest), 26));

}

QCString
WirelessSecurityWEPImpl::String2Hex(QByteArray bytes, int final_len) const
{
	QCString result(final_len+1);
	static char hex_digits[] = "0123456789abcdef";
	result.resize(bytes.size() * 2 + 1);
	for (uint i = 0; i < bytes.size(); i++)
	{
		result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
		result[2*i+1] = hex_digits[bytes[i] & 0xf];
	}
	/* Cut converted key off at the correct length for this cipher type */
	if (final_len > -1)
		result[final_len] = '\0';
	return result;
}


/*
	class WirelessSecurityWEPEncryptionImpl
*/
WirelessSecurityWEPEncryptionImpl::WirelessSecurityWEPEncryptionImpl(WirelessSecurity* security_setting, QWidget* parent, const char* name, WFlags fl)
	: ConnectionSettingWirelessSecurityWEPEncryption(parent, name, fl)
	, _security_setting(security_setting)
{
	cboEncryption->insertItem(i18n("None"));
	cboEncryption->insertItem(i18n("Dynamic WEP"));
}


/*
	class WirelessSecurityWPAVersionImpl
*/
WirelessSecurityWPAVersionImpl::WirelessSecurityWPAVersionImpl(WirelessSecurity* security_setting, QWidget* parent, const char* name, WFlags fl)
	: ConnectionSettingWirelessSecurityWPAVersion(parent, name, fl)
	, _security_setting(security_setting)
{
	cbWPA->setChecked(_security_setting->getProto() & WirelessSecurity::PROTO_WPA);
	cbRSN->setChecked(_security_setting->getProto() & WirelessSecurity::PROTO_RSN);

	connect(cbWPA, SIGNAL(toggled(bool)), this, SLOT(slotWPA1(bool)));
	connect(cbRSN, SIGNAL(toggled(bool)), this, SLOT(slotWPA2(bool)));

	connect(grpUseWPAVersion, SIGNAL(toggled(bool)), this, SLOT(slotAuto(bool)));
}

void
WirelessSecurityWPAVersionImpl::slotAuto(bool on)
{
	if (!on)
	{
		// auto-select proto
		_security_setting->setProto(WirelessSecurity::PROTO_AUTO);
	}
	else
	{
		// use selected wpa-version
		Q_UINT32 proto = WirelessSecurity::PROTO_NONE;
		if (cbWPA->isChecked())
			proto |= WirelessSecurity::PROTO_WPA;
		if (cbRSN->isChecked())
			proto  |= WirelessSecurity::PROTO_RSN;
		_security_setting->setProto(proto);
	}
}

void
WirelessSecurityWPAVersionImpl::slotWPA1(bool on)
{
	if (on)
		_security_setting->addProto(WirelessSecurity::PROTO_WPA);
	else
		_security_setting->delProto(WirelessSecurity::PROTO_WPA);
}

void
WirelessSecurityWPAVersionImpl::slotWPA2(bool on)
{
	if (on)
		_security_setting->addProto(WirelessSecurity::PROTO_RSN);
	else
		_security_setting->delProto(WirelessSecurity::PROTO_RSN);
}

/*
	class WirelessSecurityWPACipherImpl
*/
WirelessSecurityWPACipherImpl::WirelessSecurityWPACipherImpl(WirelessSecurity* security_setting, QWidget* parent, const char* name, WFlags fl)
	: ConnectionSettingWirelessSecurityWPACipher(parent, name, fl)
	, _security_setting(security_setting)
{
	connect(grpUseCipher, SIGNAL(toggled(bool)), this, SLOT(slotCipherChangedAuto(bool)));

	connect(chkGroupCipherTKIP, SIGNAL(toggled(bool)), this, SLOT(slotGroupCipherChangedTKIP(bool)));
	connect(chkGroupCipherCCMP, SIGNAL(toggled(bool)), this, SLOT(slotGroupCipherChangedCCMP(bool)));
	connect(chkGroupCipherWEP40, SIGNAL(toggled(bool)), this, SLOT(slotGroupCipherChangedWEP40(bool)));
	connect(chkGroupCipherWEP104, SIGNAL(toggled(bool)), this, SLOT(slotGroupCipherChangedWEP104(bool)));

	connect(chkPairwiseCipherTKIP, SIGNAL(toggled(bool)), this, SLOT(slotPairwiseCipherChangedTKIP(bool)));
	connect(chkPairwiseCipherCCMP, SIGNAL(toggled(bool)), this, SLOT(slotPairwiseCipherChangedCCMP(bool)));

	chkPairwiseCipherCCMP->setChecked(_security_setting->getPairwiseCiphers() & WirelessSecurity::CIPHER_CCMP);
	chkPairwiseCipherTKIP->setChecked(_security_setting->getPairwiseCiphers() & WirelessSecurity::CIPHER_TKIP);

	chkGroupCipherCCMP->setChecked(_security_setting->getGroupCiphers() & WirelessSecurity::CIPHER_CCMP);
	chkGroupCipherTKIP->setChecked(_security_setting->getGroupCiphers() & WirelessSecurity::CIPHER_TKIP);
	chkGroupCipherWEP40->setChecked(_security_setting->getGroupCiphers() & WirelessSecurity::CIPHER_WEP40);
	chkGroupCipherWEP104->setChecked(_security_setting->getGroupCiphers() & WirelessSecurity::CIPHER_WEP104);

}

void
WirelessSecurityWPACipherImpl::slotCipherChangedAuto(bool checked)
{
	if (!checked)
	{
		// select auto for both ciphers
		_security_setting->setGroupCiphers(WirelessSecurity::CIPHER_AUTO);
		_security_setting->setPairwiseCiphers(WirelessSecurity::CIPHER_AUTO);
	}
	else
	{
		// use the already selected ciphers

		// group cipher
		Q_UINT32 cipher = WirelessSecurity::CIPHER_NONE;
		if (chkGroupCipherTKIP->isChecked())
			cipher |= WirelessSecurity::CIPHER_TKIP;
		if (chkGroupCipherCCMP->isChecked())
			cipher |= WirelessSecurity::CIPHER_CCMP;
		if (chkGroupCipherWEP40->isChecked())
			cipher |= WirelessSecurity::CIPHER_WEP40;
		if (chkGroupCipherWEP104->isChecked())
			cipher |= WirelessSecurity::CIPHER_WEP104;
		_security_setting->setGroupCiphers(cipher);

		// pairwise cipher
		cipher = WirelessSecurity::CIPHER_NONE;
		if (chkPairwiseCipherTKIP->isChecked())
			cipher |= WirelessSecurity::CIPHER_TKIP;
		if (chkPairwiseCipherCCMP->isChecked())
			cipher |= WirelessSecurity::CIPHER_CCMP;
		_security_setting->setPairwiseCiphers(cipher);

	}
}

void
WirelessSecurityWPACipherImpl::slotGroupCipherChangedTKIP(bool checked)
{
	if (checked)
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() | WirelessSecurity::CIPHER_TKIP);
	else
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() & (!WirelessSecurity::CIPHER_TKIP));
}

void
WirelessSecurityWPACipherImpl::slotGroupCipherChangedCCMP(bool checked)
{
	if (checked)
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() | WirelessSecurity::CIPHER_CCMP);
	else
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() & (!WirelessSecurity::CIPHER_CCMP));
}

void
WirelessSecurityWPACipherImpl::slotGroupCipherChangedWEP40(bool checked)
{
	if (checked)
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() | WirelessSecurity::CIPHER_WEP40);
	else
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() & (!WirelessSecurity::CIPHER_WEP40));
}

void
WirelessSecurityWPACipherImpl::slotGroupCipherChangedWEP104(bool checked)
{
	if (checked)
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() | WirelessSecurity::CIPHER_WEP104);
	else
		_security_setting->setGroupCiphers(_security_setting->getGroupCiphers() & (!WirelessSecurity::CIPHER_WEP104));
}

void
WirelessSecurityWPACipherImpl::slotPairwiseCipherChangedTKIP(bool checked)
{
	if (checked)
		_security_setting->setPairwiseCiphers(_security_setting->getPairwiseCiphers() | WirelessSecurity::CIPHER_TKIP);
	else
		_security_setting->setPairwiseCiphers(_security_setting->getPairwiseCiphers() & (!WirelessSecurity::CIPHER_TKIP));
}

void
WirelessSecurityWPACipherImpl::slotPairwiseCipherChangedCCMP(bool checked)
{
	if (checked)
		_security_setting->setPairwiseCiphers(_security_setting->getPairwiseCiphers() | WirelessSecurity::CIPHER_CCMP);
	else
		_security_setting->setPairwiseCiphers(_security_setting->getPairwiseCiphers() & (!WirelessSecurity::CIPHER_CCMP));
}

/*
	class WirelessSecurityWPAPSK
*/
WirelessSecurityWPAPSKImpl::WirelessSecurityWPAPSKImpl(WirelessSecurity* security_setting, Wireless* wireless_setting, QWidget* parent, const char* name, WFlags fl)
	: ConnectionSettingWirelessSecurityWPAPSK(parent, name, fl)
	, _security_setting(security_setting)
	, _wireless_setting(wireless_setting)
{
	txtPSK->setText(_security_setting->getPSK());
	connect(txtPSK, SIGNAL(textChanged(const QString&)), this, SLOT(slotPSKChanged(const QString&)));
}

void
WirelessSecurityWPAPSKImpl::slotPSKChanged(const QString& psk)
{

	if (_wireless_setting)
	{
		QCString hashed;
		if (psk.length() == 64)
			hashed = psk;
		else
		{
			QCString buffer(WPA_PMK_LEN * 2);
			QByteArray essid = _wireless_setting->getEssid();
			pbkdf2_sha1 (QCString(psk).data(), essid.data(), essid.size(), 4096, (uint8_t*)buffer.data(), WPA_PMK_LEN);
			hashed = String2Hex(buffer, WPA_PMK_LEN*2);
		}
		_security_setting->setPSK(hashed);
	}
}

QCString
WirelessSecurityWPAPSKImpl::String2Hex(QByteArray bytes, int final_len) const
{
	QCString result(final_len+1);
	static char hex_digits[] = "0123456789abcdef";
	result.resize(bytes.size() * 2 + 1);
	for (uint i = 0; i < bytes.size(); i++)
	{
		result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
		result[2*i+1] = hex_digits[bytes[i] & 0xf];
	}
	/* Cut converted key off at the correct length for this cipher type */
	if (final_len > -1)
		result[final_len] = '\0';
	return result;
}

/*
	class WirelessSecurityEAPImpl
*/
WirelessSecurityEAPImpl::WirelessSecurityEAPImpl(IEEE8021x* security_setting, WirelessSecurityPhase2Impl* phase2_widget, QWidget* parent, const char* name, WFlags fl)
	: ConnectionSettingWirelessSecurityEAP(parent, name, fl)
	, _security_setting(security_setting)
	, _phase2_widget(phase2_widget)
{
	// insert all EAP-Methods
	int index = 0;
	cboMethod->insertItem(i18n("None"), index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_NONE;

	cboMethod->insertItem(i18n("TTLS"), ++index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_TTLS;

	cboMethod->insertItem(i18n("PEAP"), ++index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_PEAP;

	cboMethod->insertItem(i18n("TLS"), ++index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_TLS;

	cboMethod->insertItem(i18n("Leap"), ++index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_LEAP;

	cboMethod->insertItem(i18n("MD5"), ++index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_MD5;

	cboMethod->insertItem(i18n("FAST"), ++index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_FAST;

	cboMethod->insertItem(i18n("SIM"), ++index);
	_eapIndexMap[index] = IEEE8021x::EAP_PHASE1_SIM;

	// preselect the correct method
	QBiDirectionalMap<int, IEEE8021x::EAP_PHASE1>::Iterator it = _eapIndexMap.findData(_security_setting->getEAP());
	cboMethod->setCurrentItem(it.key());

	// update phase2 combobox
	_phase2_widget->setAllowedPhase2Methods(_security_setting->getAllowedPhase2Methods());

	txtIdentity->setText(_security_setting->getIdentity());
	txtAnonIdentity->setText(_security_setting->getAnonIdentity());
	txtPassword->setText(_security_setting->getPassword());

	chkCAStore->setChecked(_security_setting->getUseSystemCaCert());
	kURLCACert->setEnabled(!_security_setting->getUseSystemCaCert());

	// get notified if the method changes
	connect(cboMethod, SIGNAL(activated(int)), this, SLOT(slotMethodChanged(int)));
	connect(txtIdentity, SIGNAL(textChanged(const QString&)), this, SLOT(slotIdentityChanged(const QString&)));
	connect(txtAnonIdentity, SIGNAL(textChanged(const QString&)), this, SLOT(slotAnonIdentityChanged(const QString&)));
	connect(txtPassword, SIGNAL(textChanged(const QString&)), this, SLOT(slotPasswordChanged(const QString&)));
	connect(chkCAStore, SIGNAL(toggled(bool)), this, SLOT(slotUseSystemCaCertChanged(bool)));
}

void WirelessSecurityEAPImpl::slotUseSystemCaCertChanged(bool on)
{
	_security_setting->setUseSystemCaCert(on);
	kURLCACert->setEnabled(!on);
}

void WirelessSecurityEAPImpl::slotMethodChanged(int index)
{
	// new method choosen
	IEEE8021x::EAP_PHASE1 eap = _eapIndexMap[index];
	_security_setting->setEAP(eap);

	_phase2_widget->setAllowedPhase2Methods(_security_setting->getAllowedPhase2Methods());
}

void WirelessSecurityEAPImpl::slotIdentityChanged(const QString& identity)
{
	_security_setting->setIdentity(identity);
}

void WirelessSecurityEAPImpl::slotAnonIdentityChanged(const QString& identity)
{
	_security_setting->setAnonIdentity(identity);
}

void WirelessSecurityEAPImpl::slotPasswordChanged(const QString& pwd)
{
	_security_setting->setPassword(QString(txtPassword->password()));
}

/*
	class WirelessSecurityPhase2Impl
*/
WirelessSecurityPhase2Impl::WirelessSecurityPhase2Impl(IEEE8021x* security_setting, QWidget* parent, const char* name, WFlags fl)
	: ConnectionSettingWirelessSecurityPhase2(parent, name, fl)
	, _security_setting(security_setting)
{
	_allowed_methods.append(IEEE8021x::EAP_PHASE2_AUTH_NONE);
	updateMethodComboBox();

	connect(cboPhase2Method, SIGNAL(activated(int)), this, SLOT(slotPhase2MethodChanged(int)));
}

void WirelessSecurityPhase2Impl::updateMethodComboBox()
{
	// insert all phase2 EAP-Methods
	int index = 0;
	cboPhase2Method->clear();
	_eapIndexMap.clear();

	for (QValueList<IEEE8021x::EAP_PHASE2>::Iterator it = _allowed_methods.begin(); it != _allowed_methods.end(); ++it)
	{
		if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_NONE)
		{
			cboPhase2Method->insertItem(i18n("None"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_NONE;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_MSCHAPV2)
		{
			cboPhase2Method->insertItem(i18n("MSCHAPv2"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_MSCHAPV2;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_PAP)
		{	
			cboPhase2Method->insertItem(i18n("PAP"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_PAP;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_CHAP)
		{
			cboPhase2Method->insertItem(i18n("CHAP"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_CHAP;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_MSCHAP)
		{
			cboPhase2Method->insertItem(i18n("MSCHAP"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_MSCHAP;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_GTC)
		{
			cboPhase2Method->insertItem(i18n("GTC"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_GTC;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_OTP)
		{
			cboPhase2Method->insertItem(i18n("OTP"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_OTP;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_MD5)
		{
			cboPhase2Method->insertItem(i18n("MD5"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_MD5;
			index++;
		}
		else if ((*it) == IEEE8021x::EAP_PHASE2_AUTH_TLS)
		{
			cboPhase2Method->insertItem(i18n("TLS"), index);
			_eapIndexMap[index] = IEEE8021x::EAP_PHASE2_AUTH_TLS;
			index++;
		}
	}

	// preselect the correct method
	QBiDirectionalMap<int, IEEE8021x::EAP_PHASE2>::Iterator it = _eapIndexMap.findData(_security_setting->getPhase2EAP());
	if (it != _eapIndexMap.end())
	{
		cboPhase2Method->setCurrentItem(it.key());
		_security_setting->setPhase2EAP(it.data());
	}
	else
	{
		cboPhase2Method->setCurrentItem(0);
		_security_setting->setPhase2EAP(_eapIndexMap[0]);
	}
}

void WirelessSecurityPhase2Impl::setAllowedPhase2Methods(const QValueList<IEEE8021x::EAP_PHASE2>& list)
{
	_allowed_methods = list;
	updateMethodComboBox();
}

void WirelessSecurityPhase2Impl::slotPhase2MethodChanged(int index)
{
	// new method choosen
	IEEE8021x::EAP_PHASE2 eap = _eapIndexMap[index];
	_security_setting->setPhase2EAP(eap);
}

/*
	class WirelessSecurityWidgetImpl
*/

WirelessSecurityWidgetImpl::WirelessSecurityWidgetImpl(Connection* conn, bool new_conn, QWidget* parent, const char* name, WFlags fl)
	: WidgetInterface(parent, name, fl)
{
	_security_setting = dynamic_cast<WirelessSecurity*> (conn->getSetting(NM_SETTING_WIRELESS_SECURITY_SETTING_NAME));
	_wireless_setting = dynamic_cast<Wireless*> (conn->getSetting(NM_SETTING_WIRELESS_SETTING_NAME));
	_ieee8021x_setting = dynamic_cast<IEEE8021x*> (conn->getSetting(NM_SETTING_802_1X_SETTING_NAME));
	_new_conn = new_conn;

	QVBoxLayout* layout = new QVBoxLayout(this, 1, 1);
	_mainWid = new ConnectionSettingWirelessSecurityWidget(this);
	layout->addWidget(_mainWid);

	QTimer::singleShot(0, this, SLOT(slotInit()));	
}

void
WirelessSecurityWidgetImpl::slotInit()
{
	// create all security widgets...
	QWidget* wep = new WirelessSecurityWEPImpl(_security_setting, _mainWid->groupUseEncryption);
	QWidget* phase2 = new WirelessSecurityPhase2Impl(_ieee8021x_setting, _mainWid->groupUseEncryption);
	QWidget* eap = new WirelessSecurityEAPImpl(_ieee8021x_setting, (WirelessSecurityPhase2Impl*)phase2, _mainWid->groupUseEncryption);
	QWidget* wpaversion = new WirelessSecurityWPAVersionImpl(_security_setting, _mainWid->groupUseEncryption);
	QWidget* wpacipher = new WirelessSecurityWPACipherImpl(_security_setting, _mainWid->groupUseEncryption);
	QWidget* wpapsk = new WirelessSecurityWPAPSKImpl(_security_setting, _wireless_setting, _mainWid->groupUseEncryption);
	QWidget* wepencryption = new WirelessSecurityWEPEncryptionImpl(_security_setting, _mainWid->groupUseEncryption);

	wep->setHidden(true);
	eap->setHidden(true);
	wpaversion->setHidden(true);
	wpacipher->setHidden(true);
	phase2->setHidden(true);
	wpapsk->setHidden(true);
	wepencryption->setHidden(true);

	_widgets[SECURITY_WEP].clear();
	_widgets[SECURITY_WPA_PSK].clear();
	_widgets[SECURITY_WPA_EAP].clear();
	_widgets[SECURITY_IEEE8021X].clear();

	// create WEP widget list
	_widgets[SECURITY_WEP].append(wep);

	// create WPA PSK widget list
	_extra_widgets[SECURITY_WPA_PSK].append(wpaversion);
	_extra_widgets[SECURITY_WPA_PSK].append(wpacipher);
	_widgets[SECURITY_WPA_PSK].append(wpapsk);

	// create WPA EAP widget list
	_extra_widgets[SECURITY_WPA_EAP].append(wpaversion);
	_extra_widgets[SECURITY_WPA_EAP].append(wpacipher);
	_widgets[SECURITY_WPA_EAP].append(eap);
	_widgets[SECURITY_WPA_EAP].append(phase2);

	// create IEEE8021X widget list
	_widgets[SECURITY_IEEE8021X].append(wepencryption);
	_widgets[SECURITY_IEEE8021X].append(eap);

	connect(_mainWid->cboSecurity, SIGNAL(activated(int)), this, SLOT(slotComboSecurityActivated(int)));
	connect(_mainWid->groupUseEncryption, SIGNAL(toggled(bool)), this, SLOT(slotUseEncryptionToggled(bool)));
	connect(_mainWid->pbExtra, SIGNAL(toggled(bool)), this, SLOT(slotExtraSettingsToggled(bool)));

}

void
WirelessSecurityWidgetImpl::Activate()
{
	kdDebug() << "Activate " << (_new_conn ? "New" : "Edit") << endl;
	comboSecurityInit();
}

void
WirelessSecurityWidgetImpl::comboSecurityInit()
{
	int index = 0;

	QValueList<SecurityMethods> allowed_methods;
	_mainWid->cboSecurity->clear();

	// TODO: Preselect the right security method
	// We should have an Essid already, fetch all possible APs
	QValueList<AccessPoint *> aps;
	if (_new_conn && !_wireless_setting->getEssid().isEmpty())
	{
		aps = WirelessManager::getAccessPointsForEssid(_wireless_setting->getEssid());
#if 0
		kdDebug() << "Hugo " << QString(QCString(_wireless_setting->getEssid())).ascii() << endl;
#endif
	}
	if (!aps.isEmpty())
	{
		// if at least one AP has this security setting show the entry in the combobox
		for (QValueList<AccessPoint*>::Iterator it = aps.begin(); it != aps.end(); ++it)
		{
			if((*it)->isEncrypted())
			{
				kdDebug() << "AP " << (*it)->getDisplaySsid().ascii() << " is encrypted" << endl;
				if ((*it)->getRsnFlags() != NM_802_11_AP_SEC_NONE || (*it)->getWpaFlags() != NM_802_11_AP_SEC_NONE)
				{
					// WPA or RSN
					if ((*it)->getRsnFlags() & NM_802_11_AP_SEC_KEY_MGMT_PSK || (*it)->getWpaFlags() & NM_802_11_AP_SEC_KEY_MGMT_PSK)
						if (!allowed_methods.contains(SECURITY_WPA_PSK))
							allowed_methods.append(SECURITY_WPA_PSK);

			
					if ((*it)->getRsnFlags() & NM_802_11_AP_SEC_KEY_MGMT_802_1X || (*it)->getWpaFlags() & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
						if (!allowed_methods.contains(SECURITY_WPA_EAP))
							allowed_methods.append(SECURITY_WPA_EAP);
				}

				// No WPA & RSN => WEP or dynamic WEP with 802.1x authentication
				// TODO: an AP can provide WEP in addition to WPA
				if (!allowed_methods.contains(SECURITY_WEP))
					allowed_methods.append(SECURITY_WEP);
				if (!allowed_methods.contains(SECURITY_IEEE8021X))
					allowed_methods.append(SECURITY_IEEE8021X);		
			}
		}

		// insert only allowed security methods
		if (allowed_methods.contains(SECURITY_WPA_PSK))
		{
			_securityComboMap.insert(index, SECURITY_WPA_PSK);
			_mainWid->cboSecurity->insertItem(i18n("WPA Personal"), index++);
		}

		if (allowed_methods.contains(SECURITY_WPA_EAP))
		{
			_securityComboMap.insert(index, SECURITY_WPA_EAP);
			_mainWid->cboSecurity->insertItem(i18n("WPA Enterprise"), index++);
		}

		if (allowed_methods.contains(SECURITY_WEP))
		{
			_securityComboMap.insert(index, SECURITY_WEP);
			_mainWid->cboSecurity->insertItem(i18n("WEP"), index++);
		}

		if (allowed_methods.contains(SECURITY_IEEE8021X))
		{
			_securityComboMap.insert(index, SECURITY_IEEE8021X);
			_mainWid->cboSecurity->insertItem(i18n("IEEE 802.1X"), index++);
		}
	}
	else
	{
		// insert all possible authentication methods
		_mainWid->cboSecurity->insertItem(i18n("WEP"),SECURITY_WEP );
		_mainWid->cboSecurity->insertItem(i18n("WPA Personal"), SECURITY_WPA_PSK);
		_mainWid->cboSecurity->insertItem(i18n("WPA Enterprise"), SECURITY_WPA_EAP);
		_mainWid->cboSecurity->insertItem(i18n("IEEE 802.1X"), SECURITY_IEEE8021X);
		_securityComboMap.insert(SECURITY_WEP, SECURITY_WEP);
		_securityComboMap.insert(SECURITY_WPA_PSK, SECURITY_WPA_PSK);
		_securityComboMap.insert(SECURITY_WPA_EAP, SECURITY_WPA_EAP);
		_securityComboMap.insert(SECURITY_IEEE8021X, SECURITY_IEEE8021X);
	}

	if (!_new_conn)
	{
		switch(_security_setting->getKeyMgmt())
		{
			case WirelessSecurity::KEY_MGMT_NONE:
				if (_security_setting->getAuthAlg() == WirelessSecurity::AUTH_ALG_SHARED ||
				    !_security_setting->getWepKey(0).isEmpty() ||
				    !_security_setting->getWepKey(1).isEmpty() ||
				    !_security_setting->getWepKey(2).isEmpty() ||
				    !_security_setting->getWepKey(3).isEmpty() )
				{
					_mainWid->groupUseEncryption->setChecked(true);
					_mainWid->cboSecurity->setCurrentItem(SECURITY_WEP);
					slotComboSecurityActivated(_securityComboMap[SECURITY_WEP]);
				}
				else
					_mainWid->groupUseEncryption->setChecked(false);
				break;
			case WirelessSecurity::KEY_MGMT_WPA_PSK:
				_mainWid->groupUseEncryption->setChecked(true);
				_mainWid->cboSecurity->setCurrentItem(SECURITY_WPA_PSK);
				slotComboSecurityActivated(_securityComboMap[SECURITY_WPA_PSK]);
				break;
			case WirelessSecurity::KEY_MGMT_WPA_EAP:
				_mainWid->groupUseEncryption->setChecked(true);
				_mainWid->cboSecurity->setCurrentItem(SECURITY_WPA_EAP);
				slotComboSecurityActivated(_securityComboMap[SECURITY_WPA_EAP]);
				break;
			case WirelessSecurity::KEY_MGMT_IEEE8021X:
				_mainWid->groupUseEncryption->setChecked(true);
				_mainWid->cboSecurity->setCurrentItem(SECURITY_IEEE8021X);
				slotComboSecurityActivated(_securityComboMap[SECURITY_IEEE8021X]);
				break;

			default:
				break;
		}
	}
	else
	{
		// select first possible security method
		if (_mainWid->cboSecurity->count() > 0)
		{
			_mainWid->groupUseEncryption->setChecked(true);
			_mainWid->groupUseEncryption->setEnabled(true);
			_mainWid->cboSecurity->setCurrentItem(0);
			slotComboSecurityActivated(0);
		}
		else
		{
			_mainWid->groupUseEncryption->setChecked(false);
			_mainWid->groupUseEncryption->setEnabled(false);
		}
	}
}

void
WirelessSecurityWidgetImpl::slotUseEncryptionToggled(bool on)
{
	_wireless_setting->setSecurity(on ? _security_setting->getType() : NULL);
}

void
WirelessSecurityWidgetImpl::slotComboSecurityActivated(int index)
{
	int i = _securityComboMap[index];

	// authentication switched, we have to show the appropriate widgets and hide some others
	switch(i)
	{
		case SECURITY_WEP:
			configureForWEP();
			break;

		case SECURITY_WPA_PSK:
			configureForWPAPSK();
			break;

		case SECURITY_WPA_EAP:
			configureForWPAEAP();
			break;

		case SECURITY_IEEE8021X:
			configureForIEEE8021X();
			break;

		default:
			// should not happen, something is broken...
			break;
	}
}

void
WirelessSecurityWidgetImpl::configureWidgets(SecurityMethods method)
{
	// store selected method
	_currentMethod = method;

	for (int i = 0; i < SECURITY_COUNT; ++i)
	{
		// remove all current widgets that do not belong to the selected method
		if (i != method)
		{
			for (QValueList<QWidget*>::iterator it = _widgets[i].begin(); it != _widgets[i].end(); ++it)
			{
				_mainWid->groupUseEncryption->layout()->remove(*it);
				(*it)->hide();
			}
			// remove extra widgets too
			for (QValueList<QWidget*>::iterator it = _extra_widgets[i].begin(); it != _extra_widgets[i].end(); ++it)
			{
				_mainWid->groupUseEncryption->layout()->remove(*it);
				(*it)->hide();
			}
		}
	}

	// show all widgets widgets for the selected security method
	for (QValueList<QWidget*>::iterator it = _widgets[method].begin(); it != _widgets[method].end(); ++it)
	{
		_mainWid->groupUseEncryption->layout()->add(*it);
		(*it)->show();
	}

	if (_mainWid->pbExtra->isOn())
		for (QValueList<QWidget*>::iterator it = _extra_widgets[method].begin(); it != _extra_widgets[method].end(); ++it)
		{
			_mainWid->groupUseEncryption->layout()->add(*it);
			(*it)->show();
		}

	// deactivate button if no extra settings are available
	_mainWid->pbExtra->setEnabled(!(_extra_widgets[method].begin() == _extra_widgets[method].end()));
}

void
WirelessSecurityWidgetImpl::slotExtraSettingsToggled(bool on)
{
	if (on)
		for (QValueList<QWidget*>::iterator it = _extra_widgets[_currentMethod].begin(); it != _extra_widgets[_currentMethod].end(); ++it)
		{
			_mainWid->groupUseEncryption->layout()->add(*it);
			(*it)->show();
		}
	else
		for (QValueList<QWidget*>::iterator it = _extra_widgets[_currentMethod].begin(); it != _extra_widgets[_currentMethod].end(); ++it)
		{
			_mainWid->groupUseEncryption->layout()->remove(*it);
			(*it)->hide();
		}
}

void
WirelessSecurityWidgetImpl::configureForWEP()
{
	_security_setting->setKeyMgmt(WirelessSecurity::KEY_MGMT_NONE);
	configureWidgets(SECURITY_WEP);
}

void
WirelessSecurityWidgetImpl::configureForWPAPSK()
{
	_security_setting->setKeyMgmt(WirelessSecurity::KEY_MGMT_WPA_PSK);
	configureWidgets(SECURITY_WPA_PSK);
}

void
WirelessSecurityWidgetImpl::configureForWPAEAP()
{
	_security_setting->setKeyMgmt(WirelessSecurity::KEY_MGMT_WPA_EAP);
	configureWidgets(SECURITY_WPA_EAP);
}

void
WirelessSecurityWidgetImpl::configureForIEEE8021X()
{
	_security_setting->setKeyMgmt(WirelessSecurity::KEY_MGMT_IEEE8021X);
	configureWidgets(SECURITY_IEEE8021X);
}




#include "knetworkmanager-connection_setting_wireless_security_widget.moc"
