/*****************************************************************************
 * Copyright (C) 2010 S.R.Haque <srhaque@theiet.org>                         *
 * Christoph Thielecke <crissi99@gmx.de> (contains code from kvpnc.cpp)      *
 *                                                                           *
 * 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 package 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 package; if not, write to the Free Software               *
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA *
 *****************************************************************************/

#include <QtCore/QProcess>
#include <klocale.h>
#include <kmessagebox.h>
#include <kprocess.h>
#include <kptyprocess.h>
#include <kstandarddirs.h>
#include <unistd.h>
#include "CiscoVpnclientHandler.h"
#include "enterxauthinteractivepasscodedialog.h"
#include "enterpassworddialog.h"
#include "kvpnc.h"
#include "kvpncconfig.h"
#include "utils.h"

CiscoVpnclientHandler::CiscoVpnclientHandler(
    KVpnc *ui,
    KVpncConfig *config):
        HandlerBase(ui, config, "Cisco (proprietary)", "vpnclient", false),
        ciscoVpncRunning(false),
        TestCiscoVpncProcess(0),
        CiscoVpncProcess(0), //< vpnclient
        CiscoVpncDevice("cipsec0"),
        vpncConfig(""),
        VpncPty(0)
{
}

bool CiscoVpnclientHandler::vpnStart(bool authenticationRetry)
{
    // Everything step of our logic is guarded by the error state. The error
    // state starts as zero for no error, and is set to the line where any
    // problem is caught.
    unsigned errorLine = 0;

    // looking for vpnclient
    if (!Utils(GlobalConfig).getToolInfo(IpsecType)->found) {
        reportError(i18n("Unable to find \"%1\" at \"%2\".", IpsecType, GlobalConfig->pathToCiscoVpnc));
        errorLine = __LINE__;
    } else {
        debugMessage(0, i18n("Found helper %1 at %2", IpsecType, GlobalConfig->pathToCiscoVpnc));
    }

    if (!errorLine) {
        GlobalConfig->TmpGatewayIP = Utils(GlobalConfig, kapp).resolveName(GlobalConfig->currentProfile->getGateway());
        if (GlobalConfig->TmpGatewayIP == "0.0.0.0" || GlobalConfig->TmpGatewayIP.isEmpty()) {
            reportError(i18n("Host \"%1\" could not be resolved." , GlobalConfig->currentProfile->getGateway()));
            errorLine = __LINE__;
        } else {
            debugMessage(0, i18n("Gateway hostname (%1) resolved to \"%2\"." , GlobalConfig->currentProfile->getGateway() , GlobalConfig->TmpGatewayIP));
        }
    }

    if (!errorLine) {
        if (!getAuthenticationData(authenticationRetry)) {
            errorMessage(i18n("Authentication data dialog cancelled."));
            errorLine = __LINE__;
        }
    }

    if (!errorLine) {
        if (GlobalConfig->currentProfile->getExecuteCmdBeforeConnect()) {
            executeCommandBeforeConnect();
        }
    }

    QString tmpInterface;
    if (!errorLine) {
        tmpPath = KStandardDirs::locateLocal("data", "kvpnc/");

        QString tmpInterface;
        QString LocalIP;
        NetworkInterface iface(GlobalConfig , kapp);
        if (GlobalConfig->currentProfile->getNetworkDevice() == "default") {
            tmpInterface = iface.getDefaultInterface();
            debugMessage(0, i18n("Default interface: \"%1\"." , tmpInterface) );
            LocalIP = iface.getInterfaceIP(iface.getDefaultInterface());
            debugMessage(0, i18n("IP address of default interface: \"%1\"." , LocalIP) );
        } else {
            tmpInterface = GlobalConfig->currentProfile->getNetworkDevice();
            LocalIP = iface.getInterfaceIP(GlobalConfig->currentProfile->getNetworkDevice());
        }
        if (tmpInterface.isEmpty()) {
            tmpInterface = iface.getDefaultInterface();
            LocalIP = iface.getInterfaceIP(iface.getDefaultInterface());
            if (tmpInterface.isEmpty()) {
                debugMessage(0, i18n("No default interface found, using \"lo\"."));
                tmpInterface = "lo"; // no default interface found :(
                LocalIP = "127.0.0.1";
            } else {
                debugMessage(0, i18n("No default interface given, tried default interface, got success, using \"%1\"." , tmpInterface));
            }
        }

        if (LocalIP.isEmpty()) {
            debugMessage(0, i18n("No IP for default interface found, using \"127.0.0.1\"."));
            LocalIP = "127.0.0.1"; // no IP for default interface found :(
        }

        //   QString tunneldevice = "tun0";
        if (!backupDefaultRoute()) {
            errorLine = __LINE__;
        }
    }

    if (!errorLine) {
        QString ResolvConfBackupProfile = tmpPath + "resolv.conf.before.kvpnc_" + GlobalConfig->currentProfile->getName();

        debugMessage(2, i18n("Backup file of %1: %2" , QString("/etc/resolv.conf") , ResolvConfBackupProfile));

        // write vpnc connect script
        QString CiscoVpncConfig = QString("/etc/opt/cisco-vpnclient/Profiles/") + QString("kvpnc_") + QString(GlobalConfig->currentProfile->getName() + ".pcf");          // vpnc-script.<name>
        debugMessage(0, "CiscoVpncConfig: " + CiscoVpncConfig + "\n");
        QFile file(CiscoVpncConfig);
        QTextStream stream(&file);
        if (file.open(QIODevice::WriteOnly)) {
            //     stream << "# generated by kvpnc. Do not edit it." << "\n";
            stream << "[main]" << "\n";
            stream << "Description=KVpnc profile " << GlobalConfig->currentProfile->getName() << "\n";
            stream << "Host=" << GlobalConfig->currentProfile->getGateway() << "\n";

            // 1 = Pre-shared keys (default)
            // 3 = Digital Certificate using an RSA signature.
            // 5 = Mutual authentication
            if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::psk)
                stream << "AuthType=1" << "\n";
            if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::cert)
                stream << "AuthType=3" << "\n";
            if ( GlobalConfig->currentProfile->getAuthType() == VpnAccountData::hybrid )
                stream << "AuthType=5" << "\n";


            if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::psk) {
                stream << "GroupName=" << GlobalConfig->currentProfile->getID() << "\n";
                stream << "GroupPwd=" << GlobalConfig->currentProfile->getPreSharedKey() << "\n";
            }
            stream << "EnableISPConnect=0" << "\n";
            stream << "ISPConnectType=0" << "\n";
            stream << "ISPConnect=" << "\n";
            stream << "ISPCommand=" << "\n";
            if (GlobalConfig->currentProfile->getUserName().isEmpty() || authenticationRetry)
                stream << "Username=" << GlobalConfig->TmpUsername << "\n";
            else
                stream << "Username=" << GlobalConfig->currentProfile->getUserName() << "\n";
            if (GlobalConfig->currentProfile->getSaveUserPassword())
                stream << "SaveUserPassword=0" << "\n";
            else
                stream << "SaveUserPassword=1" << "\n";
            //      stream << "UserPassword=" << "\n";
            if ( GlobalConfig->currentProfile->getUseNtDomainName() )
            {
                stream << "NTDomain=" << GlobalConfig->currentProfile->getNtDomainName() << "\n";
                stream << "EnableMSLogon=1" << "\n";
            }
            else
            {
                stream << "NTDomain=" << "\n";
                stream << "EnableMSLogon=0" << "\n";
            }
            stream << "EnableBackup=0" << "\n";
            stream << "BackupServer=" << "\n";
            stream << "EnableMSLogon=0" << "\n";
            stream << "MSLogonType=0" << "\n";

            if ( GlobalConfig->currentProfile->getUseNat() )
            {
                stream << "EnableNat=1" << "\n";
                if ( GlobalConfig->currentProfile->getUseNat() )
                    stream << "TunnelingMode=0" << "\n";
                else
                {
                    stream << "TunnelingMode=1" << "\n";
                    if ( GlobalConfig->currentProfile->getUseLocalPort())
                        stream << "TcpTunnelingPort=" << GlobalConfig->currentProfile->getLocalPort() << "\n";
                }
            }
            else
            {
                stream << "EnableNat=0" << "\n";
            }


            if ( GlobalConfig->currentProfile->getAuthType() == VpnAccountData::cert )
            {
                if ( GlobalConfig->currentProfile->getUseCiscoCertStore() )
                {
                    stream << "CertStore=1" << "\n";
                }
                else
                {
                    stream << "CertStore=0" << "\n";
                }
                stream << "CertPath=" << GlobalConfig->currentProfile->getCertPath() << "\n";
                stream << "CertName=" << GlobalConfig->currentProfile->getX509Certificate() << "\n";

                //stream << "CertSubjectName=" << "\n";
                //stream << "CertSerialHash=00000000000000000000000000000000" << "\n";
                stream << "SendCertChain=0" << "\n";
            }


            stream << "PeerTimeout=" << GlobalConfig->currentProfile->getDpdIdleTimeout() << "\n";
            stream << "EnableLocalLAN=0" << "\n"; // always off

            file.close();
            debugMessage(3, i18n("Writing %1 finished.", CiscoVpncConfig));
        } else {
            errorMessage(i18n("Creating %1 has been failed.", CiscoVpncConfig));
            errorLine = __LINE__;
        }
    }

    if (!errorLine) {
        if (!checkCiscoVpncStatus()) {
            startCiscoVpnc();
            if (checkCiscoVpncStatus()) {
                reportError(i18n("The Cisco ipsec interface could not be setup."));
                errorLine = __LINE__;
            } else {
                debugMessage(1, i18n("The Cisco ipsec interface was down and could be started and is now up."));
            }
        } else {
            debugMessage(1, i18n("The Cisco ipsec interface is up."));
        }
    }

    if (!errorLine) {
        QStringList args;

        args.append("connect");
        args.append("kvpnc_" + GlobalConfig->currentProfile->getName());
        args.append("user");
        args.append(GlobalConfig->currentProfile->getUserName());
        //     args.append ( "--script" );
        //     args.append ( VpncScript );
        //     if ( GlobalConfig->VpncDebugLevel > 0 )
        //     {
        //
        //      args.append ( "--debug" );
        //      args.append ( QString().setNum ( GlobalConfig->VpncDebugLevel ) );
        //     }
        //     args.append ( "--pid-file" );
        //     args.append ( GlobalConfig->Vpnc_pid_file );
        //
        //     if ( vpnc_version_minor == 3 && vpnc_version_subminor >= 3 || vpnc_version_minor >= 3 && vpnc_version_minor >= 3 && vpnc_version_subminor >= 3 )
        //      args.append ( "--non-inter" );
        //
        //     if ( GlobalConfig->currentProfile->getUseNtDomainName() )
        //     {
        //      args.append ( "--domain" );
        //      args.append ( GlobalConfig->currentProfile->getNtDomainName() );
        //      if ( GlobalConfig->KvpncDebugLevel > 0 )
        //       logMessage ( i18n ( "Using (NT) domain name \"%1\"." , GlobalConfig->currentProfile->getNtDomainName() ), KVpncEnum::debug );
        //     }
        //
        //     if ( GlobalConfig->currentProfile->getUseNat() )
        //     {
        //      if ( vpnc_version_major >= 0 && vpnc_version_minor >= 4 )
        //      {
        //       // TODO add other nat modes
        //       args.append ( "--natt-mode");
        //       args.append ( "cisco-udp");
        //      }
        //      else
        //       args.append ( "--udp" );
        //
        //      if ( GlobalConfig->KvpncDebugLevel > 0 )
        //       logMessage ( i18n ( "Using UDP." ), KVpncEnum::debug );
        //     }
        //     else
        //     {
        //      args.append ( "--disable-natt" );
        //      if ( GlobalConfig->KvpncDebugLevel > 0 )
        //       debugMessage(i18n("Do not use UDP."));
        //     }
        //
        //     if ( GlobalConfig->currentProfile->getUseLocalPort() == true )
        //     {
        //      args.append ( "--local-port" );
        //      args.append ( QString().setNum ( GlobalConfig->currentProfile->getLocalPort() ) );
        //      if ( GlobalConfig->KvpncDebugLevel > 0 )
        //       logMessage ( i18n ( "Using user-defined local port \"%1\"." , QString().setNum ( GlobalConfig->currentProfile->getLocalPort() ) ), KVpncEnum::debug );
        //     }
        //
        //
        //     if ( GlobalConfig->currentProfile->getUseUdpPort() )
        //     {
        //      args.append ( "--udp-port" );
        //      args.append ( QString().setNum ( GlobalConfig->currentProfile->getUdpPort() ) );
        //      if ( GlobalConfig->KvpncDebugLevel > 0 )
        //       logMessage ( i18n ( "Using user-defined UDP port \"%1.\"" , GlobalConfig->currentProfile->getUdpPort() ), KVpncEnum::debug );
        //     }
        //
        //
        //     if ( GlobalConfig->currentProfile->getUseXauthInteractive() && ( ( vpnc_version_minor == 3 && vpnc_version_minor >= 2 ) || ( vpnc_version_minor > 3 ) ) )
        //     {
        //      args.append ( "--xauth-inter" );
        //      if ( GlobalConfig->KvpncDebugLevel > 0 )
        //       logMessage ( i18n ( "Enabling interactive extended authentication (for challenge response auth)" ), KVpncEnum::debug );
        //     }
        //
        //     if ( GlobalConfig->currentProfile->getUseAdvancedSettings() == true )
        //     {
        //      logMessage ( i18n ( "Using advanced settings." ) , KVpncEnum::debug );
        //
        //      if ( GlobalConfig->currentProfile->getUseApplicationVersion() )
        //      {
        //       args.append ( "--application-version" );
        //       args.append ( GlobalConfig->currentProfile->getApplicationVersion() );
        //       logMessage ( i18n ( "Using user-defined application version \"%1\"." , GlobalConfig->currentProfile->getApplicationVersion() ) , KVpncEnum::debug );
        //      }
        //
        //
        //      //      else
        //      //      {
        //      //       args.append( "--local-port" );
        //      //       args.append( "0" ); // random port
        //      //       logMessage ( i18n( "Using random port." ), KVpncEnum::info);
        //      //      }
        //
        //
        //      if ( GlobalConfig->currentProfile->getUsePerfectForwardSecrety() )
        //      {
        //       args.append ( "--pfs" );
        //       args.append ( GlobalConfig->currentProfile->getPerfectForwardSecrety() );
        //       if ( GlobalConfig->KvpncDebugLevel > 0 )
        //        logMessage ( i18n ( "Using user-defined PFS \"%1\"." , GlobalConfig->currentProfile->getPerfectForwardSecrety() ), KVpncEnum::debug );
        //      }
        //
        //      if ( GlobalConfig->currentProfile->getUseIkeGroup() )
        //      {
        //       args.append ( "--dh" );
        //       args.append ( GlobalConfig->currentProfile->getIkeGroup() );
        //       if ( GlobalConfig->KvpncDebugLevel > 0 )
        //        logMessage ( i18n ( "Using user-defined IKE group \"%1\"." , GlobalConfig->currentProfile->getIkeGroup() ), KVpncEnum::debug );
        //      }
        //
        //     }
        //
        //     if ( vpnc_version_major >= 0 && vpnc_version_minor >= 4 )
        //     {
        //      args.append ( "--ifmode");
        //      if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tap")
        //      {
        //       if ( GlobalConfig->KvpncDebugLevel > 1 )
        //        logMessage ( i18n ( "Using tunnel device type: %1." ,"TAP"), KVpncEnum::debug );
        //       args.append ( "tap");
        //      }
        //      else
        //      {
        //       if ( GlobalConfig->KvpncDebugLevel > 1 )
        //        logMessage ( i18n ( "Using tunnel device type: %1." ,"TUN"), KVpncEnum::debug );
        //       args.append ( "tun");
        //      }

        setenv("DNS_UPDATE", (GlobalConfig->currentProfile->getUseDnsUpdate() ? "Yes" : "NO"), 1);

        debugMessage(0, i18n("Setting DNS_UPDATE \"%1\"." , QString(qgetenv("DNS_UPDATE"))));

        CiscoVpncProcess = new HelperProcess(this, GlobalConfig->pathToCiscoVpnc, args, *env,
                                             SLOT(readOutputFrom_ciscovpnc()),
                                             SLOT(readOutputFrom_ciscovpnc()),
                                             0, 0);
        if (!CiscoVpncProcess || !CiscoVpncProcess->start())
        {
            errorLine = __LINE__;
        }
    }

    if (!errorLine) {
        if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::psk) {
            debugMessage(0, i18n("Trying to connect to server \"%1\" (%2) with user \"%3\" and IPSec ID \"%4\"...\n" , GlobalConfig->currentProfile->getGateway() , GlobalConfig->TmpGatewayIP , GlobalConfig->currentProfile->getUserName() , GlobalConfig->currentProfile->getID()));
        }
        if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::cert) {
            debugMessage(0, i18n("Trying to connect to server \"%1\" (%2) with user \"%3\"...\n" , GlobalConfig->currentProfile->getGateway() , GlobalConfig->TmpGatewayIP , GlobalConfig->currentProfile->getUserName()));
        }
    } else {
        errorMessage(i18n("Error at line %1.", errorLine));
    }
    return 0 == errorLine;
}

