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

HandlerBase::HandlerBase(
    KVpnc *ui,
    KVpncConfig *config,
    QString type,
    QString daemons,
    bool _useL2tpAfterFirstConnection):
        gui(ui),
        GlobalConfig(config),
        useL2tpAfterFirstConnection(_useL2tpAfterFirstConnection),
        pppdHasReplacedefaultrouteSupport(false),
        connectCounter(0),
        IpsecType(type),
        stopContinue(false),
        DisconnectProcess(0),
        m_daemons(daemons),
        OpenL2tpProcess(0),
        L2tpdProcess(0), //< vpnclient
        StartStopOpenl2tpProcess(0)
{
    GlobalConfig->appPointer->setOverrideCursor(QCursor(Qt::WaitCursor));
    tmpPath = KStandardDirs::locateLocal("data", "kvpnc/");

    // TBD: Duplicated code.
    env = new QStringList();
    *env << "LC_ALL=C" << "LANG=C" << "PATH=/bin:/usr/bin:/usr/sbin:/sbin";
}

HandlerBase::~HandlerBase() {
}

QString HandlerBase::type() const {
    return IpsecType;
}

QString HandlerBase::daemons() const {
    return m_daemons;
}

void HandlerBase::serverError(const QString &message)
{
    reportError(message);
}

void HandlerBase::setStatusConnected(unsigned line)
{
    gui->setStatusConnected(IpsecType, line);

    disconnect(&durationTimer, SIGNAL(timeout()), this, SLOT(slotDurationEvent()));
    connect(&durationTimer, SIGNAL(timeout()), this, SLOT(slotDurationEvent()));
    durationTimer.start(1000);

    setFirewallAfterConnect();
    if (GlobalConfig->currentProfile->getExecuteCmdAfterConnect())
        executeCommandAfterConnect();

    sleep(2);

    if (GlobalConfig->currentProfile->getUseAdditionalNetworkRoutes() && !GlobalConfig->currentProfile->getAdditionalNetworkRoutes().isEmpty())
        addAdditionalNetworkRoutes();

    if (GlobalConfig->currentProfile->getUseConnectionStatusCheck()) {
        startConnectionStatusCheck();
    }

    timer.stop();
    connectCounter = 0;
    disconnect(&timer, SIGNAL(timeout()), this, SLOT(slotConnectTimedOut()));
}

void HandlerBase::setStatusDisconnected(unsigned line, DisconnectionReason reason)
{
    // Clean up.
    timer.stop();
    disconnect(&timer, SIGNAL(timeout()), this, SLOT(slotConnectTimedOut()));
    vpnStop();

    bool retry = false;
    switch (reason) {
    case DISCONNECTION_REASON_AUTHENTICATION_FAILED:
        GlobalConfig->AuthRetryCount++;
        // Remember authentication failures for when the dialog is shown.
        GlobalConfig->haveUserData = false;
        retry = true;
        break;
    case DISCONNECTION_REASON_CONFIGURATION_CHANGED:
        gui->saveSessionClicked();
        retry = true;
        break;
    case DISCONNECTION_REASON_FATAL_ERROR:
        break;
    case DISCONNECTION_REASON_USER_REQUEST:
        break;
    }

    // Too many attempts already?
    retry &= (GlobalConfig->currentConnectRetry < GlobalConfig->maxConnectRetry);
    if (retry) {
        // Retry.
        GlobalConfig->currentConnectRetry++;
        debugMessage(1, i18n("Connection attempt %1", QString().setNum(GlobalConfig->currentConnectRetry)));
        vpnStart(true);
    } else {
        // Tell the GUI we failed.
        connectionEnded();
        gui->setStatusDisconnected(IpsecType, line);
    }
}

void HandlerBase::vpnConnect()
{
    // Try to initiate a connection attempt.
    GlobalConfig->AuthRetryCount = 1;
    GlobalConfig->currentConnectRetry = 1;
    // xgettext: no-c-format
    debugMessage(1, i18n("Connection attempt with %1s timeout", QString().setNum(GlobalConfig->tryConnectTimeout)));
    if (vpnStart(false)) {
        gui->setStatusConnecting(IpsecType, __LINE__);

        // Start the connection timeout.
        disconnect(&timer, SIGNAL(timeout()), this, SLOT(slotConnectTimedOut()));
        connect(&timer, SIGNAL(timeout()), this, SLOT(slotConnectTimedOut()));
        timer.start(GlobalConfig->tryConnectTimeout * 1000);
    } else {
        // Cleanup any state we created in this failed attempt.
        vpnDisconnectConnecting();
    }
}

void HandlerBase::vpnDisconnectConnected()
{
    setStatusDisconnected(__LINE__, DISCONNECTION_REASON_USER_REQUEST);
}

void HandlerBase::vpnDisconnectConnecting()
{
    setStatusDisconnected(__LINE__, DISCONNECTION_REASON_USER_REQUEST);
}

//void HandlerBase::addRoute() { gui->(); }
//void HandlerBase::delRoute() { gui->(); }
//void HandlerBase::readFromStderr() { gui->(); }
//void HandlerBase::readFromStderrCtl() { gui->(); }
//void HandlerBase::readFromStderrHelper() { gui->(); }
//void HandlerBase::readFromStderrStatus() { gui->(); }
//void HandlerBase::readFromStdout() { gui->(); }
//void HandlerBase::readFromStdoutCtl() { gui->(); }
//void HandlerBase::readFromStdoutHelper() { gui->(); }
//void HandlerBase::readFromStdoutStatus() { gui->(); }
//void HandlerBase::start() { gui->(); }
//void HandlerBase::started() { gui->(); }
//void HandlerBase::stop() { gui->(); }


void HandlerBase::doPingKickupTunnel() {
    gui->doPingKickupTunnel();
}

void HandlerBase::setFirewallAfterConnect() {
    gui->setFirewallAfterConnect();
}

void HandlerBase::startConnectionStatusCheck() {
    gui->startConnectionStatusCheck();
}

void HandlerBase::executeCommandBeforeConnect() {
    gui->executeCommandBeforeConnect();
}

void HandlerBase::executeCommandAfterConnect() {
    gui->executeCommandAfterConnect();
}

bool HandlerBase::backupDefaultRoute()
{
    OldDefaultroute = tmpPath + "default-route." + GlobalConfig->currentProfile->getName(); // default-route.<id>

    QString scriptFilename = tmpPath + "backup_default-route." + GlobalConfig->currentProfile->getName() + ".sh"; // default-route.<id>
    QFile scriptFile(scriptFilename);    // warning: static
    QTextStream stream2(&scriptFile);
    if (!scriptFile.open(QIODevice::WriteOnly)) {
        errorMessage(i18n("Default route could not backed up."));
        return false;
    }
    stream2 << " #!" << GlobalConfig->InterpreterShell << "\n";
    stream2 << GlobalConfig->pathToIp << " route show | grep default > " << OldDefaultroute << "\n";
    scriptFile.close();

    QProcess process(this);
    QStringList args;
    args.append(scriptFilename);
    process.setEnvironment(*env);
    process.start(GlobalConfig->InterpreterShell, args);
    if (!process.waitForStarted()) {
        reportError(i18n("Failed to start \"%1\"."  , QString("backup default route process")));
        return false;
    }
    debugMessage(1, i18n("\"%1\" started."  , QString("backup default route process")));

    waitForFinished(&process, 100);
    debugMessage(1, i18n("\"%1\" finished."  , QString("backup default route process")));
    return true;
}

void HandlerBase::backupIpsecSystemConfig() {
    gui->backupIpsecSystemConfig();
}

QString HandlerBase::getX509CertificateID(QString Cert, bool user) {
    return gui->getX509CertificateID(Cert, user);
}

void HandlerBase::readFromStdout_getX509CertificateID() {
    gui->readFromStdout_getX509CertificateID();
}

