/***************************************************************************
 *
 * tdenetman-vpnc.cpp - A NetworkManager frontend for TDE
 *
 * Copyright (C) 2006 Novell, Inc.
 * Copyright (C) 2012 Timothy Pearson <kb9vqf@pearsoncomputing.net>
 *
 * Author: Helmut Schaa <hschaa@suse.de>, <Helmut.Schaa@gmx.de>
 * Author: Timothy Pearson <kb9vqf@pearsoncomputing.net>
 *
 * 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
 *
 **************************************************************************/

#include <tdelocale.h>
#include <tdemessagebox.h>
#include <tqmessagebox.h>
#include <tqbutton.h>
#include <kcombobox.h>
#include <klineedit.h>
#include <kurlrequester.h>
#include <tqobjectlist.h>
#include <tqobject.h>
#include <tqcheckbox.h>
#include <kpassdlg.h>
#include <kgenericfactory.h>
#include <tqlabel.h>
#include <string>
#include <stdio.h>

#include "tdenetman-vpnc.h"
using namespace std;

typedef KGenericFactory<VPNCPlugin> VPNCPluginFactory;
K_EXPORT_COMPONENT_FACTORY(tdenetman_vpnc, VPNCPluginFactory("tdenetman_vpnc"));

#define NAT_MODE_CISCO 0
#define NAT_MODE_NATT 1
#define NAT_MODE_DISABLED 2

char linedata [2048];

VPNCPlugin::VPNCPlugin(TQObject* parent, const char* name, const TQStringList& args) 
	: VPNPlugin(parent, name, args)
{
	TDELocale* loc = TDEGlobal::locale();
	loc->insertCatalogue("NetworkManager-vpnc");
}

VPNCPlugin::~VPNCPlugin()
{

}

VPNConfigWidget* VPNCPlugin::CreateConfigWidget(TQWidget* parent)
{
	return new VPNCConfig(parent);
}

VPNAuthenticationWidget* VPNCPlugin::CreateAuthenticationWidget(TQWidget* parent)
{
	return new VPNCAuthentication(parent);
}


VPNCConfig::VPNCConfig(TQWidget* parent)
	: VPNConfigWidget(parent)
{
	TQVBoxLayout* layout = new TQVBoxLayout(this, 1, 1);
	_vpncWidget = new VPNCConfigWidget(this);
	layout->addWidget(_vpncWidget);

	connect(_vpncWidget->pcfImport, TQ_SIGNAL(clicked()), this, TQ_SLOT( pcfImport()) );	

	//connect(_vpncWidget->chkOverrideUsername, TQ_SIGNAL(toggled(bool)), _vpncWidget->Xauth_username, TQ_SLOT(setEnabled(bool)));
	//connect(_vpncWidget->chkOverrideUsername, TQ_SIGNAL(toggled(bool)), _vpncWidget->lblUsername, TQ_SLOT(setEnabled(bool)));

	connect(_vpncWidget->chkUseDomain, TQ_SIGNAL(toggled(bool)), _vpncWidget->Domain, TQ_SLOT(setEnabled(bool)));
	connect(_vpncWidget->chkUseDomain, TQ_SIGNAL(toggled(bool)), _vpncWidget->lblDomain, TQ_SLOT(setEnabled(bool)));

	connect(_vpncWidget->chkIPAdresses, TQ_SIGNAL(toggled(bool)), _vpncWidget->routes, TQ_SLOT(setEnabled(bool)));

	connect(_vpncWidget->chkUseKeepAlive, TQ_SIGNAL(toggled(bool)), _vpncWidget->nat_keep_alive_interval, TQ_SLOT(setEnabled(bool)));
	connect(_vpncWidget->chkUseKeepAlive, TQ_SIGNAL(toggled(bool)), _vpncWidget->lblKeepAliveInterval, TQ_SLOT(setEnabled(bool)));

	_vpncWidget->cboNAT->insertItem(i18n("Cisco UDP (default)"), NAT_MODE_CISCO);
	_vpncWidget->cboNAT->insertItem(i18n("NAT-T"), NAT_MODE_NATT);
	_vpncWidget->cboNAT->insertItem(i18n("Disabled"), NAT_MODE_DISABLED);

	this->languageChange();
}