void CiscoVpnclientHandler::vpnStop()
{
    QString CiscoVpncDisconnectScript = tmpPath + "vpnclient-disconnect." + GlobalConfig->currentProfile->getID() + ".sh";
    // write vpnc connect script

    QFile file(CiscoVpncDisconnectScript);
    QTextStream stream(&file);
    if (file.open(QIODevice::WriteOnly)) {
        stream <<  "#!" << GlobalConfig->InterpreterShell << "\n";
        stream << "# generated by kvpnc. Do not edit it." << "\n";
        stream << "# profile: " + GlobalConfig->currentProfile->getName() << "\n";
        stream << "\n";

        //      if ( GlobalConfig->currentProfile->getReplaceDefaultRoute() )
        //      {
        //       if ( GlobalConfig->KvpncDebugLevel > 2 )
        //        logMessage ( i18n ( "Restoring default route before connection..." ), KVpncEnum::debug );
        //
        //       QString OldDefaultroute = tmpPath + "default-route." + GlobalConfig->currentProfile->getName(); // default-route.<id>
        //       stream << GlobalConfig->pathToIp + " route del default > /dev/null 2>&1\n";
        //       stream << GlobalConfig->pathToIp + " route add $(cat \"" + OldDefaultroute + "\")\n";
        //       //       stream << GlobalConfig->pathToIp + " route add $(cat \"/var/run/vpnc/defaultroute\")\n";
        //      }
        //      //     stream << GlobalConfig->pathToIp+" route del $(cat \"" + VpncGateway + "\")\n";

        /* update dns? */
        if (GlobalConfig->currentProfile->getUseDnsUpdate()) {
            //stream << "chmod u+w  /etc/resolv.conf\n";
            stream << "if [ -f /sbin/resolvconf ] ; then\n";
            stream << " /sbin/resolvconf -d "+GlobalConfig->DnsDevice+"\n";
            stream << "else\n";
            stream << " cat " + tmpPath + "resolv.conf.before.kvpnc_" + GlobalConfig->currentProfile->getName() + " > /etc/resolv.conf\n";

            stream << "fi\n";
        } else {
            /* dont update dns */
        }

        stream << GlobalConfig->pathToIp + " route flush cache\n";
        file.close();
        disconnectProcess("vpnc_disconnect", CiscoVpncDisconnectScript);
    } else {
        errorMessage(i18n("Creating %1 has been failed.", CiscoVpncDisconnectScript));
    }

    if (CiscoVpncProcess) {
        delete CiscoVpncProcess;
        CiscoVpncProcess = 0;
    }
}