void HandlerBase::l2tpPrepare(bool do_auth)
{
    QString LocalIP;


    if (GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::l2tpd) {
        // bug in openswan: only 80 chars in line allowed!!!
        int pppdoptionsfilepathlen = QString("pppoptfile = " + tmpPath + "options." + GlobalConfig->currentProfile->getName() + ".l2tpd").length();
        if (pppdoptionsfilepathlen > 80) {
            reportError(i18n("The line length for pppoptfile, %1, is longer than 80 chars. Openswan has an bug and cannot handle that. Please rename the profile to a shorter name." , QString().setNum(pppdoptionsfilepathlen)));
            stopContinue = true;
            return;
        }
        QString tmpInterface;
        NetworkInterface iface(GlobalConfig, kapp);
        if (GlobalConfig->currentProfile->getNetworkDevice() == "default" || GlobalConfig->currentProfile->getNetworkDevice() == "") {
            tmpInterface = iface.getDefaultInterface();
            debugMessage(0, i18n("Default interface: \"%1\"." , QString((tmpInterface))) );
            LocalIP = iface.getInterfaceIP(iface.getDefaultInterface());
            debugMessage(0, i18n("IP address of default interface: \"%1\"."  , QString(LocalIP)) );
        } else {
            tmpInterface = GlobalConfig->currentProfile->getNetworkDevice();
            LocalIP = iface.getInterfaceIP(GlobalConfig->currentProfile->getNetworkDevice());
        }

        // write l2tpd.conf
        QFile L2tpdConfigFile(tmpPath + "l2tpd." + GlobalConfig->currentProfile->getName() + ".conf");
        QTextStream stream(&L2tpdConfigFile);
        if (L2tpdConfigFile.open(QIODevice::WriteOnly)) {
            stream << "[global]" << "\n";

            //   if ( !LocalIP.isEmpty() )
            stream << "listen-addr = " << LocalIP << "\n";
            //   else
            //    stream << "listen-addr = 127.0.0.1" <<"\n";
            //   stream << "listen-addr = 0.0.0.0" <<"\n";

            stream << "port = 1701" << "\n";
            if (do_auth) {
                stream << "auth file = /etc/l2tpd/l2tp-secrets" << "\n";
            }


            if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
                if (GlobalConfig->enableDebugXl2tpdNetwork)
                    stream << "debug network = yes" << "\n";
                if (GlobalConfig->enableDebugXl2tpdpacket)
                    stream << "debug packet = yes" << "\n";
                if (GlobalConfig->enableDebugXl2tpdstate)
                    stream << "debug state = yes" << "\n";
                if (GlobalConfig->enableDebugXl2tpdtunnel)
                    stream << "debug tunnel = yes" << "\n";
            }


            stream << "[lac " << GlobalConfig->currentProfile->getName() << "]" << "\n";
            stream << "lns = " << GlobalConfig->currentProfile->getGateway() << "\n";
            stream << "redial = yes" << "\n";
            stream << "redial timeout = 20" << "\n";
            stream << "max redials = 15" << "\n";
            //     stream << "hidden bit = yes" << "\n";
            stream << "length bit = yes" << "\n";

            // do not need to let authenticate the peer
            if (do_auth)
            {
                stream << "require authentication = yes" << "\n";
            }
            else
            {
                stream << "require authentication = no" << "\n";
            }

            if (GlobalConfig->currentProfile->getAuthMethod() == "chap" || GlobalConfig->currentProfile->getAuthMethod() == "mschap" || GlobalConfig->currentProfile->getAuthMethod() == "mschap-v2") {
                stream << "require chap = yes" << "\n";
                stream << "refuse pap = yes" << "\n";
            }
            if (GlobalConfig->currentProfile->getAuthMethod() == "pap") {
                stream << "refuse chap = yes" << "\n";
                stream << "require pap = yes" << "\n";
            }

            QString UsernameStr = "";
            if (!GlobalConfig->currentProfile->getUserName().isEmpty())
                UsernameStr = GlobalConfig->currentProfile->getUserName();

            if (UsernameStr.isEmpty() && !GlobalConfig->TmpUsername.isEmpty())
                UsernameStr = GlobalConfig->TmpUsername;

            debugMessage(1, i18n("Username: %1" , UsernameStr));



            stream << "name = " << UsernameStr << "\n";
            stream << "pppoptfile = " << tmpPath + "options." + GlobalConfig->currentProfile->getName() + ".l2tpd" << "\n";
            stream << "ppp debug = yes" << "\n";
            stream << "autodial = yes" << "\n";
            L2tpdConfigFile.close();

            L2tpdProcess = 0L;
        } else {
            errorMessage(i18n("Creating %1 failed." , QString("l2tpd config file")));
            stopContinue = true;
        }


        // write options.l2tpd
        QFile L2tpdPppdOptionsFile(tmpPath + "options." + GlobalConfig->currentProfile->getName() + ".l2tpd");
        stream.setDevice(&L2tpdPppdOptionsFile);
        if (L2tpdPppdOptionsFile.open(QIODevice::WriteOnly)) {
            stream << "noauth" << "\n";
            stream << "user " << GlobalConfig->currentProfile->getUserName() << "\n";
            stream << "ipcp-accept-local" << "\n";
            stream << "ipcp-accept-remote" << "\n";
            //     stream << "crtscts" << "\n";
            stream << "idle 180" << "\n";
            stream << "lock" << "\n";
            //     stream << "proxyarp" << "\n";
            //     stream << "connect-delay 5000" << "\n";
            //     stream << "persist" << "\n";
            //     stream << "hide-password" << "\n";
            //     if (!GlobalConfig->currentProfile->getUseDnsServer())
            //      stream << "usepeerdns" << "\n";
            //     stream << "asyncmap 0" << "\n";
            //     stream << "crtscts" << "\n";
            //     stream << "lock" << "\n";
            //     stream << "lcp-echo-interval 10" << "\n";
            //     stream << "lcp-echo-failure 3" << "\n";
            //     stream << "noipx" << "\n";

            stream << "linkname kvpnc." << GlobalConfig->currentProfile->getName() << "\n";
            // FIXME how i can get safe the right interface name otherway?


            if (GlobalConfig->PppdDebugLevel)
                stream << "debug" << "\n";
            //stream << "kdebug 1" << "\n";

            if (GlobalConfig->currentProfile->getAuthMethod() == "chap") {
                stream << "# use chap" << "\n";
                stream << GlobalConfig->pppdcap.RequireAuthChapOption << "\n";
            }

            if (GlobalConfig->currentProfile->getAuthMethod() == "mschap") {
                stream << "# use mschap" << "\n";
                stream << GlobalConfig->pppdcap.RequireAuthMschapOption << "\n";
            }

            if (GlobalConfig->currentProfile->getAuthMethod() == "mschap-v2") {
                stream << "# use mschap-v2" << "\n";
                stream << GlobalConfig->pppdcap.RequireAuthMschapv2Option << "\n";
            }

            if (GlobalConfig->currentProfile->getAuthMethod() == "pap") {
                stream << "# use pap" << "\n";
                stream << GlobalConfig->pppdcap.RequireAuthPapOption << "\n";
            }

            if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
                if (GlobalConfig->enableDebugPppd)
                    stream << "debug" << "\n";
            } else {
                if (GlobalConfig->enableDebugPppd)
                    stream << "debug" << "\n";
            }

            if (!GlobalConfig->currentProfile->getReplaceDefaultRoute()) {
                stream << "# do not set defaultroute\n";
                stream << "nodefaultroute";
                stream << "\n";
            } else {
                if (GlobalConfig->currentProfile->getReplaceDefaultRoute()) {
                    stream << "# set defaultroute\n";
                    stream << "defaultroute\n";
                    if (GlobalConfig->pppdcap.pppdHasReplacedefaultrouteSupport)
                        stream << "replacedefaultroute\n";
                }
                stream << "\n";
            }

            if (GlobalConfig->currentProfile->getUseMtu()) {
                stream << "mtu " << GlobalConfig->currentProfile->getMtu() << "\n";
            }
            if (GlobalConfig->currentProfile->getUseMru()) {

                stream << "mru " << GlobalConfig->currentProfile->getMru() << "\n";
            }

            stream << "connect-delay 5000" << "\n";



            L2tpdPppdOptionsFile.close();
        } else {
            errorMessage(i18n("Creating %1 failed." , i18n("l2tpd options file for pppd")));
            stopContinue = true;
        }

        //  // write l2tp secrets file
        //  QString L2tpSecrets = tmpPath + "l2tp-secrets." + GlobalConfig->currentProfile->getName();
        //
        //  if ( GlobalConfig->KvpncDebugLevel > 0 )
        //   logMessage ( i18n ( "l2tp secrets file: %1" , tmpPath + "l2tp-secrets." + GlobalConfig->currentProfile->getName() ), KVpncEnum::debug );
        //  QFile L2tpdSecretsFile ( L2tpSecrets );
        //  stream.setDevice ( &L2tpdSecretsFile );
        //  if ( L2tpdSecretsFile.open ( QIODevice::WriteOnly | IO_WriteOnly ) )
        //  {
        //   stream << "# +++ generated by kvpnc. Do not edit it." << "\n";
        //   stream << "# profile: " + GlobalConfig->currentProfile->getName() << "\n";
        //
        //   if ( GlobalConfig->currentProfile->getSaveUserPassword() )
        //    GlobalConfig->TmpPassword = GlobalConfig->currentProfile->getUserPassword();
        //
        //   QString UsernameStr;
        //   if ( !GlobalConfig->currentProfile->getDontSaveUsername() )
        //    UsernameStr = GlobalConfig->currentProfile->getUserName();
        //   else
        //    UsernameStr = GlobalConfig->TmpUsername;
        //
        //   if (GlobalConfig->TmpUsername.isEmpty() && !GlobalConfig->currentProfile->getUserName().isEmpty() )
        //    GlobalConfig->TmpUsername = GlobalConfig->currentProfile->getUserName();
        //
        //
        //   if (GlobalConfig->KvpncDebugLevel > 1)
        //    logMessage ( i18n ( "Username: %1" , GlobalConfig->TmpUsername.isEmpty() ), KVpncEnum::debug );
        //
        //   stream << "* " << GlobalConfig->currentProfile->getGateway() + " \"" << GlobalConfig->TmpPassword << "\" *\n";
        //   stream << GlobalConfig->currentProfile->getGateway() << " \"" << GlobalConfig->TmpPassword << "\" *\n";
        //
        //   stream << "# --- generated by kvpnc. Do not edit it." << "\n";
        //   L2tpdSecretsFile.close();
        //   Utils ( GlobalConfig, this ).doChmod ( L2tpdSecretsFile.name(), "go-rwx" );
        //
        //  }
        //  else
        //  {
        //   logMessage ( i18n ( "Creating of %1 failed." , "l2tpd secrets file" ), KVpncEnum::error );
        //   stopContinue = true;
        //  }
        pppdSecretsAdd();
        if (do_auth) {
            pppdSecretsAdd("/etc/l2tpd/l2tp-secrets");
        }

    }
    if (GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::openl2tp) {
        // write openl2tp.<profilename>.conf
        QString tmpPath = KStandardDirs::locateLocal("data", "kvpnc/");
        QString OpenL2tpContName = tmpPath + "openl2tp." + GlobalConfig->currentProfile->getName() + ".conf";
        QFile OpenL2tpConfigFile(OpenL2tpContName);
        QTextStream stream(&OpenL2tpConfigFile);
        if (OpenL2tpConfigFile.open(QIODevice::WriteOnly)) {
            stream << "# generated by kvpnc. Do not edit it." << "\n";
            stream << "# profile: " + GlobalConfig->currentProfile->getName() << "\n";
            stream << "" << "\n";
            stream << "ppp profile modify profile_name=default ";
            if (GlobalConfig->currentProfile->getAuthMethod() == "chap")
                stream << "auth_eap=no auth_pap=no auth_mschapv1=no auth_mschapv2=no";

            if (GlobalConfig->currentProfile->getAuthMethod() == "mschap")
                stream << "auth_eap=no auth_pap=no auth_mschapv1=yes auth_mschapv2=yes";

            if (GlobalConfig->currentProfile->getAuthMethod() == "mschap-v2")
                stream << "auth_eap=no auth_pap=no auth_mschapv1=no auth_mschapv2=yes";

            if (GlobalConfig->currentProfile->getAuthMethod() == "pap")
                stream << "auth_eap=no auth_pap=yes auth_mschapv1=no auth_mschapv2=no";

            stream << "\n";
            stream << "tunnel create tunnel_name=" << GlobalConfig->currentProfile->getName() << " dest_ipaddr="  << GlobalConfig->TmpGatewayIP << " persist=yes" << "\n";


            if (GlobalConfig->currentProfile->getSaveUserPassword())
                GlobalConfig->TmpPassword = GlobalConfig->currentProfile->getUserPassword();

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


            stream << "session create tunnel_name=" << GlobalConfig->currentProfile->getName() << " session_name=" << GlobalConfig->currentProfile->getName() << " user_name=" << UsernameStr << " user_password=" << GlobalConfig->TmpPassword << "\n";

            OpenL2tpConfigFile.close();

            kernelModuleLoad("slhc");
            kernelModuleLoad("ppp_generic");
            kernelModuleLoad("pppox");
            kernelModuleLoad("pppol2tp");
        } else {
            errorMessage(i18n("Creating %1 failed.", QString("openl2tp config file")));
            stopContinue = true;
        }
    }
}