VPNCConfig::~VPNCConfig()
{

}

void VPNCConfig::languageChange()
{

}

int VPNCConfig::getFileConfig(const char *parameter, char *line) {
	int i;

	if (strstr(line, parameter) != NULL) {
		if ((strstr(line, parameter) - line) == 0) {
			for (i=0; i<(strlen(line)-strlen(parameter));i++) {
				linedata[i] = line[i+strlen(parameter)];
				if ((linedata[i] == 10) || (linedata[i] == 13)) {
					linedata[i] = 0;
				}
			}
			linedata[i-1]=0;

			return 0;
		}
		else {
			return 1;
		}
	}
	else {
		return 1;
	}
}

void VPNCConfig::pcfImport()
{
	const TQString& pcf_file = TQString(_vpncWidget->editPCF->url());
	printf("Asked for PCF import from file %s\n", pcf_file.ascii());

	FILE *file = fopen ( pcf_file.ascii(), "r" );
	if ( file != NULL ) {
		char line [2048];	// or other suitable maximum line size
		// read a line
		while ( fgets ( line, sizeof line, file ) != NULL ) {
			// Parse the line and update global variables (current line in variable "line")
			if (getFileConfig("Host=", line) == 0) {
				//strdup(linedata)
				printf("Got configuration parameter Host with data %s\n", linedata);
				_vpncWidget->IPSec_gateway->setText(linedata);
			}
			if (getFileConfig("GroupName=", line) == 0) {
				printf("Got configuration parameter GroupName with data %s\n", linedata);
				_vpncWidget->IPSec_ID->setText(linedata);
			}
// 			if (getFileConfig("TcpTunnelingPort=", line) == 0) {
// 				printf("Got configuration parameter TcpTunnelingPort with data %s\n", linedata);
// 				_vpncWidget->IPSec_ID->setText(linedata);
// 			}
			if (getFileConfig("NTDomain=", line) == 0) {
				if (strlen(linedata) > 0) {
					printf("Got configuration parameter NTDomain with data %s\n", linedata);
					_vpncWidget->Domain->setText(linedata);
					_vpncWidget->chkUseDomain->setChecked(true);
				}
			}
			if (getFileConfig("GroupPwd=", line) == 0) {
				if (strlen(linedata) > 0) {
					printf("Got configuration parameter GroupPwd with data %s\n", linedata);
					KMessageBox::information(this, TQString("Your group password is: %1\n\r\n\rYou will need this information when you log on").arg(linedata));
				}
			}
			if (getFileConfig("enc_GroupPwd=", line) == 0) {
				if (strlen(linedata) > 0) {
					printf("Got configuration parameter enc_GroupPwd with data %s\n", linedata);

					// Decrypt the obfusticated password with /usr/lib/vpnc/cisco-decrypt
					string decryptcommand="/usr/lib/vpnc/cisco-decrypt ";
					FILE *pipe_decrypt;
					char decrypted_result[2048];
					int i;

					decryptcommand.append(linedata);
					printf("Group password decrypt command: %s\n", decryptcommand.c_str());
					if ((pipe_decrypt = popen(decryptcommand.c_str(), "r")) == NULL)
					{
						printf("Group password decrypt error\n");
					}
					else {
						if (fgets(decrypted_result, 2048, pipe_decrypt) == NULL) {
							printf("Error reading from decryption program\n");
						}
						pclose(pipe_decrypt);
						for (i=0;i<2048;i++) {
							if (decrypted_result[i] == 0) {
								decrypted_result[i-1]=0;
								i=2048;
							}
						}
						printf("Group password decrypt result: '%s'\n", decrypted_result);
					}
					KMessageBox::information(this, TQString("Your group password is: %1\n\r\n\rYou will need this information when you log on").arg(decrypted_result));
				}
			}
		}
		fclose ( file );
	}
	else
	{
		//printf("[WARN] Unable to open configuration file %s\n", pcf_file.ascii());
		KMessageBox::error(this, i18n("That configuration file does not exist!"));
	}
}