bool CiscoVpnclientHandler::getAuthenticationData(bool AuthRetry)
{
    bool askUsernamePass = false;
    bool askGroupPass = false;

    if (AuthRetry)
        askUsernamePass = true;

    if (!GlobalConfig->haveUserData) {
        if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::psk && !GlobalConfig->currentProfile->getSavePsk())
            askUsernamePass = true;
        if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::psk && GlobalConfig->currentProfile->getAllowEmptyGroupPassword() && GlobalConfig->currentProfile->getPreSharedKey().isEmpty())
            askUsernamePass = true;

        if (GlobalConfig->currentProfile->getUserName().isEmpty())
            askUsernamePass = true;

        if (GlobalConfig->currentProfile->getUserPassword().isEmpty())
            askUsernamePass = true;

        if (GlobalConfig->currentProfile->getAuthType() == VpnAccountData::psk)
            askGroupPass = true;

    } else {
        debugMessage(4, i18n("User data already collected."));
    }

    if (GlobalConfig->currentProfile->getAskUserPasswordOnEachConnect()) {
        debugMessage(4, i18n("User password on each connect forced."));

        askUsernamePass = true;
    }

    if (askUsernamePass) {
        bool requestUsername = GlobalConfig->currentProfile->getUserPassword().isEmpty();
        EnterUsernamePasswordDialog dlg(gui, i18n("Enter Account Data"), askGroupPass, requestUsername);

        if (!GlobalConfig->currentProfile->getUserName().isEmpty())
            dlg.UsernameEdit->setText(GlobalConfig->currentProfile->getUserName());

        if (!GlobalConfig->currentProfile->getHideGroupPasswordInAccountDataDialog()) {
            dlg.LabelGroupPassword->setText(i18n("Enter group password:"));

            if (!GlobalConfig->currentProfile->getPreSharedKey().isEmpty()) {
                dlg.PSKLineEdit->setText(GlobalConfig->currentProfile->getPreSharedKey());
            }
        } else {
            dlg.PSKLineEdit->hide();
            dlg.LabelGroupPassword->hide();
            dlg.PSKLineEdit->setText(GlobalConfig->currentProfile->getPreSharedKey());
        }

        if (!GlobalConfig->currentProfile->getUserPassword().isEmpty())
            dlg.PasswordEdit->setText(GlobalConfig->currentProfile->getUserPassword());

        if (!GlobalConfig->currentProfile->getHideGroupPasswordInAccountDataDialog()) {
            if (!dlg.UsernameEdit->text().isEmpty()) {                //go straight to pw if username present
                if (!dlg.PSKLineEdit->text().isEmpty())
                    dlg.PasswordEdit->setFocus();
                else
                    dlg.PSKLineEdit->setFocus();
            }
        } else
            dlg.PasswordEdit->setFocus();

        if (GlobalConfig->currentProfile->getSaveUserPassword())
            dlg.SavePasswordCheckBox->setChecked(true);
        else
            dlg.SavePasswordCheckBox->setChecked(false);

        if (!GlobalConfig->currentProfile->getDontSaveUsername())
            dlg.SaveUsernameCheckBox->setChecked(true);
        else
            dlg.SaveUsernameCheckBox->setChecked(false);

        if (GlobalConfig->currentProfile->getSavePsk())
            dlg.SavePskCheckBox->setChecked(true);
        else
            dlg.SavePskCheckBox->setChecked(false);


        if (dlg.exec()) {
            GlobalConfig->TmpUsername = dlg.UsernameEdit->text();
            GlobalConfig->TmpGroupPassword = dlg.PSKLineEdit->text();
            GlobalConfig->TmpPassword = dlg.PasswordEdit->text();
            bool needSave = false;

            if (GlobalConfig->currentProfile->getHideGroupPasswordInAccountDataDialog() && GlobalConfig->currentProfile->getPreSharedKey().isEmpty() && !GlobalConfig->currentProfile->getAllowEmptyGroupPassword())
                askGroupPass = true;
            if (askGroupPass && GlobalConfig->TmpGroupPassword.isEmpty() && !GlobalConfig->currentProfile->getAllowEmptyGroupPassword()) {
                errorMessage(i18n("Group password is empty"));
                return false;
            }

            if (requestUsername && GlobalConfig->TmpUsername.isEmpty()) {
                errorMessage(i18n("Username is empty."));
                return false;
            }

            debugMessage(0, i18n("Some account data which was needed was obtained from a password dialog."));

            if (dlg.SaveUsernameCheckBox->isChecked()) {
                GlobalConfig->currentProfile->setDontSaveUsername(false);
                GlobalConfig->currentProfile->setUserName(dlg.UsernameEdit->text());
                needSave = true;
            } else {
                GlobalConfig->currentProfile->setDontSaveUsername(true);
            }


            if (!GlobalConfig->currentProfile->getHideGroupPasswordInAccountDataDialog()) {
                if (dlg.SavePskCheckBox->isChecked() && askGroupPass) {
                    GlobalConfig->currentProfile->setSavePsk(true);
                    GlobalConfig->currentProfile->setPreSharedKey(GlobalConfig->TmpGroupPassword);
                    needSave = true;
                } else {
                    GlobalConfig->currentProfile->setSavePsk(false);
                }
            } else {
                GlobalConfig->TmpGroupPassword = GlobalConfig->currentProfile->getPreSharedKey();
            }

            if (dlg.SavePasswordCheckBox->isChecked()) {
                GlobalConfig->currentProfile->setSaveUserPassword(true);
                GlobalConfig->currentProfile->setUserPassword(GlobalConfig->TmpPassword);
                needSave = true;
            } else {
                GlobalConfig->currentProfile->setSaveUserPassword(false);
            }
            if (needSave == true) {
                debugMessage(2, i18n("Need to save because user had request it."));

                GlobalConfig->saveOptions(true, GlobalConfig->currentProfile->getName());
            }
            GlobalConfig->haveUserData = true;
        } else {
            AuthRetry = false;
            debugMessage(0, i18n("Connect canceled because account data dialog aborted."));
            return false;
        }
        GlobalConfig->TmpPassword = GlobalConfig->currentProfile->getUserPassword();
        GlobalConfig->TmpGroupPassword = GlobalConfig->currentProfile->getPreSharedKey();
        GlobalConfig->TmpUsername = GlobalConfig->currentProfile->getUserName();
    }
    return true;
}

