/***************************************************************************
*   Copyright (C) 2004 by Christoph Thielecke                             *
*   crissi99@gmx.de                                                       *
*                                                                         *
*   @description This class imports a openvpn configuration file                             *
*                                                                         *
*   @author Christoph Thielecke <crissi99@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.             *
***************************************************************************/
//BEGIN INCLUDES
#include <kmessagebox.h>
#include <kio/netaccess.h>
#include <ktempfile.h>
#include <klocale.h>
#include <kconfig.h>
#include <kdialogbase.h>
#include <kcombobox.h>
#include <kurlrequester.h>
#include <klineedit.h>
#include <kpassdlg.h>
#include <qfile.h>
#include <qurl.h>
#include <kurl.h>
#include <qtextstream.h>
#include <qcheckbox.h>
#include <string>

#include <iostream>

#include "importopenvpnprofiledialog.h"
#include "utils.h"
#include "importcertificatedialog.h"
//END INCLUDES

ImportOpenvpnProfileDialog::ImportOpenvpnProfileDialog(KVpncConfig *config, QWidget *parent, const QString& caption)
		: KDialogBase( parent, "Import_Cisco_OpenVPN_profile", true, caption,
		               KDialogBase::Ok|KDialogBase::Cancel, KDialogBase::Ok, true )
{
	filename = "";
	Pkcs12CertFile="";
	CertPath="";
	importOk = false;
	this->config = config;

	main = new ImportOpenvpnProfileDialogBase(this);
	setMainWidget(main);
	//main->setMinimumSize(main->sizeHint());

	main->FilenameUrlrequester->setFilter( "*.ovpn *.conf" );

	main->FilenameUrlrequester->setURL(filename);

}

ImportOpenvpnProfileDialog::~ImportOpenvpnProfileDialog()
{
	delete main;
}

void ImportOpenvpnProfileDialog::accept()
{

	filename = main->FilenameUrlrequester->url();
	if ( !filename.isEmpty() )
	{
		if (config->KvpncDebugLevel > 0)
			config->appendLogEntry( i18n( "OpenVPN import: file: %1" ).arg(filename),config->debug );
		canAccept();
	}
	else
	{
		config->appendLogEntry( i18n( "OpenVPN import: file name empty" ),config->error );
		KMessageBox::sorry( 0, i18n( "File name can not be empty!" ), i18n( "Empty File Name" ) );
	}
}