void VPNCConfig::setVPNData(TDENetworkSingleRouteConfigurationList& routes, TDENetworkSettingsMap& properties, TDENetworkSettingsMap& secrets)
{
	m_vpnProperties = properties;
	m_vpnSecrets = secrets;

	// fill up our inputfields (only textfields atm)
	for (TDENetworkSettingsMap::ConstIterator it = properties.begin(); it != properties.end(); ++it) {
		TQString entry = it.key();
		TQString value = it.data();

		if (entry == "IPSec gateway")
		{
			_vpncWidget->IPSec_gateway->setText(value);
		}
		else if (entry == "IPSec ID")
		{
			_vpncWidget->IPSec_ID->setText(value);
		}
		else if (entry == "Xauth username")
		{
			_vpncWidget->Xauth_username->setText(value);
			//_vpncWidget->chkOverrideUsername->setChecked(true);
		}
		else if (entry == "Domain")
		{
			_vpncWidget->Domain->setText(value);
			_vpncWidget->chkUseDomain->setChecked(true);
		}
		else if (entry == "NAT-Keepalive packet interval")
		{
			_vpncWidget->nat_keep_alive_interval->setText(value);
			_vpncWidget->chkUseKeepAlive->setChecked(true);
		}
		// backwards compatibility
		else if (entry == "Disable NAT Traversal")
		{
			_vpncWidget->cboNAT->setCurrentItem(NAT_MODE_DISABLED);
		}
		else if (entry == "NAT Traversal Mode")
		{
			if (value == "natt")
				_vpncWidget->cboNAT->setCurrentItem(NAT_MODE_NATT);
			else if (value == "cisco-udp")
				_vpncWidget->cboNAT->setCurrentItem(NAT_MODE_CISCO);
			else if (value == "none")
				_vpncWidget->cboNAT->setCurrentItem(NAT_MODE_DISABLED);
			else
			{
				// FIXME: unknown NAT mode
			}
		}
		else if (entry == "Enable Single DES")
		{
			_vpncWidget->chkSingleDES->setChecked(value == "yes" || value == "true");
		}
	}

	// set routes
	if (!routes.empty())
	{
		_vpncWidget->chkIPAdresses->setChecked(true);
		TQStringList routesText;
		for (TDENetworkSingleRouteConfigurationList::Iterator it = routes.begin(); it != routes.end(); ++it) {
			routesText.append(TQString("%1/%2").arg((*it).ipAddress.toString()).arg((*it).networkMask.toCIDRMask()));
		}
		_vpncWidget->routes->setText(routesText.join(" "));
	}
}

TDENetworkSettingsMap VPNCConfig::getVPNProperties() {
	// Build a list of properties
	m_vpnProperties.insert("IPSec gateway", TQString(_vpncWidget->IPSec_gateway->text()));
	m_vpnProperties.insert("IPSec ID", TQString(_vpncWidget->IPSec_ID->text()));

	// if (_vpncWidget->chkOverrideUsername->isChecked()) {
		m_vpnProperties.insert("Xauth username", TQString(_vpncWidget->Xauth_username->text()));
	// }

	if (_vpncWidget->chkUseDomain->isChecked()) {
		m_vpnProperties.insert("Domain", TQString(_vpncWidget->Domain->text()));
	}
	else {
		m_vpnProperties.remove("Domain");
	}

	if (_vpncWidget->chkUseKeepAlive->isChecked()) {
		m_vpnProperties.insert("NAT-Keepalive packet interval", TQString(_vpncWidget->nat_keep_alive_interval->text()));
	}
	else {
		m_vpnProperties.remove("NAT-Keepalive packet interval");
	}

	switch (_vpncWidget->cboNAT->currentItem()) {
		case NAT_MODE_CISCO:
			m_vpnProperties.insert("NAT Traversal Mode", "cisco-udp");
			break;
		case NAT_MODE_NATT:
			m_vpnProperties.insert("NAT Traversal Mode", "natt");
			break;
		case NAT_MODE_DISABLED:
		default:
			m_vpnProperties.insert("NAT Traversal Mode", "none");
			break;
	}

	if (_vpncWidget->chkSingleDES->isChecked()) {
		m_vpnProperties.insert("Enable Single DES", "yes");
	}
	else {
		m_vpnProperties.insert("Enable Single DES", "no");
	}

	return m_vpnProperties;
}