QString CiscoVpnclientHandler::pingDevice() const {
    return CiscoVpncDevice;
}

void CiscoVpnclientHandler::readOutputFrom_ciscovpnc()
{
    QString source = "[vpnclient raw]";
    unsigned errorLine = 0;
    DisconnectionReason reason = DISCONNECTION_REASON_FATAL_ERROR;
    bool connectSuccess = false;
    bool terminatedByClient = false;

    //mw->DebugOutput->append( "readOutputFrom_ciscovpnc!\n" );
    QStringList msg_list = QString(CiscoVpncProcess->readAllStandardOutput()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);

        debugMessage(3, QString("[vpnclient raw]: ") + msg );


        if (msg.indexOf("illegal read", 0, Qt::CaseInsensitive) > -1) { }

        else if (msg.indexOf("The profile specified could not be read.", 0, Qt::CaseInsensitive) > -1) {
            serverError(i18n("Profile missing. Please contact the KVpnc author."));

            errorLine = __LINE__;
        }

        else if (msg.indexOf("Secure VPN Connection terminated locally by the Client", 0, Qt::CaseInsensitive) > -1) {
            errorMessage(i18n("Secure VPN connection terminated locally by the client."));
            terminatedByClient = true;
            serverError(i18n("Secure VPN connection terminated locally by the client. Please check your settings (e.g. certificate password.)"));
            errorLine = __LINE__;
        }

        // binding to port failed
        if (msg.indexOf("bind: Address already in use", 0, Qt::CaseInsensitive) > -1) {
            //   if ( GlobalConfig->KvpncDebugLevel > 0 )
            //    debugMessage( i18n( "Binding to port failed. Another vpnc is running, terminate it and try reconnect ." ) );
            debugMessage(0, QString("binding" + msg));

            QString NameAndPid = Utils(GlobalConfig).getNameAndPidOfProgramListen(500);
            debugMessage(0, i18n("NameAndPid: %1" , NameAndPid) );
            if (!NameAndPid.isEmpty()) {
                int pid = NameAndPid.section('/', 0, 0).toInt();
                QString Name = NameAndPid.section('/', 1, 1);
                serverError(i18n("Binding port %1 failed. Program \"%2\" with PID \"%3\" is using it. You have to stop it first." , QString().setNum(500) , Name , QString().setNum(pid)));
            } else
                serverError(i18n("Port binding failed"));

            errorLine = __LINE__;
        }

        if (msg.indexOf("Reason: Failed to establish a VPN connection.", 0, Qt::CaseInsensitive) > -1) {
            if (terminatedByClient) {
                serverError(i18n("Secure VPN connection terminated locally by the client. Please check your settings (e.g. certificate password.)"));

                errorLine = __LINE__;
            }
        }

        if (msg.indexOf("The VPN sub-system is busy or has failed.", 0, Qt::CaseInsensitive) > -1) {
            errorLine = __LINE__;
        }

        else if (msg.indexOf("Reason: Remote peer is no longer responding.", 0, Qt::CaseInsensitive) > -1) {
            serverError(i18n("Timeout while connecting to %1." , GlobalConfig->currentProfile->getGateway()));

            errorLine = __LINE__;
        }

        if (msg.indexOf("Reason: A connection is already in the process of being established.", 0, Qt::CaseInsensitive) > -1) {
            serverError(i18n("There is already an instance of %1 running." , QString("vpnclient")));

            errorLine = __LINE__;
        }

        // requesting username
        if (msg.indexOf("Username [", 0, Qt::CaseInsensitive) > -1) {
            debugMessage(0, "[vpnclient] " + i18n("Username requested, send it...\n"));

            QString UsernameStr;
            if (!GlobalConfig->currentProfile->getDontSaveUsername())
                UsernameStr = GlobalConfig->currentProfile->getUserName();
            else
                UsernameStr = GlobalConfig->TmpUsername;

            CiscoVpncProcess->write(UsernameStr.toUtf8());
            CiscoVpncProcess->write("\n");
        }

        // requesting password
        if (msg.indexOf("Password [", 0, Qt::CaseInsensitive) > -1) {

            debugMessage(0, "[vpnclient] " + i18n("User password requested, send it...\n"));

            QString UserPassStr = "";
            if (!GlobalConfig->currentProfile->getSaveUserPassword() || (reason == DISCONNECTION_REASON_AUTHENTICATION_FAILED))
                UserPassStr = GlobalConfig->TmpPassword;
            else
                UserPassStr = GlobalConfig->currentProfile->getUserPassword();

            debugMessage(5, "[vpnclient] " + i18n("User password: %1\n" , UserPassStr));


            CiscoVpncProcess->write(UserPassStr.toUtf8());
            CiscoVpncProcess->write("\n");
        }
        if (msg.indexOf("Authenticating user.", 0, Qt::CaseInsensitive) > -1) {
            if (GlobalConfig->AuthRetryCount > 1) {
                serverError(i18n("Authentication failed (%1)." , i18n("group password")));

                errorLine = __LINE__;
                reason = DISCONNECTION_REASON_AUTHENTICATION_FAILED;
            }
        }
        if (msg.indexOf("Save Password (Y/N)", 0, Qt::CaseInsensitive) > -1) {
            CiscoVpncProcess->write("Y");
            CiscoVpncProcess->write("\n");
        }

        if (msg.indexOf("Reason: A connection is already in the process of being established.", 0, Qt::CaseInsensitive) > -1) {
            reportError(i18n("Reason: A connection is already in the process of being established."));

            errorLine = __LINE__;
        }

        // requesting certificate password
        if (msg.indexOf("Enter Certificate password:", 0, Qt::CaseInsensitive) > -1) {
            debugMessage(0, "[vpnclient] " + i18n("Certificate password requested, send it...\n"));

            QString PrivKeyPassStr = "";
            //   if (GlobalConfig->currentProfile->getSavePsk())
            PrivKeyPassStr = GlobalConfig->currentProfile->getPrivateKeyPass();
            //   else
            //    PrivKeyPassStr = TmpPrivKeyPassStr;
            if (PrivKeyPassStr.isEmpty()) {
                GlobalConfig->TmpPrivateKeyPass = "";
                QString pass = "";
                EnterXauthInteractivePasscodeDialog dlg(0, true);
                dlg.setWindowTitle(i18n("Enter certificate password"));
                dlg.main->DescriptionLabel->setText(i18n("Enter certificate password to unlock certificate:"));
                dlg.main->LabelPassword->setText(i18n("Certificate password:"));
                dlg.main->SavePasswordCheckBox->setText(i18n("Save certificate password"));
                //     dlg.resize(QSize(dlg.width()+20,dlg.height()));
                dlg.main->PasswordEdit->setFocus();
                debugMessage(0, "[vpnclient] " + i18n("Password for certificate requested...\n"));
                if (dlg.exec()) {

                    pass = dlg.main->PasswordEdit->text();

                    bool allowEmptyCertPassword = true; //FIXME: made an option in gui
                    if (!pass.isEmpty() || allowEmptyCertPassword) {

                        debugMessage(2, "[vpnclient] " + i18n("certificate password got from user"));

                        debugMessage(6, i18n("Send certificate password: %1" , pass));

                        if (dlg.main->SavePasswordCheckBox->isChecked()) {
                            GlobalConfig->currentProfile->setSavePrivateKeyPassword(true);
                            GlobalConfig->currentProfile->setPrivateKeyPass(QString(pass));
                        }

                        GlobalConfig->TmpPrivateKeyPass = QString(pass);

                        //             if ( GlobalConfig->KvpncDebugLevel > 5 )
                        //     debugMessage( "[vpnclient]: private key password: " + GlobalConfig->TmpPrivateKeyPass );

                        debugMessage(2, "[vpnclient] " + i18n("Send certificate password..."));

                        CiscoVpncProcess->write(GlobalConfig->TmpPrivateKeyPass.toUtf8());
                        CiscoVpncProcess->write("\n");
                    } else {
                        errorMessage("[vpnclient] certificate password empty, stop.");
                        errorLine = __LINE__;
                    }
                } else {
                    debugMessage(0, i18n("Connect canceled because password enter dialog aborted."));
                    errorLine = __LINE__;
                }
            } else {
                debugMessage(6, i18n("Send certificate password: %1" , PrivKeyPassStr));

                CiscoVpncProcess->write(PrivKeyPassStr.toUtf8());
                CiscoVpncProcess->write("\n");
            }
        }

        if (msg.indexOf("Reason: User authentication failed.", 0, Qt::CaseInsensitive) > -1) {
            reportError(i18n("Authentication failed (%1)." , i18n("user password")));

            errorLine = __LINE__;
            reason = DISCONNECTION_REASON_AUTHENTICATION_FAILED;
        }

        if (msg.indexOf("Your VPN connection is secure.", 0, Qt::CaseInsensitive) > -1)
            connectSuccess = true;

        if (msg.indexOf("Client address: ", 0, Qt::CaseInsensitive) > -1) {
            //    NetworkInterface iface ( GlobalConfig, parent );
            //    TunnelInterfaceIP = iface.getInterfaceIP ( CiscoVpncDevice );

            gui->setTunnelInterfaceIP(msg.section(':', 1, 1));
            //    NetworkInterface iface ( GlobalConfig, parent );
            //    TunnelInterfaceIP = iface.getInterfaceIP ( CiscoVpncDevice );


        }

        if (msg.indexOf("VPN tunnel information:", 0, Qt::CaseInsensitive) > -1) {
            //    Client address: 192.168.201.59
        }
        if (msg.indexOf("Local LAN Access is disabled", 0, Qt::CaseInsensitive) > -1) {
            debugMessage(0, i18n("Local LAN access is disabled (forced by server). This means you cannot access to your local LAN."));
        }

        if (msg.indexOf("Local LAN Access is enabled", 0, Qt::CaseInsensitive) > -1) {
            //    logMessage ( i18n ( "Local LAN access is enabled." , PrivKeyPassStr ), KVpncEnum::info );
        }

        if (msg.indexOf("Encryption:", 0, Qt::CaseInsensitive) > -1) {
            QString Encryption = msg.section(':', 1, 1).trimmed();
            debugMessage(2, i18n("Encryption algorithm used: %1", Encryption));
        }

        if (msg.indexOf("Authentication:", 0, Qt::CaseInsensitive) > -1) {
            QString Authentication = msg.section(':', 1, 1).trimmed();
            debugMessage(2, i18n("Authentication algorithm used: %1", Authentication));
        }

        if (connectSuccess) {
            successMessage(i18n("%1: Connection established.", source));

            setStatusConnected(__LINE__);

            connectSuccess = false;

            NetworkInterface iface(GlobalConfig, kapp);
            gui->setTunnelInterfaceIP(iface.getInterfaceIP(CiscoVpncDevice));
        }

        if (errorLine) {
            setStatusDisconnected(errorLine, reason);
        }
        /*
        Contacting the gateway at
        Username



        VPN tunnel information.
        Client address: 192.168.88.11
        Server address: 194.95.17.10
        Encryption: 128-bit AES
        Authentication: HMAC-SHA
        IP Compression: None
        NAT passthrough is active on port UDP 10000
        Local LAN Access is disabled

        Disconnecting the VPN connection.

        */
    }
}