void HandlerBase::l2tpStart()
{
    QString daemon = "";
    if (GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::l2tpd) {
        if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
            debugMessage(1, i18n("Using %1.", QString("xl2tpd")));
            daemon = "xl2tpd";
        } else {
            debugMessage(1, i18n("Using %1.", QString("l2tpd")));
            daemon = "l2tpd";
        }

        QString L2tpdPid = "";
        if (daemon == "xl2tpd")
            L2tpdPid = "/var/run/xl2tpd.pid";
        else
            L2tpdPid = "/var/run/l2tpd.pid";


        QString L2tpdControl = "";
        if (daemon == "xl2tpd")
            L2tpdControl = "/var/run/l2tp-control";
        else
            L2tpdControl = "/var/run/l2tp-control";



        //  if (QFile(L2tpdPid).exists())
        //  {
        //   if (GlobalConfig->KvpncDebugLevel > 1)
        //    errorMessage(i18n("Using control interface for starting l2tp connection"),KVpncEnum::debug);
        //
        //   QString L2tpdControl="";
        //   if (daemon == "xl2tpd")
        //    L2tpdControl="/var/run/xl2tpd/l2tp-control";
        //   else
        //    L2tpdControl="/var/run/l2tp-control";
        //
        //   QFile L2tpdControlFile ( L2tpdControl );
        //   QTextStream stream( &L2tpdControlFile );
        //   if ( L2tpdControlFile.open( QIODevice::WriteOnly  ) ) {
        //    stream << "c " << GlobalConfig->currentProfile->getName() << "\n";
        //    L2tpdControlFile.close();
        //   }
        //   else
        //   {
        //    control_interface_success=false;
        //    errorMessage(i18n("Starting l2tp connection via control interface has been failed"),KVpncEnum::error);
        //   }
        //  }
        //  if (!QFile("/var/run/l2tpd.pid").exists() || control_interface_success==false)
        {
            debugMessage(1, i18n("Starting l2tpd manually"));
            sleep(2);

            // start l2tpd
            QString proc = "";
            QStringList args;
            if (daemon == "xl2tpd") {
                debugMessage(1, i18n("Using %1.", QString("xl2tpd")));
                proc = GlobalConfig->pathToXl2tpd;
            } else {
                debugMessage(1, i18n("Using %1.", QString("l2tpd")));
                proc = GlobalConfig->pathToL2tpd;
            }
            args.append("-p");
            args.append("/var/run/l2tpd." + GlobalConfig->currentProfile->getName() + ".pid");

            if (daemon == "xl2tpd") {
                args.append("-C");
                args.append(L2tpdControl);
            }
            args.append("-c");
            args.append(tmpPath + "l2tpd." + GlobalConfig->currentProfile->getName() + ".conf");
            //   args.append ( "-s" );
            //   args.append ( tmpPath + "l2tp-secrets." + GlobalConfig->currentProfile->getName() );
            args.append("-D");

            debugMessage(2, "\"" + daemon + "\" cmd line: " + args.join(" ") );

            L2tpdProcess = new HelperProcess(this, proc, args, *env,
                                             SLOT(readFromStdout_l2tpd()),
                                             SLOT(readFromStderr_l2tpd()),
                                             0, 0);
            if (!L2tpdProcess || !L2tpdProcess->start()) {
                reportError(i18n("Failed to start \"%1\"." , daemon));
                setStatusDisconnected(__LINE__, DISCONNECTION_REASON_FATAL_ERROR);
            } else {
                debugMessage(0, i18n("\"%1\" started." , QString("l2tpd")));


                //    if (GlobalConfig->KvpncDebugLevel > 1)
                //     errorMessage(i18n("Using control interface for starting l2tp connection"),KVpncEnum::debug);
                //
                //    QString L2tpdControl="";
                //    if (daemon == "xl2tpd")
                //     L2tpdControl="/var/run/xl2tpd/l2tp-control";
                //    else
                //     L2tpdControl="/var/run/l2tp-control";
                //
                //    QFile L2tpdControlFile ( L2tpdControl );
                //    QTextStream stream( &L2tpdControlFile );
                //    if ( L2tpdControlFile.open( QIODevice::WriteOnly  ) ) {
                //     stream << "c " << GlobalConfig->currentProfile->getName() << "\n";
                //     L2tpdControlFile.close();
                //    }
                //    else
                //    {
                //     control_interface_success=false;
                //     errorMessage(i18n("Starting l2tp connection via control interface has been failed"),KVpncEnum::error);
                //    }
            }
        }
    }
    if (GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::openl2tp) {
        {
            debugMessage(1, i18n("Using %1." , QString("openl2tp")));
            daemon = "openl2tp";
        }

        //   bool control_interface_success=true;

        //   QString L2tpdPid="";
        //   if (daemon == "xl2tpd")
        //    L2tpdPid="/var/run/xl2tpd.pid";
        //   else
        //    L2tpdPid="/var/run/l2tpd.pid";

        startStopOpenl2tp(true);
        sleep(2);
        startStopOpenl2tp();

        debugMessage(1, i18n("Starting openl2tpd manually"));
        //   sleep ( 2 );

        // start openl2tpd
        debugMessage(1, i18n("Using %1.", QString("openl2tpd")));

        QStringList args;

        //    if (GlobalConfig->currentProfile->getConnectionType() == VpnAccountData::l2tpd_racoon)
        //   {
        //    // use ipsec tools extensions
        //    args.append ( "-p" );
        //    args.append ( "ipsec.so" );
        //   }
        args.append("-f");    // foreground
        args.append("-c");

        QString OpenL2tpContName = tmpPath + "openl2tp." + GlobalConfig->currentProfile->getName() + ".conf";

        args.append(OpenL2tpContName);
        args.append("-D");    // debug

        debugMessage(2, "\"" + daemon + "\" cmd line: " + args.join(" ") );

        OpenL2tpProcess = new HelperProcess(this, GlobalConfig->pathToOpenl2tp, args, *env,
                                            SLOT(readFromStdout_openl2tp()),
                                            SLOT(readFromStderr_openl2tp()),
                                            0, 0);
        if (!OpenL2tpProcess || !OpenL2tpProcess->start()) {
            reportError(i18n("Failed to start \"%1\".", QString(daemon)));
            setStatusDisconnected(__LINE__, DISCONNECTION_REASON_FATAL_ERROR);
        } else {
            debugMessage(0, i18n("\"%1\" started." , QString("openl2tp")));
        }
    }
}

void HandlerBase::l2tpStop()
{
    if (GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::l2tpd) {
        if (L2tpdProcess) {
            L2tpWaitForPppUpTimer.stop();
            delete L2tpdProcess;
            L2tpdProcess = 0L;
        }
    }
    if (GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::openl2tp) {
        if (OpenL2tpProcess) {
            delete OpenL2tpProcess;
            OpenL2tpProcess = 0L;
            if (QFile("/var/run/openl2tpd.pid").exists())
                QFile("/var/run/openl2tpd.pid").remove();
        }
    }

    kernelModuleUnload("slhc");
    kernelModuleUnload("ppp_generic");
    if (GlobalConfig->currentProfile->getL2tpDaemon() == VpnAccountData::openl2tp) {
        kernelModuleUnload("pppox");
        kernelModuleUnload("pppol2tp");
        startStopOpenl2tp(true);
        sleep(2);
        startStopOpenl2tp();
    }
}

void HandlerBase::startStopOpenl2tp(bool stop, bool silent)
{
    debugMessage(0, "[openl2tp] " + i18n("Starting %1..."  , QString("/etc/init.d/openl2tpd")) );
    QStringList args;

    if (stop == false) {
        if (silent == false || GlobalConfig->KvpncDebugLevel > 5) {
            debugMessage(0, i18n("Starting %1..."  , QString("openl2tpd")));
        }
        args.append("start");
        GlobalConfig->currentConnectRetry++;
    } else {
        if (silent == false || GlobalConfig->KvpncDebugLevel > 5) {
            debugMessage(0, i18n("Stopping %1..."  , QString("openl2tp")));
        }
        args.append("stop");
    }

    IpsecStartingInProgress = true;
    if (silent == false || GlobalConfig->KvpncDebugLevel > 8) {
        StartStopOpenl2tpProcess = new HelperProcess(this, "/etc/init.d/openl2tp", args, *env,
                SLOT(readFromStdout_startstopOpenl2tp()),
                SLOT(readFromStderr_startstopOpenl2tp()),
                0, 0);
    } else {
        StartStopOpenl2tpProcess = new HelperProcess(this, "/etc/init.d/openl2tp", args, *env,
                0,
                0,
                0, 0);
    }
    if (!StartStopOpenl2tpProcess || !StartStopOpenl2tpProcess->start()) {
        if (silent == false) {
            reportError(i18n("Failed to start \"%1\"."  , QString("ipsec")));
        }
        //   disconnectClicked();
        IpsecStartingInProgress = false;
    } else {
        if (silent == false) {
            if (stop == false) {
                debugMessage(2, i18n("\"%1\" started."  , QString("/etc/init.d/openl2tp start")) );
            } else {
                debugMessage(2, i18n("\"%1\" started."  , QString("/etc/init.d/openl2tp stop")) );
            }
        }
        StartStopOpenl2tpProcess->waitForFinished(GlobalConfig->currentProfile->getMaxConnectTries() * 200000);
        delete StartStopOpenl2tpProcess;
        StartStopOpenl2tpProcess = 0L;
    }

}

void HandlerBase::doAddRemoveVirtualIp(QString action) {
    gui->doAddRemoveVirtualIp(action);
}

void HandlerBase::waitForFinished(QProcess *process, int refreshtime, QString refreshmsg)
{
    gui->waitForFinished(process, refreshtime, refreshmsg);
}

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

        debugMessage(0, "[disconnect] " + msg);

    }
}

void HandlerBase::readFromStderr_disconnect()
{
    QStringList msg_list = QString(DisconnectProcess->readAllStandardError()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);

        errorMessage("[disconnect err] " + msg);
    }
}

void HandlerBase::disconnectProcess(QString task, QString script)
{
    QStringList args;
    args.append(script);
    DisconnectProcess = new HelperProcess(this, GlobalConfig->InterpreterShell, args, *env,
                                          SLOT(readFromStdout_disconnect()),
                                          SLOT(readFromStderr_disconnect()),
                                          0, 0);
    if (!DisconnectProcess || !DisconnectProcess->start()) {
        reportError(i18n("Failed to start \"%1\".", task), QString(), KVpncEnum::info);
    } else {
        DisconnectProcess->waitForFinished(100000);
    }
    delete DisconnectProcess;
    DisconnectProcess = 0;
}


