/*****************************************************************************
 * 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 <kmessagebox.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <unistd.h>
#include "L2tpdHandler.h"
#include "enterpassworddialog.h"
#include "kvpnc.h"
#include "kvpncconfig.h"
#include "utils.h"

L2tpdHandler::L2tpdHandler(
    KVpnc *ui,
    KVpncConfig *config,
    QString daemons):
        HandlerBase(ui, config, "L2TP (plain)", daemons, false)
{
}

bool L2tpdHandler::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;

    if (!errorLine) {
        // looking for vpnc
        if (!Utils(GlobalConfig).getToolInfo("l2tpd")->found &&
                !Utils(GlobalConfig).getToolInfo("xl2tpd")->found) {
            reportError(i18n("Unable to find \"%1\" or \"%2\"!").arg ("l2tpd").arg ("xl2tpd"));
            errorLine = __LINE__;
        } else {
            debugMessage(1,  i18n ( "l2tpd_plain" ) );
        }
    }

    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();
        }
    }

    if (!errorLine) {
        QString tmpInterface;
        QString LocalIP;
        NetworkInterface iface ( GlobalConfig, kapp );
        if ( GlobalConfig->currentProfile->getNetworkDevice() == "default" || GlobalConfig->currentProfile->getNetworkDevice() == "" ) {
            tmpInterface = iface.getDefaultInterface();
            debugMessage(0,  i18n ( "Default interface: \"%1\"." ).arg ( tmpInterface )  );
            LocalIP = iface.getInterfaceIP ( iface.getDefaultInterface() );
            debugMessage(0,  i18n ( "IP address of default interface: \"%1\"." ).arg ( 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 :(
            } else {
                debugMessage (0, i18n ( "No default interface given, tried default interface, got success, using \"%1\"." ).arg ( tmpInterface ));
            }
        }

        if ( LocalIP.isEmpty() ) {
            if ( GlobalConfig->PppdDebugLevel > 0 )
                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 Gateway = GlobalConfig->currentProfile->getGateway();
        QString ProfileName = GlobalConfig->currentProfile->getName();
        QString CertPath = GlobalConfig->currentProfile->getCertPath();



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

        debugMessage(0,  i18n ( "Setting DNS_UPDATE \"%1\"." ).arg ( getenv ( "DNS_UPDATE" ) ) );

        l2tpPrepare(true);
        l2tpStart();
    }

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

void L2tpdHandler::vpnStop()
{
    //if (QFile("/var/run/l2tpd.pid").exists()) {
    //  if (GlobalConfig->KvpncDebugLevel > 1)
    //      logMessage(i18n("Using control interface for disconnecting l2tp connection"),KVpncEnum::debug);
    //  QFile L2tpdControlFile ( "/var/run/l2tp-control" );
    //  QTextStream stream( &L2tpdControlFile );
    //  if ( L2tpdControlFile.open( IO_WriteOnly  ) ) {
    //      stream << "d " << GlobalConfig->currentProfile->getName() << "\n";
    //      L2tpdControlFile.close();
    //  }
    //}
    //else
    //{
    //  if (QFile("/var/run/l2tpd.pid").exists())
    //  {
    //      if (GlobalConfig->KvpncDebugLevel > 1)
    //          logMessage(i18n("Using control interface for disconnecting l2tp connection"),KVpncEnum::debug);
    //      QFile L2tpdControlFile ( "/var/run/l2tp-control" );
    //      QTextStream stream( &L2tpdControlFile );
    //      if ( L2tpdControlFile.open( IO_WriteOnly  ) ) {
    //          stream << "d " << GlobalConfig->currentProfile->getName() << "\n";
    //          L2tpdControlFile.close();
    //      }
    //      else
    l2tpStop();

    if (  GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::l2tpd ) {
        pppdSecretsRemove();
        // remove kvpnc entries from /etc/l2tpd/l2tp-secrets
        pppdSecretsRemove("/etc/l2tpd/l2tp-secrets");
    }
}

bool L2tpdHandler::getAuthenticationData(bool AuthRetry)
{
    bool askUsernamePass = false;
    bool askPsk = false;

    if ( GlobalConfig->currentProfile->getAuthWithUsernameAndPassword() ) {
        if ( !GlobalConfig->haveUserData ) {
            GlobalConfig->TmpUsername = GlobalConfig->currentProfile->getUserName();
            GlobalConfig->TmpPassword = GlobalConfig->currentProfile->getUserPassword();

            if ( GlobalConfig->TmpPassword.isEmpty() || GlobalConfig->TmpUsername.isEmpty() )
                askUsernamePass=true;

            GlobalConfig->WaitingForXauth=false;
            GlobalConfig->haveUserData=true;
        } else {
            debugMessage(4,  i18n ( "User data already collected." ) );
        }
    }

    if ( AuthRetry )
        askUsernamePass = true;

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

        askUsernamePass = true;
    }

    if ( !GlobalConfig->currentProfile->getSaveUserPassword() && GlobalConfig->currentProfile->getUserName().isEmpty() || GlobalConfig->currentProfile->getUserPassword().isEmpty()  )
        askUsernamePass = true;

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

            if ( !GlobalConfig->currentProfile->getUserName().isEmpty() )
                dlg.UsernameEdit->setText ( GlobalConfig->currentProfile->getUserName() );
            dlg.LabelGroupPassword->setText ( i18n ( "PSK:" ) );

            if ( !GlobalConfig->currentProfile->getUserPassword().isEmpty() )
                dlg.PasswordEdit->setText ( GlobalConfig->currentProfile->getUserPassword() );
            else
                dlg.PasswordEdit->setFocus();
        }
        if ( askPsk ) {
            if ( !GlobalConfig->currentProfile->getPreSharedKey().isEmpty() )
                dlg.PSKLineEdit->setText ( GlobalConfig->currentProfile->getPreSharedKey() );
            else if ( !GlobalConfig->currentProfile->getUserPassword().isEmpty() )
                dlg.PSKLineEdit->setFocus();
            if ( !askUsernamePass )
            {
                dlg.PasswordEdit->hide();
                dlg.UsernameEdit->hide();
                dlg.LabelPassword->hide();
                dlg.LabelUsername->hide();
            }
        } else {
            dlg.LabelGroupPassword->hide();
            dlg.PSKLineEdit->hide();
        }

        //              dlg.main->SaveValuesCheckBox->setChecked( GlobalConfig->currentProfile->getSaveUserPassword() || !GlobalConfig->currentProfile->getDontSaveUsername() );

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

            if ( askPsk || AuthRetry ) {

                if ( GlobalConfig->currentProfile->getPreSharedKey().isEmpty() || GlobalConfig->TmpGroupPassword.isEmpty() ) {
                    errorMessage ( i18n ( "PSK is empty!" ));
                    return false;
                }
            }

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


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

            if ( dlg.SavePasswordCheckBox->isChecked() ) {
                GlobalConfig->currentProfile->setSaveUserPassword ( true );
                GlobalConfig->currentProfile->setUserPassword ( GlobalConfig->TmpPassword );
            } else {
                GlobalConfig->currentProfile->setSaveUserPassword ( false );
                needSave = true;
            }
            if (needSave)
                GlobalConfig->saveOptions(true, GlobalConfig->currentProfile->getName());

            debugMessage(0,  i18n ( "Some account data which is needed got from password enter dialog." ) );
            //                  saveSessionClicked();
        }
    } else {
        AuthRetry = false;
        debugMessage(0,  i18n ( "Connect canceled because account data dialog aborted." ) );
        return false;
    }
    return true;
}

QString L2tpdHandler::pingDevice() const {
    return "";
}