TDENetworkSettingsMap VPNCConfig::getVPNSecrets() {
	// Build a list of secrets
	// FIXME

	return m_vpnSecrets;
}

TDENetworkSingleRouteConfigurationList VPNCConfig::getVPNRoutes()
{
	TDENetworkSingleRouteConfigurationList ret;
	TQStringList strlist;
	if(_vpncWidget->chkIPAdresses->isChecked()) {
		strlist = TQStringList::split(" ", _vpncWidget->routes->text());
	}

	for (TQStringList::Iterator it = strlist.begin(); it != strlist.end(); ++it) {
		TQStringList pieces = TQStringList::split("/", (*it));
		TDENetworkSingleRouteConfiguration routeconfig;
		routeconfig.ipAddress.setAddress(pieces[0]);
		if (pieces.count() > 1) {
			routeconfig.networkMask.fromCIDRMask(pieces[1].toUInt());
		}
		ret.append(routeconfig);
	}

	return ret;
}

bool VPNCConfig::hasChanged()
{
	return true;
}

bool VPNCConfig::isValid(TQStringList& err_msg)
{
	bool retval = true;
	if(_vpncWidget->IPSec_gateway->text() == "" || _vpncWidget->IPSec_ID->text() == "")
	{
		err_msg.append(i18n("At least the gateway and group has to be supplied."));
		retval = false;
	}
	return retval;
}

VPNCAuthentication::VPNCAuthentication(TQWidget* parent, char* name)
	: VPNAuthenticationWidget(parent, name)
{
	TQVBoxLayout* layout = new TQVBoxLayout(this, 1, 1);
	_vpncAuth = new VPNCAuthenticationWidget(this);
	layout->addWidget(_vpncAuth);
}

VPNCAuthentication::~VPNCAuthentication()
{

}

TDENetworkSettingsMap VPNCAuthentication::getPasswords()
{
	TDENetworkSettingsMap pwds;
	pwds.insert("Xauth password", _vpncAuth->editUserPassword->password());
	if (_vpncAuth->chkObfusticated->isChecked()) {
		// Decrypt the obfusticated password with /usr/lib/vpnc/cisco-decrypt
		string decryptcommand="/usr/lib/vpnc/cisco-decrypt ";
		FILE *pipe_decrypt;
		char decrypted_result[2048];
		int i;

		decryptcommand.append(_vpncAuth->editGroupPassword->password().local8Bit());
		printf("Group password decrypt command: %s\n", decryptcommand.c_str());
		if ((pipe_decrypt = popen(decryptcommand.c_str(), "r")) == NULL)
		{
			printf("Group password decrypt error\n");
		}
		else {
			if (fgets(decrypted_result, 2048, pipe_decrypt) == NULL) {
				printf("Error reading from decryption program\n");
			}
			pclose(pipe_decrypt);
			for (i=0;i<2048;i++) {
				if (decrypted_result[i] == 0) {
					decrypted_result[i-1]=0;
					i=2048;
				}
			}
			printf("Group password decrypt result: '%s'\n", decrypted_result);
			pwds.insert("IPSec secret", TQString(decrypted_result));
		}
	}
	else {
		pwds.insert("IPSec secret", _vpncAuth->editGroupPassword->password());
	}
	return pwds;
}

void VPNCAuthentication::setPasswords(TDENetworkSettingsMap secrets) {
	if (secrets.contains("Xauth password")) {
		_vpncAuth->editUserPassword->erase();
		_vpncAuth->editUserPassword->insert(secrets["Xauth password"]);
	}
	else if (secrets.contains("IPSec secret")) {
		_vpncAuth->editGroupPassword->erase();
		_vpncAuth->editGroupPassword->insert(secrets["IPSec secret"]);
	}
}

#include "tdenetman-vpnc.moc"