void HandlerBase::readFromStdout_openl2tp()
{
    unsigned errorLine = 0;
    DisconnectionReason reason = DISCONNECTION_REASON_FATAL_ERROR;
    QStringList msg_list = QString(OpenL2tpProcess->readAllStandardOutput()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
        bool connectSuccess = false;

        if (GlobalConfig->enableDebugOpenl2tp) {
            debugMessage(0, "[openl2tp] " + msg);
        } else {
            if (msg.indexOf("FUNC:", 0, Qt::CaseInsensitive) < 0  && msg.indexOf("FSM:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("AVP:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("PROTO:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("XPRT:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("DATA:", 0, Qt::CaseInsensitive) < 0)
                debugMessage(0, "[openl2tp] " + msg);
        }

        if (msg.indexOf("address", 0, Qt::CaseInsensitive) > -1) {
            debugMessage(0, i18n("Got IP address"));

            if (msg.indexOf("local", 0, Qt::CaseInsensitive) > -1) {
                gui->setTunnelInterfaceIP(msg.section(' ', 4, 4));

                connectSuccess = true;
            }
        } else if (msg.indexOf("event ICRP_ACCEPT in state WAITREPLY", 0, Qt::CaseInsensitive) > -1) {
            // short before low level connection up
        } else if (msg.indexOf("starting UNIX pppd", 0, Qt::CaseInsensitive) > -1) {
            // low level connection sure up
        } else if (msg.indexOf("state change: WAITCTLREPLY --> ESTABLISHED", 0, Qt::CaseInsensitive) > -1) {
            // low level connection up
        } else if (msg.indexOf("Using interface", 0, Qt::CaseInsensitive) > -1) {

            gui->setL2tpPppDevice(msg.section(' ', 2, 2));
        } else if (msg.indexOf("authentication succeeded:", 0, Qt::CaseInsensitive) > -1) {
            debugMessage(0, i18n("Authentication succeeded."));
            //    connectSuccess=true;
        } else if (msg.indexOf("Connection terminated.", 0, Qt::CaseInsensitive) > -1) {
            reportError(i18n("Connection has been terminated."));
            errorLine = __LINE__;
        }

        if (connectSuccess) {
            setStatusConnected(__LINE__);
        }

        if (errorLine) {
            debugMessage(0, i18n("There is a reason to stop connecting, terminating \"%1\" process."  , QString("openl2tpd")) );
            setStatusDisconnected(errorLine, reason);
            return ;
        }

    }
}

void HandlerBase::readFromStderr_openl2tp()
{
    QStringList msg_list = QString(OpenL2tpProcess->readAllStandardError()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
        bool abort = false;
        errorMessage("[openl2tp err] " + msg);


        if (msg.indexOf("parse error", 0, Qt::CaseInsensitive) > -1) {
            reportError(i18n("Error in generated configuration file for \"%1\", please contact the KVpnc team." , QString("openl2tpd")));
            abort = true;
        } else if (msg.indexOf("File /var/run/openl2tpd.pid already exists", 0, Qt::CaseInsensitive) > -1) {
            reportError(i18n("Lock file of %1 still exists. Please remove it if %2 is not running." , QString("openl2tpd"), QString("openl2tpd")));
            abort = true;
        }


        if (abort) {
            debugMessage(0, i18n("There is a reason to stop connecting, terminating \"%1\" process." , QString("l2tpd")) );
            setStatusDisconnected(__LINE__, DISCONNECTION_REASON_FATAL_ERROR);
            return ;
        }
    }
}

void HandlerBase::readFromStdout_startstopOpenl2tp()
{
    QStringList msg_list = QString(StartStopOpenl2tpProcess->readAllStandardOutput()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
        bool abort = false;
        if (GlobalConfig->enableDebugOpenl2tp) {
            debugMessage(0, "[openl2tp] " + msg);
        } else {
            if (msg.indexOf("FUNC:", 0, Qt::CaseInsensitive) < 0  && msg.indexOf("FSM:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("AVP:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("PROTO:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("XPRT:", 0, Qt::CaseInsensitive) < 0 && msg.indexOf("DATA:", 0, Qt::CaseInsensitive) < 0)
                debugMessage(0, "[openl2tp] " + msg);
        }


        if (abort) {
            debugMessage(0, i18n("There is a reason to stop connecting, terminating \"%1\" process." , QString("openl2tpd")) );
            setStatusDisconnected(__LINE__, DISCONNECTION_REASON_FATAL_ERROR);
            return ;
        }

    }
}

void HandlerBase::readFromStderr_startstopOpenl2tp()
{
    QStringList msg_list = QString(StartStopOpenl2tpProcess->readAllStandardError()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
        errorMessage("[openl2tp err] " + msg);

        bool abort = false;
        if (abort) {
            debugMessage(0, i18n("There is a reason to stop connecting, terminating \"%1\" process." , QString("openl2tp")) );
            setStatusDisconnected(__LINE__, DISCONNECTION_REASON_FATAL_ERROR);
            return ;
        }
    }
}

void HandlerBase::readFromStdout_l2tpd()
{
    QStringList msg_list = QString(L2tpdProcess->readAllStandardOutput()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
        processStdout_l2tpd(msg);
    }
}

void HandlerBase::readFromStderr_l2tpd()
{
    QStringList msg_list = QString(L2tpdProcess->readAllStandardError()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
        processStderr_l2tpd(msg);
    }

}

void HandlerBase::processStdout_l2tpd(QString msg)
{
    bool NormalMsg = true;
    bool ErrorMsg = false;
    debugMessage(7, QString("[l2tpd raw] " + msg) );
    unsigned errorLine = 0;
    DisconnectionReason reason = DISCONNECTION_REASON_FATAL_ERROR;
    bool connectSuccess = false;

    if (msg.indexOf("init_network: Unable to bind socket. Terminating", 0, Qt::CaseInsensitive) > -1 || msg.indexOf("Unable to bind socket: Address already in use", 0, Qt::CaseInsensitive) > -1) {
        bool kill_l2tpd = true;

        QString daemon = "xl2tpd";
        if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
            daemon = "xl2tpd";
            if (!GlobalConfig->doKillXl2tpdIfStillRunning) {
                errorMessage(QString("[l2tpd err] " +
                                     i18n("Bind to given port has failed."
                                          " Another %1 process is running."
                                          " Please stop %1 first.",
                                          daemon)));
                errorLine = __LINE__;
                kill_l2tpd = false;
            }
        } else {
            daemon = "l2tpd";
            if (!GlobalConfig->doKillL2tpdIfStillRunning) {
                errorMessage(QString("[l2tpd err] " +
                                     i18n("Bind to given port has failed."
                                          " Another %1 process is running."
                                          " Please stop %1 first.",
                                          daemon)));
                errorLine = __LINE__;
                kill_l2tpd = false;
            }
        }

        if (kill_l2tpd == true) {
            QProcess killl2tpdprocess(this);
            QString proc = GlobalConfig->pathToKillall;
            QStringList args;
            if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists())
                args.append("xl2tpd");
            else
                args.append("l2tpd");
            killl2tpdprocess.setEnvironment(*env);
            killl2tpdprocess.start(proc, args);
            if (!killl2tpdprocess.waitForStarted()) {
                errorMessage(i18n("l2tpd could not be killed."));
                errorMessage(QString("[l2tpd err] " +
                                     i18n("Bind to given port has failed."
                                          " Another %1 process is running."
                                          " Please stop %1 first.",
                                          daemon)));
                errorLine = __LINE__;
            } else {
                waitForFinished(&killl2tpdprocess, 100);
                // restart l2tpd
                //       if ( L2tpdProcess != 0)
                //        L2tpdProcess->kill();

                sleep(1);

                QString proc = "";
                QStringList args;
                //
                if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
                    debugMessage(1, i18n("Using %1.", QString("xl2tpd")));
                    proc = GlobalConfig->pathToXl2tpd;
                } else {
                    debugMessage(1, i18n("Using %1.", QString("l2tpd")));
                    proc = GlobalConfig->pathToL2tpd;
                }
                args.append("-p");
                args.append("/var/run/l2tpd" + GlobalConfig->currentProfile->getName() + ".pid");
                args.append("-c");
                args.append(tmpPath + "l2tpd." + GlobalConfig->currentProfile->getName() + ".conf");
                args.append("-s");
                args.append(tmpPath + "l2tp-secrets" + GlobalConfig->currentProfile->getName());
                args.append("-D");

                L2tpdProcess = new HelperProcess(this, proc, args, *env,
                                                 SLOT(readFromStdout_l2tpd()),
                                                 SLOT(readFromStderr_l2tpd()),
                                                 0, 0);
                if (!L2tpdProcess || !L2tpdProcess->start()) {
                    reportError(i18n("Failed to start \"%1\"." , QString("l2tpd")));
                    errorLine = __LINE__;
                } else {
                    debugMessage(0, i18n("%1 was already running. It was killed and restarted." , QString("l2tpd")));
                }
            }

        }
    } else if (msg.indexOf("Connection closed to", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        errorMessage(QString("[l2tpd err] " + i18n("Connection was closed.")) );
        errorLine = __LINE__;
    } else if (msg.indexOf("pppd exited for call", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        errorMessage(QString("[l2tpd err] " + i18n("pppd exited for call")) );
        errorLine = __LINE__;
    } else if (msg.indexOf("unrecognized option", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        errorMessage(QString("[l2tpd err] " + i18n("Unknown option in generated config file, please report to maintainer.")) );
        errorLine = __LINE__;
    }


    // normal
    if (NormalMsg) {
        debugMessage(1, "[l2tpd] " + msg);
    } else if (ErrorMsg) {
        errorMessage("[l2tpd err] " + msg);
    }

    if (errorLine) {
        debugMessage(0, i18n("There is a reason to stop connecting, terminating \"%1\" process." , QString("pppd")) );
        //terminateConnection ( L2tpdProcess );
        setStatusDisconnected(errorLine, reason);

        // remove kvpnc entries from secrets file
        pppdSecretsRemove();
    } else {
        // success
        if (connectSuccess) {
            setStatusConnected(__LINE__);
            //FIXME make it better
            gui->setPppdDevice("ppp0");
            NetworkInterface iface(GlobalConfig, kapp);
            if (iface.interfaceExist(gui->pppdDevice())) {
                gui->setTunnelInterfaceIP(iface.getInterfaceIP(gui->pppdDevice()));
                debugMessage(0, i18n("Tunnel device: %1\n" , gui->pppdDevice()));
            }
        }

    }
    //      if (GlobalConfig->appPointer->hasPendingEvents ())
    //    GlobalConfig->appPointer->processEvents();

}

void HandlerBase::processStderr_l2tpd(QString msg)
{
    bool NormalMsg = true;
    bool ErrorMsg = false;
    unsigned errorLine = 0;
    DisconnectionReason reason = DISCONNECTION_REASON_FATAL_ERROR;
    bool connectSuccess = false;

    debugMessage(7, QString("[l2tpd err raw] " + msg) );
    //
    //   if ( msg.length() > 3 )
    {

        //   logMessage ( QString( "[l2tpd err] " + msg ) , KVpncEnum::error );


        if (msg.indexOf("Maximum retries exceeded for tunnel", 0, Qt::CaseInsensitive) > -1) {
            ErrorMsg = true;
            debugMessage(0, QString("[l2tpd] " + i18n("Maximum number of L2TP connect retries exceeded for tunnel, waiting a moment....")) );
            errorLine = __LINE__;
        } else if (msg.indexOf("l2tp_call:Connecting to host", 0, Qt::CaseInsensitive) > -1) {
            NormalMsg = true;
            debugMessage(0, QString("[l2tpd] " + i18n("l2tp_call:Connecting to host")) );
            //    abort=true;
        } else if (msg.indexOf("maximum retries exceeded.", 0, Qt::CaseInsensitive) > -1) {
            ErrorMsg = true;
            errorMessage(QString("[l2tpd err] " + i18n("Maximum number of L2TP connect retries exceeded, giving up.")) );
            errorLine = __LINE__;
        } else if (msg.indexOf("Connection closed to", 0, Qt::CaseInsensitive) > -1) {
            ErrorMsg = true;
            errorMessage(QString("[l2tpd err] " + i18n("Connection was closed.")) );
            errorLine = __LINE__;
        } else if (msg.indexOf("pppd exited for call", 0, Qt::CaseInsensitive) > -1) {
            ErrorMsg = true;
            errorMessage(QString("[l2tpd err] " + i18n("pppd exited for call.")) );
            errorLine = __LINE__;
        } else if (msg.indexOf("Unable to load config file", 0, Qt::CaseInsensitive) > -1) {
            ErrorMsg = true;
            reportError(i18n("Syntax error in config detected. Please report that to the KVpnc maintainer."), "[l2tpd err]");
            errorLine = __LINE__;
        }

        else if (msg.indexOf("init_network: Unable to bind socket. Terminating", 0, Qt::CaseInsensitive) > -1 || msg.indexOf("Unable to bind socket: Address already in use", 0, Qt::CaseInsensitive) > -1) {
            ErrorMsg = true;
            bool kill_l2tpd = true;

            QString daemon = "xl2tpd";
            if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
                daemon = "xl2tpd";
                if (!GlobalConfig->doKillXl2tpdIfStillRunning) {
                    errorMessage(QString("[l2tpd err] " +
                                         i18n("Bind to given port has failed."
                                              " Another %1 process is running."
                                              " Please stop %1 first.",
                                              daemon)));
                    errorLine = __LINE__;
                    kill_l2tpd = false;
                }
            } else {
                daemon = "l2tpd";
                if (!GlobalConfig->doKillL2tpdIfStillRunning) {
                    errorMessage(QString("[l2tpd err] " +
                                         i18n("Bind to given port has failed."
                                              " Another %1 process is running."
                                              " Please stop %1 first.",
                                              daemon)));
                    errorLine = __LINE__;
                    kill_l2tpd = false;
                }
            }

            if (kill_l2tpd == true) {
                QProcess killl2tpdprocess(this);
                QString proc = GlobalConfig->pathToKillall;
                QStringList args;
                if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists())
                    args.append("xl2tpd");
                else
                    args.append("l2tpd");
                killl2tpdprocess.setEnvironment(*env);
                killl2tpdprocess.start(proc, args);
                if (!killl2tpdprocess.waitForStarted()) {
                    errorMessage(i18n("%1 could not be killed." , QString("l2tpd")) );
                    errorMessage(QString("[l2tpd err] " +
                                         i18n("Bind to given port has failed."
                                              " Another %1 process is running."
                                              " Please stop %1 first.",
                                              daemon)));
                    errorLine = __LINE__;
                } else {
                    waitForFinished(&killl2tpdprocess, 100);

                    // restart l2tpd
                    //       if ( L2tpdProcess != 0)
                    //        L2tpdProcess->kill();

                    sleep(1);

                    QString proc = "";
                    QStringList args;
                    if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
                        debugMessage(1, i18n("Using %1.", QString("xl2tpd")));
                        proc = GlobalConfig->pathToXl2tpd;
                    } else {
                        debugMessage(1, i18n("Using %1.", QString("l2tpd")));
                        proc = GlobalConfig->pathToL2tpd;
                    }
                    args.append("-p");
                    args.append("/var/run/l2tpd" + GlobalConfig->currentProfile->getName() + ".pid");
                    args.append("-c");
                    args.append(tmpPath + "l2tpd." + GlobalConfig->currentProfile->getName() + ".conf");
                    args.append("-s");
                    args.append(tmpPath + "l2tp-secrets" + GlobalConfig->currentProfile->getName());
                    args.append("-D");

                    L2tpdProcess = new HelperProcess(this, proc, args, *env,
                                                     SLOT(readFromStdout_l2tpd()),
                                                     SLOT(readFromStderr_l2tpd()),
                                                     0, 0);
                    if (!L2tpdProcess || !L2tpdProcess->start()) {
                        reportError(i18n("Failed to start \"%1\"." , QString("l2tpd")));
                        errorLine = __LINE__;
                    } else {
                        debugMessage(0, i18n("%1 was already running. It was killed and restarted." , QString("l2tpd")));
                    }
                }
            }
        }
        // control_finish: Connection established to 192.168.10.222, 1701.  Local: 55406, Remote: 37911.
        else if (msg.indexOf("Connection established", 0, Qt::CaseInsensitive) > -1) {
            NormalMsg = true;
            successMessage(QString("[l2tpd] " + i18n("Low level connection to %1 established."  , QString(GlobalConfig->currentProfile->getGateway()))));
        } else if (msg.indexOf("Call established", 0, Qt::CaseInsensitive) > -1) {
            NormalMsg = true;
            debugMessage(0, QString("[l2tpd] " + i18n("Low level connection to %1 established."  , QString(GlobalConfig->currentProfile->getGateway()))) );
            if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
                debugMessage(0, QString("[l2tpd] " + i18n("Low level connection %1 established."  , QString(GlobalConfig->currentProfile->getGateway()))) );
            }

            disconnect(&L2tpWaitForPppUpTimer, SIGNAL(timeout()), this, SLOT(checkL2tpPppUp()));
            connect(&L2tpWaitForPppUpTimer, SIGNAL(timeout()), this, SLOT(checkL2tpPppUp()));
            L2tpWaitForPppUpTimer.start(1000);

        } else if (msg.indexOf("Connecting to host", 0, Qt::CaseInsensitive) > -1) {
            NormalMsg = true;
            debugMessage(1, i18n("%1 is connecting to host %2..." , QString("l2tpd"), GlobalConfig->currentProfile->getGateway()));
        } else if (msg.indexOf("Listening on IP address", 0, Qt::CaseInsensitive) > -1
                   || msg.indexOf("Calling on tunnel", 0, Qt::CaseInsensitive) > -1) {
            NormalMsg = true;
        } else if (!gui->statusConnected() && msg.indexOf("check_control: control, cid =", 0, Qt::CaseInsensitive) > -1) {
            NormalMsg = true;
            // cid is greather than 0
            if (msg.section(',', 1, 1).section('=', 1, 1).trimmed() != "0") {             // check_control: control, cid = 17467, Ns = 2, Nr = 4
                successMessage(QString("[l2tpd] " + i18n("L2TP tunnel to %1 established."  , QString(GlobalConfig->currentProfile->getGateway()))));

                connectSuccess = true;
            }
        } else if (msg.indexOf("Connecting to host", 0, Qt::CaseInsensitive) > -1) {
            successMessage(QString("[l2tpd] " + i18n("L2TP connection to %1 established."  , QString(GlobalConfig->currentProfile->getGateway()))));
            if (!GlobalConfig->pathToXl2tpd.isEmpty() && QFile(GlobalConfig->pathToXl2tpd).exists()) {
                successMessage(QString("[l2tpd] " + i18n("L2TP tunnel to %1 established." , QString(GlobalConfig->currentProfile->getGateway()))));
            }
            connectSuccess = true;
        }

        if (connectSuccess) {
            setStatusConnected(__LINE__);
        }


        // normal
        if (NormalMsg) {
            debugMessage(1, "[l2tpd] " + msg);
        } else if (ErrorMsg) {
            errorMessage("[l2tpd err] " + msg);
        }
        if (errorLine) {
            debugMessage(0, i18n("There is a reason to stop connecting, terminating \"%1\" process." , QString("l2tpd")) );
            setStatusDisconnected(errorLine, reason);

            pppdSecretsRemove();
            return ;
        }
    }
    //   if (GlobalConfig->appPointer->hasPendingEvents ())
    //    GlobalConfig->appPointer->processEvents();

}

void HandlerBase::addAdditionalNetworkRoutes()
{
    if (GlobalConfig->currentProfile == 0)
        return ;

    if (!GlobalConfig->currentProfile->getAdditionalNetworkRoutes().isEmpty()) {
        debugMessage(0, i18n("Setting additional network routes..."));
        QStringList AdditionalNetworkRoutes = GlobalConfig->currentProfile->getAdditionalNetworkRoutes();

        int count = 1;

        QString dev = GlobalConfig->currentProfile->getNetworkDevice();

        NetworkInterface iface(GlobalConfig, kapp);
        QString defaultinterface = iface.getDefaultInterface();


        if (dev.isEmpty()) {
            if (defaultinterface.isEmpty())
                dev = "lo";
            else
                dev = defaultinterface;
        }
        if (dev == "default")
            dev = defaultinterface;
        else
            dev = "lo";

        debugMessage(1, i18n("Default interface: %1" , dev));

        QString tmpPath = KStandardDirs::locateLocal("data", "kvpnc/");
        QFile file(tmpPath + "addAdditionalNetworkRoutes." + GlobalConfig->currentProfile->getName() + ".sh");
        QString Route = "";
        QStringList RoutesList;
        QTextStream stream(&file);
        if (file.open(QIODevice::WriteOnly)) {
            stream << "#!" << GlobalConfig->InterpreterShell << "\n";
            for (QStringList::Iterator it = AdditionalNetworkRoutes.begin(); it != AdditionalNetworkRoutes.end(); ++it) {
                Route += "\t" + QString().setNum(count) + ": ";
                count++;
                QString net = (*it).section('#', 0, 0);

                QString Gateway = QString(*it).section('#', 1, 1);
                QString GatewayString = "";
                QString Interface = QString(*it).section('#', 2, 2);
                QString InterfaceString = "";
                bool extended = false;
                Route += net;
                if (!Gateway.isEmpty() && Gateway != "-") {
                    GatewayString += "gateway ";
                    GatewayString += Gateway;
                    Route +=  " " + i18n("over gateway") + " " + Gateway + "\n";
                    extended = true;
                }
                if (!Interface.isEmpty() && Interface != "-") {
                    InterfaceString += Interface;
                    if (Interface != "default")
                        dev = Interface;
                    Route += " " + i18n("over interface") + " " + dev + "\n";
                    extended = true;
                } else {
                    dev=defaultinterface;
                    Route += " " + i18n ( "over interface" ) + " " + dev + "\n";
                }
                RoutesList.append(Route);
                Route = "";

                if (net.indexOf("/32", 0, Qt::CaseInsensitive) > 0)
                    stream << GlobalConfig->pathToRoute << " add " << net << " " << GatewayString << " " << dev << "\n";
                else
                    stream << GlobalConfig->pathToRoute << " add -net " << net << " " << GatewayString << " " << dev << "\n";

            }
            file.close();
            QStringList args;
            args.append(tmpPath + "addAdditionalNetworkRoutes." + GlobalConfig->currentProfile->getName() + ".sh");
            QString tmpInterface = dev;

            RouteProcess = new HelperProcess(this, GlobalConfig->InterpreterShell, args, *env,
                                             SLOT(readFromStdout_route()),
                                             SLOT(readFromStderr_route()),
                                             0, 0);
            if (!RouteProcess || !RouteProcess->start()) {
                reportError(i18n("Failed to start \"%1\"." , QString("route (addtitional network routes)")));
                //disconnectClicked();
                delete RouteProcess;
                RouteProcess = 0L;
                return;
            } else {
                debugMessage(1, i18n("Adding the following additional network routes:"));
                for (QStringList::Iterator it = RoutesList.begin(); it != RoutesList.end(); ++it)
                    debugMessage(1, *it );
                RouteProcess->waitForFinished(100000);
                delete RouteProcess;
                RouteProcess = 0L;
            }

        }
    }
}

void HandlerBase::removeAdditionalNetworkRoutes()
{
    if (!GlobalConfig->currentProfile->getAdditionalNetworkRoutes().isEmpty()) {
        QStringList AdditionalNetworkRoutes = GlobalConfig->currentProfile->getAdditionalNetworkRoutes();
        QString dev = GlobalConfig->currentProfile->getNetworkDevice();

        NetworkInterface iface(GlobalConfig, kapp);
        QString defaultinterface = iface.getDefaultInterface();
        int count = 1;

        if (dev.isEmpty()) {
            if (defaultinterface.isEmpty())
                dev = "lo";
            else
                dev = defaultinterface;
        }
        if (dev == "default")
            dev = defaultinterface;
        else
            dev = "lo";


        debugMessage(1, i18n("Default interface: %1" , defaultinterface));

        QString tmpPath = KStandardDirs::locateLocal("data", "kvpnc/");
        QFile file(tmpPath + "delAdditionalNetworkRoutes." + GlobalConfig->currentProfile->getName() + ".sh");
        QString Route = "";
        QStringList RoutesList;
        QTextStream stream(&file);
        if (file.open(QIODevice::WriteOnly)) {
            stream << "#!" << GlobalConfig->InterpreterShell << "\n";
            for (QStringList::Iterator it = AdditionalNetworkRoutes.begin(); it != AdditionalNetworkRoutes.end(); ++it) {
                Route += "\t" + QString().setNum(count) + ": ";
                count++;

                QString net = (*it).section('#', 0, 0);

                QString Gateway = QString(*it).section('#', 1, 1);
                QString GatewayString = "";
                QString Interface = QString(*it).section('#', 2, 2);
                QString InterfaceString = "";
                bool extended = false;
                Route += net;
                if (!Gateway.isEmpty() && Gateway != "-") {
                    GatewayString += "gw ";
                    GatewayString += Gateway;
                    Route += " " + i18n("over gateway") + " " + Gateway + "\n";
                    extended = true;
                }
                if (!Interface.isEmpty() && Interface != "-") {
                    InterfaceString += Interface;
                    if (Interface != "default")
                        dev = Interface;
                    Route += " " + i18n("over interface") + " " + dev + "\n";
                    extended = true;
                } else {
                    dev=defaultinterface;
                    Route += " " + i18n ( "over interface" ) + " " + dev + "\n";
                }

                RoutesList.append(Route);
                Route = "";

                if (net.indexOf("/32", 0, Qt::CaseInsensitive) > 0)
                    stream << GlobalConfig->pathToRoute << " del " << net << " " << GatewayString << " " << dev << "\n";
                else
                    stream << GlobalConfig->pathToRoute << " del -net " << net << " " << GatewayString << " " << dev << "\n";

            }
            file.close();
            QStringList args;
            args.append(tmpPath + "delAdditionalNetworkRoutes." + GlobalConfig->currentProfile->getName() + ".sh");
            QString tmpInterface = dev;

            RouteProcess = new HelperProcess(this, GlobalConfig->InterpreterShell, args, *env,
                                             SLOT(readFromStdout_route()),
                                             SLOT(readFromStderr_route()),
                                             0, 0);
            if (!RouteProcess || !RouteProcess->start()) {
                reportError(i18n("Failed to start \"%1\"." , QString("route (addtitional network routes)")));
                delete RouteProcess;
                RouteProcess = 0L;
                //disconnectClicked();
                return;
            } else {
                debugMessage(1, i18n("Removing the following additional network routes:"));
                for (QStringList::Iterator it = RoutesList.begin(); it != RoutesList.end(); ++it)
                    debugMessage(1, *it );
                RouteProcess->waitForFinished(100000);
                delete RouteProcess;
                RouteProcess = 0L;
            }
        }
    }
}

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

        debugMessage(0, "[route] " + msg);

    }
}