void ImportOpenvpnProfileDialog::canAccept()
{

	QFile f( filename );
	if ( !f.exists() )
	{
		KMessageBox::information( 0, i18n( "File not found." ), i18n( "No File" ) );

		//		emit progress( 100 );
		return ;
	}

	//BEGIN Sample
	// sample config

	/*
	#
	# Sample OpenVPN configuration file for
	# home using SSL/TLS mode and RSA certificates/keys.
	#
	# '#' or ';' may be used to delimit comments.

	#######################################################
	# PATS INFORMATION:
	# No adaptations necessary in this file, unless you
	# give different names to your certificates or you
	# place them in different folders
	######################################################


	# Use a dynamic tun device.
	# For Linux 2.2 or non-Linux OSes,
	# you may want to use an explicit
	# unit number such as "tun1".
	# OpenVPN also supports virtual
	# ethernet "tap" devices.
	dev tap

	# Our OpenVPN peer is the PATS gateway.
	remote 143.129.70.202

	float

	# In SSL/TLS key exchange, Office will
	# assume server role and Home
	# will assume client role.
	tls-client

	# pull necessary here. This option will
	# enable the server to push commands to
	# the client
	pull

	route 10.0.0.0 255.255.0.0 vpn_gateway

	# Certificate Authority file
	ca cacert.pem

	# Our certificate/public key
	cert cert.pem

	# Our private key
	key key.pem

	# OpenVPN uses UDP port 5000 by default.
	port 5000

	# Downgrade UID and GID to
	# "nobody" after initialization
	# for extra security.
	; user nobody
	; group nobody

	# If you built OpenVPN with
	# LZO compression, uncomment
	# out the following line.
	# PREFFERED
	comp-lzo

	# Uncomment this section for a more reliable detection when a system
	# loses its connection.  For example, dial-ups or laptops that
	# travel to other locations.
	# This commands will be pushed through by the server
	; ping 15
	; ping-restart 45
	; ping-timer-rem
	; persist-tun
	; persist-key

	# Verbosity level.
	# 0 -- quiet except for fatal errors.
	# 1 -- mostly quiet, but display non-fatal network errors. PREFERRED
	# 3 -- medium output, good for normal operation.
	# 9 -- verbose, good for troubleshooting
	verb 1
	*/

	/* Example 2
	client
	dev tun

	proto udp
	remote 10.7.21.1 1194

	resolv-retry infinite
	ns-cert-type server
	nobind
	user nobody
	group nogroup
	persist-key
	persist-tun

	ca certs/richard-root-ca.crt
	cert certs/richard-openvpn-notebook-richard.crt
	key certs/richard-openvpn-notebook-richard.key

	cipher AES-128-CBC
	ping 15
	ping-restart 45
	ping-timer-rem
	persist-tun
	persist-key

	comp-lzo
	verb 3
	*/
	//END Sample

	QFile OpenvpnConfigFile(filename);
	QTextStream stream ( &OpenvpnConfigFile );

	if ( OpenvpnConfigFile.open(IO_ReadOnly))
	{
		VpnAccountData::ConnectionType ConnType = VpnAccountData::openvpn;
		acc = new VpnAccountData ( ConnType, "" );
		acc->setName( filename.section('/',-1,-1).section('.', -2,-2) );// /home/user/openvpn/CompanyABC.conf -> CompanyABC
		acc->setDescription( i18n("Imported from %1").arg(filename.section('/',-1,-1)));
		acc->setLocalPort(1194);
		acc->setAuthWithUsernameAndPassword( false );
		acc->setRemoteNetMask( "24" );

		acc->setUseTlsAuth( false );
// 		acc->setUseConnectionStatusCheck( false );
// 		acc->setDoReconnectAfterConnectionLost( false );

		QString line = "";
		while ( !stream.atEnd() )
		{
			line = stream.readLine().simplifyWhiteSpace(); // line of text excluding '\n' and replace all white chars with one blank
			if ( !line.startsWith("#") )
			{

				if (line.startsWith("remote "))
				{
					acc->setGateway( line.section(' ', 1,1) ); // IP address
					if (!line.section(' ',2,2).isEmpty())
					{
						acc->setUseRemotePort( true);
						acc->setRemotePort (line.section(' ',2,2).toInt());

						if (config->KvpncDebugLevel > 0)
							config->appendLogEntry( i18n( "OpenVPN import: use userdefinied remote port: %1" ).arg(acc->getRemotePort() ),config->debug );
					}
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: gateway: %1" ).arg(acc->getGateway()),config->debug );
				}

				else if (line.startsWith("dev "))
				{
					acc->setTunnelDeviceType( line.section(' ', 1,1) ); // tun or tap
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: tunnel device type: %1" ).arg(acc->getTunnelDeviceType()),config->debug );
				}

				else if (line.startsWith("route "))
				{
					// FIXME no fully supported yet!!!

					// FIXME made it possible to remember what type have to been set!
					QString gateway_type ="";
					bool useGateway;
					acc->setUseAdditionalNetworkRoutes(true);
					QStringList AdditionalNetworkRoutes;
					// example entry:
					// <network>/<netmask>#<gateway>

					QString network = line.section(' ', 1,1)+"/"+line.section(' ',2,2); // ip and netmask

					QString Part3 = line.section(' ',3,3); // possible gateway
					if (Part3 != "vpn_gateway" && Part3 != "net_gateway" && Part3 != "remote_host" )
					{
						network.append("#");
						network.append(Part3); // gateway
						gateway_type = line.section(' ',3,3);
						useGateway=true;
					}
					else
					{
						gateway_type = Part3;
					}

					AdditionalNetworkRoutes.append(network);
					acc->setAdditionalNetworkRoutes(AdditionalNetworkRoutes);

					if (config->KvpncDebugLevel > 0)
						if (useGateway)
							config->appendLogEntry( i18n( "OpenVPN import: special route found: %1, type: %2" ).arg(network).arg(gateway_type),config->debug );
						else
							config->appendLogEntry( i18n( "OpenVPN import: special route found: %1 over %3, type: %2" ).arg(network).arg(gateway_type).arg(Part3),config->debug );
				}

				else if (line.startsWith("port "))
				{
					acc->setUseLocalPort( true );
					acc->setLocalPort( line.section(' ',1,1).toInt());
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: local port specified: %1" ).arg(acc->getLocalPort()),config->debug );
				}

				else if (line.startsWith("comp-lzo"))
				{
					acc->setDisableLzoCompression(false);
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: use LZO compression" ),config->debug );
				}

				else if (line.startsWith("cert "))
				{
					acc->setAuthType( VpnAccountData::cert );
					if (CertPath.isEmpty())
						acc->setX509Certificate( line.section(' ',1,1));
					else
						acc->setX509Certificate( CertPath+"/"+line.section(' ',1,1));
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: certificate: %1" ).arg(acc->getX509Certificate()),config->debug );
				}

				else if (line.startsWith("key "))
				{
					acc->setAuthType( VpnAccountData::cert );
					if (CertPath.isEmpty())
						acc->setPrivateKey(line.section(' ',1,1));
					else
						acc->setPrivateKey(CertPath+"/"+line.section(' ',1,1));
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: PSK in file: %1" ).arg(acc->getPrivateKey()),config->debug );
				}

				else if (line.startsWith("ca "))
				{
					acc->setAuthType( VpnAccountData::cert );
					if (CertPath.isEmpty())
						acc->setCaCertificate(line.section(' ',1,1));
					else
						acc->setCaCertificate(CertPath+"/"+line.section(' ',1,1));
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: CA certificate: %1" ).arg(acc->getCaCertificate()),config->debug );
				}

				else if (line.startsWith("proto "))
				{
					if (line.section(' ',1,1) == "udp")
					{
						acc->setUseUdp(true);
						if (config->KvpncDebugLevel > 0)
							config->appendLogEntry( i18n( "OpenVPN import: use UDP" ),config->debug );
					}
					else if (line.section(' ',1,1) == "tcp-client")
					{
						acc->setUseUdp(false);
						if (config->KvpncDebugLevel > 0)
							config->appendLogEntry( i18n( "OpenVPN import: dont use UDP" ),config->debug );
					}

				}

				else if (line.startsWith("cipher "))
				{
					acc->setUseUserdefiniedCipher(true);
					acc->setUserdefiniedCipher(line.section(' ',1,1));
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: use userdefinied cipher" ),config->debug );
				}

				else if (line.startsWith("tls-auth "))
				{
					acc->setUseTlsAuth(true);
					acc->setTlsAuthFile(line.section(' ',1,1));
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: use TLS auth" ),config->debug );
				}

				else if (line.startsWith("redirect-gateway"))
				{
					acc->setUseRedirectGateway(true);
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: use redirect gateway" ),config->debug );
				}

				else if (line.startsWith("ns-cert-type "))
				{
					acc->setUseNsCertType(true);

					if (line.section(' ',1,1) == "client")
					{
						acc->setNsCertType( "client" );
						if (config->KvpncDebugLevel > 0)
							config->appendLogEntry( i18n( "OpenVPN import: use NS certificate type: %1" ).arg("client"),config->debug );
					}
					if (line.section(' ',1,1) == "server")
					{
						acc->setNsCertType( "server" );
						if (config->KvpncDebugLevel > 0)
							config->appendLogEntry( i18n( "OpenVPN import: use NS certificate type: %1" ).arg("server"),config->debug );
					}
				}

				else if (line.startsWith("auth-user-pass"))
				{
					acc->setAuthWithUsernameAndPassword(true);
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: authenticate with username and password" ),config->debug );
				}

				else if (line.startsWith("http-proxy "))
				{
					acc->setUseHttpProxy( true );
					acc->setHttpProxy( line.section(' ',1,1 ));
					acc->setHttpProxyPort( line.section(' ',2,2 ).toInt());
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: use HTTP proxy: %1, Port: %2" ).arg(acc->getHttpProxy()).arg(QString().setNum(acc->getHttpProxyPort())),config->debug );
				}

				else if (line.startsWith("http-proxy-timeout "))
				{
					acc->setUseHttpProxy( true );
					acc->setHttpProxyTimeout( line.section(' ',1,1 ).toInt());
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: use NS certificate type: %1" ).arg(QString().setNum(acc->getHttpProxyTimeout())),config->debug );
				}

				else if (line.startsWith("pkcs12 "))
				{
					acc->setAuthType( VpnAccountData::cert );
					Pkcs12CertFile =  line.section(' ', 1,1);
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: pkcs12 file found: %1" ).arg(Pkcs12CertFile),config->debug );
				}

				else if (line.startsWith("cd "))
				{
					CertPath= line.section(' ',1,1);

					/* we need to put the prefix to all cert paths */
					if (!acc->getCaCertificate().isEmpty() && !acc->getCaCertificate().startsWith(CertPath))
						acc->setCaCertificate(CertPath+"/"+acc->getCaCertificate());

					if ( !acc->getX509Certificate().isEmpty() && !acc->getCaCertificate().startsWith(CertPath))
						acc->setX509Certificate(CertPath+"/"+acc->getX509Certificate());

					if ( !acc->getPreSharedKey().isEmpty() && !acc->getCaCertificate().startsWith(CertPath))
						acc->setPreSharedKey(CertPath+"/"+acc->getPreSharedKey());

					if (!Pkcs12CertFile.isEmpty() && !acc->getCaCertificate().startsWith(CertPath))
						Pkcs12CertFile=CertPath+"/"+Pkcs12CertFile;


					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: certificate prefix found: %1" ).arg(CertPath),config->debug );
				}

				else if (line.startsWith("tls-remote"))
				{
					acc->setUseTlsRemoteHost(true);
					acc->setTlsRemoteHost(line.section(' ',1,1 ));
					if (config->KvpncDebugLevel > 0)
						config->appendLogEntry( i18n( "OpenVPN import: use tls remote host: %1" ).arg(acc->getTlsRemoteHost()),config->debug );
				}

			}
		}
		OpenvpnConfigFile.close();
	}

	importOk = true;

	if (!Pkcs12CertFile.isEmpty())
	{

		QString filepath= filename.section('/',0,-2); // should give the base path

		ImportCertificateDialog dlg( this, i18n("Import Certificate...").ascii(), config);

		QString p12file= filepath+"/"+Pkcs12CertFile;

		dlg.main->ImporttypeComboBox->setCurrentItem(ImportCertificateDialog::pkcs12_openvpn);
		dlg.main->ImporttypeComboBox->setEnabled(false);
		// 		dlg.main->RacoonCertificatePathUrlrequester->setEnabled(true);
		dlg.main->RacoonCertificatePathUrlrequester->setURL("/etc/openvpn");
		dlg.main->FreeswanGroupBox->setEnabled(false);
		dlg.main->PrivateKeyPasswordEdit->setEnabled( true );
		dlg.main->PrivateKeyAgainPasswordEdit->setEnabled( true );

		dlg.main->FilenameUrlrequester->setURL(p12file);
		dlg.main->ImportPasswordEdit->setEnabled( true );
		dlg.main->P12GroupBox->setEnabled( true );
		dlg.main->FreeswanGroupBox->setEnabled( false );
		dlg.main->FilenameUrlrequester->setFilter( "*.p12" );

		dlg.main->ImportPasswordEdit->setFocus();

		int result = dlg.exec();

		if (result == QDialog::Accepted)
		{
			if (dlg.importSuccess)
			{
				config->appendLogEntry( i18n( "OpenVPN import: import of pkcs12 certificate file %1 was successful." ).arg(Pkcs12CertFile),config->info );
				importOk=true;

				acc->setX509Certificate( dlg.main->RacoonCertificatePathUrlrequester->url()+"/mykeys_" + (p12file.left( p12file.length() - 4 )).section('/',-1,-1) + ".pem");
				acc->setPrivateKey( dlg.main->RacoonCertificatePathUrlrequester->url()+"/mykeys_" + (p12file.left( p12file.length() - 4 )).section('/',-1,-1) + ".pem");
				acc->setCaCertificate( dlg.main->RacoonCertificatePathUrlrequester->url()+"/ca_" + (p12file.left( p12file.length() - 4 )).section('/',-1,-1) + ".pem");
				acc->setCertPath( dlg.main->RacoonCertificatePathUrlrequester->url() );
				acc->setPrivateKeyPass( dlg.main->ImportPasswordEdit->text() );


			}
			else
			{
				config->appendLogEntry( i18n( "OpenVPN import: import of pkcs12 certificate file %1 failed!" ).arg(Pkcs12CertFile),config->error );
				importOk=false;
			}
		}
		else
		{
			config->appendLogEntry( i18n( "OpenVPN import: import of pkcs12 certificate file was cancelled." ).arg(Pkcs12CertFile),config->info );
			importOk=false;
		}

	}

	//std::cout << "accept" << std::endl;
	QDialog::accept();
}


#include "importopenvpnprofiledialog.moc"