void CiscoVpnclientHandler::readCiscoVpncTestProcessOutput()
{
    QStringList msg_list = QString(TestCiscoVpncProcess->readAllStandardOutput()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);

        debugMessage(3, i18n("msg: %1"  , QString(msg)));

        if (msg == "")
            return ;
        if (msg.indexOf("The VPN module is not loaded.", 0, Qt::CaseInsensitive) > -1) {
            debugMessage(1, i18n("Virtual interface of cisco client is not present"));
            ciscoVpncRunning = false;
            return;
        } else if (msg.indexOf("cisco_ipsec", 0, Qt::CaseInsensitive) > -1) {
            debugMessage(1, i18n("Virtual interface of cisco client is present"));
            ciscoVpncRunning = true;
            return;
        }
    }
}

bool CiscoVpnclientHandler::checkCiscoVpncStatus()
{
    ciscoVpncRunning = false;
    QStringList args;
    args.append("/etc/init.d/vpnclient_init");
    args.append("status");

    TestCiscoVpncProcess = new HelperProcess(this, GlobalConfig->InterpreterShell, args, *env,
            SLOT(readCiscoVpncTestProcessOutput()),
            SLOT(readCiscoVpncTestProcessOutput()),
            0, 0);
    if (!TestCiscoVpncProcess || !TestCiscoVpncProcess->start()) {
        errorMessage(i18n("unable to start proc (%1)." , i18n("Test Cisco vpnclient")));
        delete TestCiscoVpncProcess;
        TestCiscoVpncProcess = 0L;
        return false;
    }
    TestCiscoVpncProcess->waitForFinished(100000);
    delete TestCiscoVpncProcess;
    TestCiscoVpncProcess = 0L;
    return ciscoVpncRunning;
}

void CiscoVpnclientHandler::startCiscoVpnc()
{
    QStringList args;
    args.append("/etc/init.d/vpnclient_init");
    args.append("start");

    TestCiscoVpncProcess = new HelperProcess(this, GlobalConfig->InterpreterShell, args, *env,
            SLOT(readCiscoVpncTestProcessOutput()),
            SLOT(readCiscoVpncTestProcessOutput()),
            0, 0);
    if (!TestCiscoVpncProcess || !TestCiscoVpncProcess->start()) {
        errorMessage(i18n("unable to start proc (%1)." , i18n("Start Cisco vpnclient")));
        delete TestCiscoVpncProcess;
        TestCiscoVpncProcess = 0L;
        return;
    }
    debugMessage(1, i18n("proc (%1) started." , i18n("Start Cisco vpnclient")) );
    TestCiscoVpncProcess->waitForFinished(100000);
    delete TestCiscoVpncProcess;
    TestCiscoVpncProcess = 0L;
}