void HandlerBase::readFromStderr_route()
{
    QStringList msg_list = QString(RouteProcess->readAllStandardError()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);

        debugMessage(0, "[route err] " + msg);

    }
}

void HandlerBase::setPingTest()
{
    pingtest = true;
}

int HandlerBase::connectCountIncrement()
{
    return ++connectCounter;
}

void HandlerBase::connectCountZero()
{
    connectCounter = 0;
}

void HandlerBase::slotConnectTimedOut()
{
    gui->slotConnectTimedOut();
}

void HandlerBase::slotDurationEvent()
{
    gui->slotDurationEvent();
}

int HandlerBase::connectSeconds() const {
    return connectedSeconds;
}

int HandlerBase::connectSecondsIncrement() {
    return ++connectedSeconds;
}

void HandlerBase::connectSecondsZero() {
    connectedSeconds = 0;
}

void HandlerBase::connectionEnded()
{
    durationTimer.stop();
    disconnect(&durationTimer, SIGNAL(timeout()), this, SLOT(slotDurationEvent()));
    gui->connectionEnded();
}

bool HandlerBase::timerIsActive() {
    return timer.isActive();
}

void HandlerBase::timerStop() {
    timer.stop();
}

void HandlerBase::debugMessage(unsigned int level, const QString &message) {
    if (GlobalConfig->KvpncDebugLevel > (int)level) {
        GlobalConfig->appendLogEntry(message, KVpncEnum::debug);
    }
}

void HandlerBase::errorMessage(const QString &message) {
    GlobalConfig->appendLogEntry(message, KVpncEnum::error);
}

void HandlerBase::successMessage(const QString &message) {
    GlobalConfig->appendLogEntry(message, KVpncEnum::success);
}

/**
 * The basic principle is that if we are going to bother the user with a dialog, it had
 * better be for an error, and thus something that also needs to be logged.
 *
 * For now at least, we keep support for KMessageBox::error() and KMessageBox::sorry(),
 * though I'm not sure what the rationale really is for this.
 */
void HandlerBase::reportError(const QString &text, const QString &caption, KVpncEnum::LogType type) {
    switch (type) {
    case KVpncEnum::error:
        KMessageBox::error(gui, text, caption);
        break;
    case KVpncEnum::info:
        KMessageBox::sorry(gui, text, caption);
        break;
    default:
        // Since we are bothering the user with a dialog, it is basically a programming error
        // to use anything other than the explicit cases above. Oh well, do *something*.
        KMessageBox::error(gui, text, caption);
        break;
    }
    errorMessage(text);
}

HandlerBase::HelperProgram::HelperProgram(QString name, QString minimumVersion, QString regExp):
        m_name(name),
        m_minimumVersion(minimumVersion),
        m_actualVersion("0.0"),
        m_regExp(regExp)
{
}

const QString HandlerBase::HelperProgram::name() const
{
    return m_name;
}

const QString HandlerBase::HelperProgram::minimumVersion() const
{
    return m_minimumVersion;
}

const QString HandlerBase::HelperProgram::actualVersion() const
{
    return m_actualVersion;
}

void HandlerBase::HelperProgram::setActualVersion(QString actualVersion)
{
    m_actualVersion = actualVersion;
}

bool HandlerBase::HelperProgram::isGe() const
{
    return isGe(m_minimumVersion, m_actualVersion);
}

bool HandlerBase::HelperProgram::actualIsGe(QString againstVersion) const
{
    return isGe(m_actualVersion, againstVersion);
}

bool HandlerBase::HelperProgram::isGe(QString reference, QString against) const
{
    QRegExp separator(m_regExp);
    unsigned n;
    QString referenceSection;
    QString againstSection;
    unsigned referenceN;
    unsigned againstN;

    n = 0;
    do
    {
        referenceSection = reference.section(separator, n, n);
        againstSection = against.section(separator, n, n);
        referenceN = referenceSection.toUInt();
        againstN = againstSection.toUInt();
        if (againstN > referenceN) {
            // Bail out on first section which is gt...
            return true;
        }
        n++;
    } while (referenceSection.length());

    // Last section!
    return (againstN >= referenceN);
}

void HandlerBase::pppdSecretsRemove(const QString &secretsFilename)
{
    QFile file(secretsFilename);
    debugMessage(0, i18n("pppd secrets file: %1", secretsFilename));
    QTextStream stream(&file);
    if (file.open(IO_ReadOnly)) {
        QString line = "";
        QString papsecret_content = "";
        bool kvpnc_start_marker_found = false;
        bool kvpnc_end_marker_found = false;
        while (!stream.atEnd()) {
            line = stream.readLine(); // line of text excluding '\n'
            if (line == "# --- generated by kvpnc. Do not edit it.") {
                kvpnc_end_marker_found = true;
                debugMessage(2, i18n("End marker in %1 found", secretsFilename));
            }
            if (line == "# +++ generated by kvpnc. Do not edit it.") {
                kvpnc_start_marker_found = true;
                debugMessage(2, i18n("Start marker in %1 found", secretsFilename));
            }

            if (kvpnc_start_marker_found == false) {
                papsecret_content += line;
                papsecret_content += '\n';
            }
        }
        file.close();
        if (file.remove()) {
            debugMessage(2, i18n("File %1 successfully removed", secretsFilename));
            //                          file.setName("/etc/ppp/pap-secrets2");
            if (file.open(IO_WriteOnly)) {
                stream.setDevice(&file);
                stream << papsecret_content;
                file.close();
                debugMessage(2, i18n("File %1 successfully rewritten", secretsFilename));
            } else {
                errorMessage(i18n("File %1 rewrite failed", secretsFilename));
            }
        } else {
            errorMessage(i18n("File %1 remove failed", secretsFilename));
        }

    } else {
        errorMessage(i18n("File %1 could not opened!", secretsFilename));
    }
}

void HandlerBase::pppdSecretsRemove()
{
    if (GlobalConfig->currentProfile->getAuthMethod() == "chap" ||
            GlobalConfig->currentProfile->getAuthMethod() == "mschap" ||
            GlobalConfig->currentProfile->getAuthMethod() == "mschap-v2") {
        // remove kvpnc entries from chap-secerets
        pppdSecretsRemove("/etc/ppp/chap-secrets");
    }
    if (GlobalConfig->currentProfile->getAuthMethod() == "pap") {
        // remove kvpnc entries from pap-secerets
        pppdSecretsRemove("/etc/ppp/pap-secrets");
    }
}

bool HandlerBase::pppdSecretsAdd(const QString &secretsFilename)
{
    debugMessage(0, i18n("pppd secrets file: %1", secretsFilename));
    Utils(GlobalConfig, this).doChmod(secretsFilename, "go-rwx");
    QFile file(secretsFilename);
    QTextStream stream(&file);
    if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
        stream << "# +++ generated by kvpnc. Do not edit it." << "\n";
        stream << "# profile: " + GlobalConfig->currentProfile->getName() << "\n";

        if (GlobalConfig->currentProfile->getSaveUserPassword())
            GlobalConfig->TmpPassword = GlobalConfig->currentProfile->getUserPassword();

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

        debugMessage(0, i18n("Username: %1" , UsernameStr));

        if (GlobalConfig->currentProfile->getUseNtDomainName() && !GlobalConfig->currentProfile->getNtDomainName().isEmpty()) {
            // line: "<domainname>\\<username>"<tab><remote host><tab>"<password>"<tab><ip address>
            stream << "\"" << GlobalConfig->currentProfile->getNtDomainName() << "\\\\" << UsernameStr << "\"\t" << "*" << "\t" << " \"" << GlobalConfig->TmpPassword << "\"\t*\n";
        } else {
            // line: "<username>"<tab><remote host><tab>"<password>"<tab><ip address>
            stream << "\"" << UsernameStr << "\"\t" << "*" << "\t" << " \"" << GlobalConfig->TmpPassword << "\"\t*\n";

        }
        stream << "# --- generated by kvpnc. Do not edit it." << "\n";
        file.close();

        Utils(GlobalConfig, this).doChmod(secretsFilename, "go-rwx");
        return true;
    }
    return false;
}

bool HandlerBase::pppdSecretsAdd()
{
    if (GlobalConfig->currentProfile->getAuthMethod() == "chap" ||
            GlobalConfig->currentProfile->getAuthMethod() == "mschap" ||
            GlobalConfig->currentProfile->getAuthMethod() == "mschap-v2") {
        if (pppdSecretsAdd("/etc/ppp/chap-secrets")) {
            return true;
        }
    }
    if (GlobalConfig->currentProfile->getAuthMethod() == "pap") {
        if (pppdSecretsAdd("/etc/ppp/pap-secrets")) {
            return true;
        }
    }
    return false;
}

bool HandlerBase::kernelModuleLoad(const QString &module)
{
    if (!Utils(GlobalConfig, kapp).loadKernelModule(module, kapp)) {
        reportError(i18n("Loading of module \"%1\" failed.", module));
        return false;
    } else {
        debugMessage(0, i18n("Loading of module \"%1\" was successful.", module));
        return true;
    }
}

void HandlerBase::kernelModuleUnload(const QString &module)
{
    if (!Utils(GlobalConfig, gui).unloadKernelModule(module, kapp)) {
        debugMessage(3, i18n("Unloading module \"%1\" failed" , module));
    } else {
        debugMessage(3, i18n("Unloading module \"%1\" succeeded" , module));
    }
}

bool HandlerBase::enableTunnelSupport()
{
    bool tunsupportfound = false;
    QString procmisc = "";
    QFile f("/proc/misc");
    if (f.open(QIODevice::ReadOnly)) {
        QStringList contentlist = QString(f.readAll()).split("\n");
        for (int i = 0; i < contentlist.size(); ++i) {
            QString line = contentlist.at(i);
            if (line.contains("tun", Qt::CaseInsensitive)) {
                debugMessage(3, i18n("Support for TUN/TAP found compiled into kernel."));
                tunsupportfound = true;
                break;
            }
        }
        f.close();
    } else {
        return false;
    }
    if (!tunsupportfound) {
        // load the module 'tun'
        if (!kernelModuleLoad("tun")) {
            return false;
        }
        debugMessage(3, i18n("Support for TUN/TAP loaded into kernel."));
    }

    if (!Utils(GlobalConfig, kapp).tunDevExists() &&
            !Utils(GlobalConfig, kapp).createTunDev()) {
        reportError(i18n("Unable to find or create tunnel device file \"%1\"." , QString("/dev/net/tun")));
        return false;
    }
    return true;
}

/**
 * The rules for having an authentication data capability which is shared by
 * multiple protocol handlers is to balance generality with enough "smarts"
 * to not bother the user with unused options.
 *
 * For a GUI dialog, we resolve this as follows:
 *
 *  - We hide any fields which are not valid for the protocol.
 *
 *  - We disable any fields which are not valid for the current configuration.
 *
 *  - We *don't* hide/disable fields just because we know them to be valid.
 *    Instead, we try to set the focus as "intelligently" as possible.
 *
 * Basically, by not hiding fields which are relevant we give a consistent
 * user experience, and also provide the option of - for example - trying
 * an alternative username (even if the username is not the issue).
 */
bool HandlerBase::getAuthenticationData(bool AuthRetry)
{
    // If authentication failed, all bets are off.
    bool requestUsername = AuthRetry;
    bool requestGroupPassword = AuthRetry;
    bool askUsernamePass = AuthRetry;

    // Based on data, do we need a username?
    if (GlobalConfig->currentProfile->getUserName().isEmpty()) {
        requestUsername = true;
    }

    // Based on data, do we need a group password?
    GlobalConfig->currentProfile->getSavePsk();
    GlobalConfig->currentProfile->getPskIsInFile();
    if (GlobalConfig->currentProfile->getPreSharedKey().isEmpty() &&
        !GlobalConfig->currentProfile->getAllowEmptyGroupPassword()) {
        requestGroupPassword = true;
    }

    // Based on data, do we need a password?
    if (GlobalConfig->currentProfile->getUserPassword().isEmpty()) {
        askUsernamePass = true;
    }
    if (GlobalConfig->currentProfile->getAskUserPasswordOnEachConnect()) {
        debugMessage(4, i18n("User password on each connect forced."));
        askUsernamePass = true;
    }

    // Show the dialog.
    if (requestUsername || askUsernamePass || requestGroupPassword) {

        // TBD: right now, AFAIK, all the protocol handlers we expect *can* use
        // both a username and a group password, but none of the support an ID
        // as a piece of authentication data.
        //
        // So, this is all hardcoded until I know better...
        EnterUsernamePasswordDialog dlg(gui, i18n("Enter Account Data"), true, true);
        dlg.LabelID->hide();
        dlg.IDEdit->hide();

        // Enable/disable stuff.
        dlg.PSKLineEdit->setEnabled(!GlobalConfig->currentProfile->getAllowEmptyGroupPassword());

        dlg.UsernameEdit->setText(GlobalConfig->currentProfile->getUserName());
        dlg.PSKLineEdit->setText(GlobalConfig->currentProfile->getPreSharedKey());
        dlg.PasswordEdit->setText(GlobalConfig->currentProfile->getUserPassword());

        // Try to set the focus to somewhere sane.
        if (requestUsername) {
            dlg.UsernameEdit->setFocus();
        } else if (requestGroupPassword || !askUsernamePass) {
            dlg.PSKLineEdit->setFocus();
        } else if (askUsernamePass) {
            dlg.PasswordEdit->setFocus();
        }

        dlg.SaveUsernameCheckBox->setChecked(!GlobalConfig->currentProfile->getDontSaveUsername());
        dlg.SavePskCheckBox->setChecked(GlobalConfig->currentProfile->getSavePsk());
        dlg.SavePasswordCheckBox->setChecked(GlobalConfig->currentProfile->getSaveUserPassword());

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

            if (requestUsername && GlobalConfig->TmpUsername.isEmpty()) {
                errorMessage(i18n("Username is empty."));
                return false;
            }
            if (requestGroupPassword && GlobalConfig->TmpGroupPassword.isEmpty()) {
                errorMessage(i18n("PSK is empty"));
                return false;
            }
            if (askUsernamePass && GlobalConfig->TmpPassword.isEmpty()) {
                errorMessage(i18n("Password is empty."));
                return false;
            }

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

            bool needSave = requestUsername && dlg.SaveUsernameCheckBox->isChecked();
            GlobalConfig->currentProfile->setDontSaveUsername(!dlg.SaveUsernameCheckBox->isChecked());
            GlobalConfig->currentProfile->setUserName(dlg.UsernameEdit->text());

            needSave = needSave || (requestGroupPassword && dlg.SavePskCheckBox->isChecked());
            GlobalConfig->currentProfile->setSavePsk(dlg.SavePskCheckBox->isChecked());
            GlobalConfig->currentProfile->setPreSharedKey(GlobalConfig->TmpGroupPassword);

            needSave = needSave || (askUsernamePass && dlg.SavePasswordCheckBox->isChecked());
            GlobalConfig->currentProfile->setSaveUserPassword(dlg.SavePasswordCheckBox->isChecked());
            GlobalConfig->currentProfile->setUserPassword(GlobalConfig->TmpPassword);

            if (needSave) {
                debugMessage(2, i18n("Need to save because user had request it."));
                GlobalConfig->saveOptions(true, GlobalConfig->currentProfile->getName());
            }
            return true;
        } else {
            debugMessage(0, i18n("Connect canceled because account data dialog aborted."));
            return false;
        }
    } else {
        GlobalConfig->TmpPassword = GlobalConfig->currentProfile->getUserPassword();
        GlobalConfig->TmpGroupPassword = GlobalConfig->currentProfile->getPreSharedKey();
        GlobalConfig->TmpUsername = GlobalConfig->currentProfile->getUserName();
        return true;
    }
}

HandlerBase::HelperProcess::HelperProcess(
    HandlerBase *parent,
    const QString &program, QStringList &args, QStringList &env,
    const char *processOutputSlot, const char *processErrorSlot,
    const char *startedSlot, const char *finishedSlot) :
        KProcess(),
        m_parent(parent),
        m_program(program),
        m_processOutputSlot(processOutputSlot),
        m_processErrorSlot(processErrorSlot),
        m_startedSlot(startedSlot),
        m_finishedSlot(finishedSlot)
{
    setOutputChannelMode(KProcess::SeparateChannels);
    setEnvironment(env);
    if (!connect(this, SIGNAL(readyReadStandardOutput()), m_parent, m_processOutputSlot)) {
        m_parent->errorMessage(i18n("Failed to connect to SLOT(%1) (%2)", m_processOutputSlot, "stdout"));
    }
    if (!connect(this, SIGNAL(readyReadStandardError()), m_parent, m_processErrorSlot)) {
        m_parent->errorMessage(i18n("Failed to connect to SLOT(%1) (%2)", m_processErrorSlot, "stderr"));
    }
    if (m_startedSlot) {
        if (!connect(this, SIGNAL(started()), m_parent, m_startedSlot)) {
            m_parent->errorMessage(i18n("Failed to connect to SLOT(%1) (%2)", m_startedSlot, "started"));
        }
    }
    if (m_finishedSlot) {
        if (!connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), m_parent, m_finishedSlot)) {
            m_parent->errorMessage(i18n("Failed to connect to SLOT(%1) (%2)", m_finishedSlot, "finished"));
        }
    }

    m_parent->debugMessage(1, i18n("Starting '%1 %2'", m_program, args.join(" ")));
    setProgram(m_program, args);
    setEnvironment(env);
}

HandlerBase::HelperProcess::~HelperProcess()
{
    unsigned long timeoutMicroseconds = 1000000;
    unsigned long wait = 10000;
    unsigned long count = timeoutMicroseconds / wait;

    m_parent->debugMessage(1, i18n("Stopping \"%1\"" , m_program));

    disconnect(this, SIGNAL(readyReadStandardOutput()), m_parent, m_processOutputSlot);
    disconnect(this, SIGNAL(readyReadStandardError()), m_parent, m_processErrorSlot);
    if (m_startedSlot) {
        disconnect(this, SIGNAL(started()), m_parent, m_startedSlot);
    }
    if (m_finishedSlot) {
        disconnect(this, SIGNAL(finished(int, QProcess::ExitStatus)), m_parent, m_finishedSlot);
    }

    // Try the nice way first.
    terminate();
    while (count && state() == QProcess::Running) {
        usleep(wait);
        if (kapp->hasPendingEvents()) {
            kapp->processEvents();
        }
        count--;
    }

    // If it is still going, get serious.
    if (state() == QProcess::Running) {
        m_parent->errorMessage(i18n("Timed out waiting for \"%1\" to terminate...", m_program));
        kill();
    }

}

QByteArray HandlerBase::HelperProcess::readAllStandardOutput()
{
    return KProcess::readAllStandardOutput();
}

QByteArray HandlerBase::HelperProcess::readAllStandardError()
{
    return KProcess::readAllStandardError();
}

bool HandlerBase::HelperProcess::start(unsigned long timeoutMicroseconds)
{
    KProcess::start();
    unsigned long wait = 10000;
    unsigned long count = timeoutMicroseconds / wait;
    while (count && state() != QProcess::Running) {
        usleep(wait);
        if (kapp->hasPendingEvents()) {
            kapp->processEvents();
        }
        count--;
    }

    // Did that work out ok?
    if (state() != QProcess::Running) {
        m_parent->errorMessage(i18n("Timed out waiting for \"%1\" to start...", m_program));
        return false;
    }
    return true;
}

void HandlerBase::HelperProcess::waitForFinished(unsigned long timeoutMicroseconds)
{
    unsigned long wait = 10000;
    unsigned long count = timeoutMicroseconds / wait;

    m_parent->debugMessage(2, i18n("Waiting for \"%1\" to terminate...", m_program));

    while (count && state() == QProcess::Running) {
        usleep(wait);
        if (kapp->hasPendingEvents()) {
            kapp->processEvents();
        }
        count--;
    }
    if (state() == QProcess::Running) {
        m_parent->errorMessage(i18n("Timed out waiting for \"%1\" to terminate...", m_program));
    }
}

qint64 HandlerBase::HelperProcess::write(const QByteArray &byteArray)
{
    return KProcess::write(byteArray);
}

HandlerBase::HelperPtyProcess::HelperPtyProcess(
    HandlerBase *parent,
    const QString &program, QStringList &args, QStringList &env,
    const char *processOutputSlot, const char *processErrorSlot,
    const char *ptyOutputSlot,
    const char *startedSlot, const char *finishedSlot) :
        KPtyProcess(),
        m_parent(parent),
        m_program(program),
        m_processOutputSlot(processOutputSlot),
        m_processErrorSlot(processErrorSlot),
        m_ptyOutputSlot(ptyOutputSlot),
        m_startedSlot(startedSlot),
        m_finishedSlot(finishedSlot)
{
    setOutputChannelMode(KProcess::SeparateChannels);
    setPtyChannels(KPtyProcess::AllChannels);
    setUseUtmp(true);
    if (!connect(this, SIGNAL(readyReadStandardOutput()), m_parent, m_processOutputSlot)) {
        m_parent->errorMessage(i18n("Failed to connect to SLOT(%1)", m_processOutputSlot));
    }
    if (!connect(this, SIGNAL(readyReadStandardError()), m_parent, m_processErrorSlot)) {
        m_parent->errorMessage(i18n("Failed to connect to SLOT(%1)", m_processErrorSlot));
    }
    if (!connect(KPtyProcess::pty(), SIGNAL(readyRead()), m_parent, m_ptyOutputSlot)) {
        m_parent->errorMessage(i18n("Failed to connect to SLOT(%1)", m_ptyOutputSlot));
    }
    if (m_startedSlot) {
        if (!connect(this, SIGNAL(started()), m_parent, m_startedSlot)) {
            m_parent->errorMessage(i18n("Failed to connect to SLOT(%1)", m_startedSlot));
        }
    }
    if (m_finishedSlot) {
        if (!connect(this, SIGNAL(finished(int, QProcess::ExitStatus)), m_parent, m_startedSlot)) {
            m_parent->errorMessage(i18n("Failed to connect to SLOT(%1)", m_startedSlot));
        }
    }

    m_parent->debugMessage(1, i18n("Starting '%1 %2'", m_program, args.join(" ")));
    setProgram(m_program, args);
    setEnvironment(env);
}

HandlerBase::HelperPtyProcess::~HelperPtyProcess()
{
    unsigned long timeoutMicroseconds = 1000000;
    unsigned long wait = 10000;
    unsigned long count = timeoutMicroseconds / wait;

    m_parent->debugMessage(1, i18n("Stopping \"%1\"" , m_program));

    // Try the nice way first.
    terminate();
    while (count && state() == QProcess::Running) {
        usleep(wait);
        if (kapp->hasPendingEvents()) {
            kapp->processEvents();
        }
        count--;
    }

    // If it is still going, get serious.
    if (state() == QProcess::Running) {
        m_parent->errorMessage(i18n("Timed out waiting for \"%1\" to terminate...", m_program));
        kill();
    }
    disconnect(this, SIGNAL(readyReadStandardOutput()), m_parent, m_processOutputSlot);
    disconnect(this, SIGNAL(readyReadStandardError()), m_parent, m_processErrorSlot);
    disconnect(KPtyProcess::pty(), SIGNAL(readyRead()), m_parent, m_ptyOutputSlot);
    if (m_startedSlot) {
        disconnect(this, SIGNAL(started()), m_parent, m_startedSlot);
    }
    if (m_finishedSlot) {
        disconnect(this, SIGNAL(finished(int, QProcess::ExitStatus)), m_parent, m_finishedSlot);
    }
}

KPtyDevice *HandlerBase::HelperPtyProcess::pty()
{
    return KPtyProcess::pty();
}

QByteArray HandlerBase::HelperPtyProcess::readAllStandardOutput()
{
    return KPtyProcess::readAllStandardOutput();
}

QByteArray HandlerBase::HelperPtyProcess::readAllStandardError()
{
    return KPtyProcess::readAllStandardError();
}

bool HandlerBase::HelperPtyProcess::start(unsigned long timeoutMicroseconds)
{
    KPtyProcess::start();
    unsigned long wait = 10000;
    unsigned long count = timeoutMicroseconds / wait;
    while (count && state() != QProcess::Running) {
        usleep(wait);
        if (kapp->hasPendingEvents()) {
            kapp->processEvents();
        }
        count--;
    }

    // Did that work out ok?
    if (state() != QProcess::Running) {
        m_parent->errorMessage(i18n("Timed out waiting for \"%1\" to start...", m_program));
        return false;
    }
    return true;
}

void HandlerBase::HelperPtyProcess::waitForFinished(unsigned long timeoutMicroseconds)
{
    unsigned long wait = 10000;
    unsigned long count = timeoutMicroseconds / wait;

    m_parent->debugMessage(2, i18n("Waiting for \"%1\" to terminate...", m_program));

    while (count && state() == QProcess::Running) {
        usleep(wait);
        if (kapp->hasPendingEvents()) {
            kapp->processEvents();
        }
        count--;
    }
    if (state() == QProcess::Running) {
        m_parent->errorMessage(i18n("Timed out waiting for \"%1\" to terminate...", m_program));
    }
}

qint64 HandlerBase::HelperPtyProcess::write(const QByteArray &byteArray)
{
    return KPtyProcess::write(byteArray);
}
