/*****************************************************************************
 * 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 "SshHandler.h"
#include "enterpassworddialog.h"
#include "kvpnc.h"
#include "kvpncconfig.h"
#include "utils.h"

SshHandler::SshHandler(
    KVpnc *ui,
    KVpncConfig *config):
        HandlerBase(ui, config, "SSH", "ssh", false),
        SshDevice(""),
        SshProcess(0),
        SshPty(0)
{
}

bool SshHandler::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 ssh
        if (!Utils(GlobalConfig).getToolInfo(IpsecType)->found) {
            reportError(i18n("Unable to find \"%1\" at \"%2\".", IpsecType, GlobalConfig->pathToSsh));
            errorLine = __LINE__;
        } else {
            debugMessage(0, i18n("Found helper %1 at %2", IpsecType, GlobalConfig->pathToSsh));
        }
    }

    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." , QString(GlobalConfig->currentProfile->getGateway())));
            errorLine = __LINE__;
        } else {
            debugMessage(0, i18n("Gateway hostname (%1) resolved to \"%2\"." , QString(GlobalConfig->currentProfile->getGateway()), GlobalConfig->TmpGatewayIP));
        }
    }

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

    if (!errorLine)
    {
        if (!enableTunnelSupport()) {
            errorLine = __LINE__;
        }
    }

    if (!errorLine)
    {
        // here we go
        if (GlobalConfig->currentProfile->getExecuteCmdBeforeConnect())
            executeCommandBeforeConnect();
    }

    QStringList args;
    if (!errorLine)
    {
        //SshProcess->setUseUtmp(true);

        //    QString AskPassScript= tmpPath+"ssh."+GlobalConfig->currentProfile->getName()+".askpass.sh";
        //
        //    QFile askpassfile (AskPassScript );
        //    QTextStream stream ( &askpassfile );
        //    if ( askpassfile.open ( QIODevice::WriteOnly ) )
        //    {
        //     stream <<  "#!"<< GlobalConfig->InterpreterShell << "\n";
        //     stream << "# generated by kvpnc. Do not edit it." << "\n";
        //     stream << "# profile: " + GlobalConfig->currentProfile->getName() << "\n";
        //     stream << "echo $1" << "\n";
        //     stream << "echo " << GlobalConfig->TmpPassword << "\n";
        //     stream << "" << "\n";
        //
        //     askpassfile.close();
        //      }
        //    else
        //    {
        //     logMessage ( i18n ( "\"%1\" write failed!", QString(askpassfile.name() )), KVpncEnum::error );
        //     setGuiStatus ( disconnected );
        //     return;
        //     }
        //
        //    Utils ( GlobalConfig, this ).doChmod (AskPassScript,"a+x"  );
        //    Utils ( GlobalConfig, this ).doChmod (AskPassScript,"go-rw"  );

        // FIXME make it dynamiclly
        SshDevice = "";
        if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun")
            SshDevice = "tun0";
        else
            SshDevice = "tap0";

        // FIXME make it dynamiclly
        if (GlobalConfig->currentProfile->getUseSshConfigRemoteScript() && !GlobalConfig->currentProfile->getSshConfigRemoteScript().isEmpty()) {
            args.append("-w0");
        } else {
            args.append("-w0:0");
        }

        if (GlobalConfig->SshDebugLevel > 0) {
            QString SshDebug = "-";
            for (int i = 0; i < GlobalConfig->SshDebugLevel; i++)
                SshDebug += "v";
            //     args.append(SshDebug);
        }

        // using ssh key
        if (!GlobalConfig->currentProfile->getAuthWithUsernameAndPassword()) {
            if (!GlobalConfig->currentProfile->getPreSharedKey().isEmpty()) {
                debugMessage(2, i18n("Using keyfile: %1" , QString(GlobalConfig->currentProfile->getPreSharedKey())));
                args.append(" -i");
                args.append(GlobalConfig->currentProfile->getPreSharedKey());
            } else {
                reportError(i18n("No SSH key file specified."));
                errorLine = __LINE__;
            }
        }

        args.append("-t") ;
        args.append("-t") ;

        args.append("-n");

        // login name
        args.append("-l") ;
        args.append(GlobalConfig->TmpUsername);



        if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun") {
            debugMessage(2, i18n("Using tunnel device type: %1" , QString("TUN")));
        }
        if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tap") {
            args.append("-o");
            args.append("Tunnel=ethernet");
            debugMessage(2, i18n("Using tunnel device type: %1" , QString("TAP")));
        }


        if (GlobalConfig->currentProfile->getUseRemotePort()) {
            args.append("-p");
            args.append(QString().setNum(GlobalConfig->currentProfile->getRemotePort()));
        }

        args.append(GlobalConfig->TmpGatewayIP);


        // FIXME add detection on server and make it dynamiclly
        if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun") {
            if (!GlobalConfig->currentProfile->getUseSshConfigRemoteScript()) {
                args.append(GlobalConfig->pathToIfconfig);
                args.append(" " + SshDevice + " " + GlobalConfig->currentProfile->getRemoteVirtualIP() + " pointopoint " + GlobalConfig->currentProfile->getLocalVirtualIP() + " up ; /bin/echo ssh_is_up");
            } else {
                if (!GlobalConfig->currentProfile->getSshConfigRemoteScript().isEmpty()) {
                    args.append(GlobalConfig->currentProfile->getSshConfigRemoteScript() + " tun " + GlobalConfig->currentProfile->getRemoteVirtualIP() + " " + GlobalConfig->currentProfile->getLocalVirtualIP() + " up ; /bin/echo ssh_is_up");

                    debugMessage(3, i18n("Using %1 as %2." , QString(GlobalConfig->currentProfile->getSshConfigRemoteScript()), i18n("ssh config remote script")));
                } else {
                    reportError(i18n("%1 is empty." , QString(i18n("ssh config remote script"))));
                    errorLine = __LINE__;
                }
            }
        }

        if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tap") {
            if (!GlobalConfig->currentProfile->getUseSshConfigRemoteScript()) {
                args.append(GlobalConfig->pathToIfconfig);
                args.append(QString(" " + SshDevice + " " + GlobalConfig->currentProfile->getLocalVirtualIP() + " netmask " + GlobalConfig->currentProfile->getRemoteVirtualIP() + " up;  /bin/echo ssh_is_up")) ;
            } else {
                if (!GlobalConfig->currentProfile->getSshConfigRemoteScript().isEmpty()) {
                    args.append(GlobalConfig->currentProfile->getSshConfigRemoteScript() + " tap ; /bin/echo ssh_is_up");
                    debugMessage(3, i18n("Using %1 as %2." , QString(GlobalConfig->currentProfile->getSshConfigRemoteScript()), i18n("ssh config remote script")));
                } else {
                    reportError(i18n("%1 is empty.", QString(i18n("ssh config remote script"))));
                    errorLine = __LINE__;
                }
            }
        }

        debugMessage(3, i18n("%1 arguments: %2", QString("ssh"), args.join(" ")));
    }

    QStringList environment;
    if (!errorLine)
    {
        environment.append("LC_ALL=C");
        environment.append("LANG=C");
        environment.append("PATH=/bin:/usr/bin:/usr/sbin:/sbin");
        //      environment.append( "SSH_ASKPASS",AskPassScript );

        ToolInfo *KsshaskpassInfo = Utils(GlobalConfig).getToolInfo("ksshaskpass");
        ToolInfo *GnomeaskpassInfo = Utils(GlobalConfig).getToolInfo("gnome-ssh-askpass");

        if (KsshaskpassInfo->found) {
            environment.append("SSH_ASKPASS=" + GlobalConfig->pathToKsshAskpass);
            debugMessage(0, i18n("%1 will be used.", QString("ksshaskpass")));
        } else if (GnomeaskpassInfo->found) {
            environment.append("SSH_ASKPASS=" + GlobalConfig->pathToGnomeSshAskpass);
            debugMessage(0, i18n("%1 will be used.", QString("gnome-ssh-askpass")));
        } else {
            reportError(i18n("No ssh askpass program found."));
            errorLine = __LINE__;
        }
    }

    if (!errorLine)
    {
        SshProcess = new HelperPtyProcess(this, GlobalConfig->pathToSsh, args, environment,
                                          SLOT(readFromStdout_ssh()),
                                          SLOT(readFromStderr_ssh()),
                                          SLOT(readFromPty_ssh()),
                                          0, 0);
        if (!SshProcess)
        {
            reportError(i18n("Failed to start \"%1\"." , QString("ssh")), QString(), KVpncEnum::info);
            errorLine = __LINE__;
        } else {
            SshPty = SshProcess->pty();
            if (!SshProcess->start()) {
                errorLine = __LINE__;
            }
        }


    }

    if (!errorLine) {
        debugMessage(0, i18n("Trying to connect to server \"%1\" with ...\n" , QString(GlobalConfig->currentProfile->getGateway())) );
    } else {
        errorMessage(i18n("Error at line %1.", errorLine));
    }
    return 0 == errorLine;
}


void SshHandler::vpnStop()
{

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

    //     terminateConnection( SshProcess );
    //     SshProcess = new QProcess(this);
    //  QString proc =  GlobalConfig->pathToKillall;
    //      QStringList args;
    //     args.append( "openvpn" );
    //
    //     connect( DisconnectProcess, SIGNAL( readAllStandardOutput() ), this, SLOT( readFromStdout_disconnect() ) );
    //     connect( DisconnectProcess, SIGNAL( readAllStandardError() ), this, SLOT( readFromStderr_disconnect() ) );
    //
    //  DisconnectProcess->setEnvironment(*env);
    //  DisconnectProcess->start(proc,args);
    //     if ( !DisconnectProcess->waitForStarted() ) {
    //      KMessageBox::sorry( this, i18n( "Failed to start \"%1\"." , QString( "killall ssh" )) );
    //     }
    //         else
    //             {
    //                 sleep(1);
    //             }


    // write ssh.<profile>.down
    QFile downfile(tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".down");
    QTextStream downstream(&downfile);
    if (downfile.open(QIODevice::WriteOnly)) {
        downstream <<  "#!" << GlobalConfig->InterpreterShell << "\n";
        downstream << "# generated by kvpnc. Do not edit it." << "\n";
        /* update dns? */
        if (GlobalConfig->currentProfile->getUseDnsUpdate()) {
            downstream << "# profile: " + GlobalConfig->currentProfile->getName() << "\n\n";
            //       downstream << "chmod u+w  /etc/resolv.conf\n";
            downstream << "if [ -x /sbin/resolvconf ] ; then\n";
            downstream << " dev=$1\n";
            downstream << " if [ -z $dev ] ; then\n";
            if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun")
                downstream << "  dev=\"tun0\"\n";
            else
                downstream << "  dev=\"tap0\"\n";
            downstream << " fi\n";
            downstream << " /sbin/resolvconf -d $dev\n";
            downstream << "else" << "\n";
            downstream << "cat " << tmpPath + "resolv.conf." + GlobalConfig->currentProfile->getName() << " > /etc/resolv.conf\n";
            downstream << "fi" << "\n";
        } else {
            /* dont update dns */
        }

        if (GlobalConfig->currentProfile->getReplaceDefaultRoute()) {
            downstream << GlobalConfig->pathToIp + " route del " + GlobalConfig->currentProfile->getGateway() + "/32 via " << GlobalConfig->OldDefaultGw << " dev " << GlobalConfig->OldDefaultDev << "\n";
            downstream << GlobalConfig->pathToIp << " route add  $(cat " << OldDefaultroute << ")" << "\n";

            debugMessage(3, i18n("Removing extra route: %1 over %2 gw %3" , QString(GlobalConfig->currentProfile->getGateway()), GlobalConfig->OldDefaultDev,  GlobalConfig->OldDefaultGw));

            downstream << GlobalConfig->pathToIp + " route del " + GlobalConfig->currentProfile->getGateway() + "/32 via " << GlobalConfig->OldDefaultGw << " dev " << GlobalConfig->OldDefaultDev << "\n";

        }

        //                     if (GlobalConfig->NewDefaultGw != "0.0.0.0") {
        //                         SshDevice = "";
        // //       if ( !PppDevice.isEmpty() )
        // //        sshev = PppDevice;
        // //       else
        //                         if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun")
        //                             SshDevice = "tun0";
        //                         else
        //                             SshDevice = "tap0";
        //
        //                         if (GlobalConfig->KvpncDebugLevel > 3)
        //                             debugMessage(i18n("Removing extra route: %1 over %2 gw %3" , QString("0.0.0.0"),  GlobalConfig->NewDefaultGw , SshDevice));
        //                         downstream << GlobalConfig->pathToIp + " route del 0.0.0.0 via " << GlobalConfig->NewDefaultGw << " dev " << SshDevice << "\n";
        //                     }

        downfile.close();

        QProcess SshDownProcess(this);
        QString proc = GlobalConfig->InterpreterShell;
        QStringList args;
        args.append(tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".down");
        SshDownProcess.setEnvironment(*env);
        SshDownProcess.start(proc, args);
        if (!SshDownProcess.waitForStarted()) {
            reportError(i18n("Failed to start \"%1\"." , QString("SshDownScript")), QString(), KVpncEnum::info);
        } else {
            debugMessage(1, i18n("\"%1\" started." , QString("SshDownScript")) );
            waitForFinished(&SshDownProcess, 100);

            debugMessage(1, i18n("\"%1\" (%2) finished.", QString("SshDownScript"), tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".down"));

            if (GlobalConfig->currentProfile->getReplaceDefaultRoute())
                debugMessage(1, i18n("Default route was restored."));

            if (GlobalConfig->currentProfile->getUseDnsUpdate() && Utils(GlobalConfig).resolvConfAvailable()) {
                debugMessage(1, i18n("resolvconf restored the old /etc/resolv.conf."));
            } else {
                if (GlobalConfig->currentProfile->getUseDnsUpdate())
                    debugMessage(1, i18n("/etc/resolv.conf was restored."));
            }
        }
    } else {
        errorMessage(i18n("\"%1\" could not be written." , QString(i18n("ssh down file"))));

    }
}

bool SshHandler::getAuthenticationData(bool AuthRetry)
{
    bool askUsernamePass = false;
    bool requestUsername = false;
    bool requestGrouppassword = false;

    if (!GlobalConfig->haveUserData) {
        //   if ( GlobalConfig->currentProfile->getAuthWithUsernameAndPassword() )
        {
            if (GlobalConfig->currentProfile->getAuthWithUsernameAndPassword()) {
                if (GlobalConfig->currentProfile->getUserPassword().isEmpty())
                    askUsernamePass = true;
                else
                    GlobalConfig->TmpPassword = GlobalConfig->currentProfile->getUserPassword();
            }
            if (GlobalConfig->currentProfile->getUserName().isEmpty())
                requestUsername = true;
            else
                GlobalConfig->TmpUsername = GlobalConfig->currentProfile->getUserName();

            if (AuthRetry) {
                askUsernamePass = true;
                requestUsername = true;
            }
        }
    } else {
        debugMessage(4, i18n("User data already collected."));
    }

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

        askUsernamePass = true;
        requestUsername = true;
    }

    if (askUsernamePass || requestUsername) {
        EnterUsernamePasswordDialog dlg(gui, i18n("Enter Account Data"), requestGrouppassword, requestUsername);

        if (GlobalConfig->currentProfile->getAuthWithUsernameAndPassword()) {
            if (GlobalConfig->currentProfile->getSaveUserPassword())
                dlg.PasswordEdit->setText(GlobalConfig->currentProfile->getUserPassword());
        } else {
            dlg.PasswordEdit->hide();
            dlg.LabelPassword->hide();
            dlg.SavePasswordCheckBox->hide();
        }
        dlg.UsernameEdit->setText(GlobalConfig->currentProfile->getUserName());

        if (GlobalConfig->currentProfile->getAuthWithUsernameAndPassword()) {
            if (!dlg.UsernameEdit->text().isEmpty())                  //go straight to pw if username present
                dlg.PasswordEdit->setFocus();
        }
        bool needSave = false;
        if (dlg.exec()) {
            GlobalConfig->TmpUsername = dlg.UsernameEdit->text();
            GlobalConfig->TmpPassword = dlg.PasswordEdit->text();

            if (GlobalConfig->currentProfile->getAuthWithUsernameAndPassword()) {
                if (GlobalConfig->TmpPassword.isEmpty()) {
                    errorMessage(i18n("Password is empty"));
                    return false;
                }
            }
            if (requestUsername && GlobalConfig->TmpUsername.isEmpty()) {
                errorMessage(i18n("Username 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);
                needSave = true;
            }

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

            if (needSave)
                GlobalConfig->saveOptions(true, GlobalConfig->currentProfile->getName());

        } else {
            return false;
            AuthRetry = false;
            debugMessage(0, i18n("Connect canceled because password enter dialog aborted."));
        }

    } else {
        if (!GlobalConfig->currentProfile->getSaveUserPassword() && ! GlobalConfig->currentProfile->getUserPassword().isEmpty()) {
            GlobalConfig->TmpPassword =  GlobalConfig->currentProfile->getUserPassword() ;
        }


        if (!GlobalConfig->currentProfile->getDontSaveUsername() && ! GlobalConfig->currentProfile->getUserName().isEmpty()) {                //go straight to pw if username present
            GlobalConfig->TmpUsername = GlobalConfig->currentProfile->getUserName();
        }
    }

    debugMessage(0, i18n("Some passwords which were needed were obtained from a password dialog."));

    AuthRetry = false;
    GlobalConfig->haveUserData = true;
    return true;
}

QString SshHandler::pingDevice() const {
    return SshDevice;
}

void SshHandler::readFromStdout_ssh()
{
    debugMessage(4, "readFromStdout_ssh");
    if (SshProcess) {
        QStringList msg_list = QString(SshProcess->readAllStandardOutput()).split('\n');
        for (int i = 0; i < msg_list.size(); ++i) {
            QString msg = msg_list.at(i);
            handleOutputFrom_ssh(msg, normal);
        }
    }
}

void SshHandler::readFromStderr_ssh()
{
    debugMessage(4, "readFromStderr_ssh");
    if (SshProcess) {
        QStringList msg_list = QString(SshProcess->readAllStandardError()).split('\n');
        for (int i = 0; i < msg_list.size(); ++i) {
            QString msg = msg_list.at(i);
            handleOutputFrom_ssh(msg, error);
        }
    }
}

void SshHandler::readFromPty_ssh()
{
    //  debugMessage("readFromPty_ssh");
    if (SshPty) {
        QStringList msg_list = QString(SshPty->readAll()).split('\n');
        for (int i = 0; i < msg_list.size(); ++i) {
            QString msg = msg_list.at(i);
            handleOutputFrom_ssh(msg, pty);
        }
    }
}

void SshHandler::handleOutputFrom_ssh(QString msg, MsgType type)
{
    bool ErrorMsg = false;
    QString source;
    unsigned errorLine = 0;
    DisconnectionReason reason = DISCONNECTION_REASON_FATAL_ERROR;
    bool connectSuccess = false;


    if (type == normal) {
        source = "[ssh]";
    } else if (type == error)
        source = "[ssh err]";
    else if (type == pty) {
        source = "[ssh pty]";
    }
    debugMessage(3, source + ": " + msg);


    if (msg.indexOf("ssh_is_up", 0, Qt::CaseInsensitive) > -1) {
        debugMessage(0, i18n("SSH tunnel is now up") );
        connectSuccess = true;
    } else if (msg.indexOf("REMOTE HOST IDENTIFICATION HAS CHANGED!", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        reportError(i18n("Remote host identification has changed.")) ;

    } else if (msg.indexOf("Host key verification failed", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        reportError(i18n("Host key verification failed"));

        errorLine = __LINE__;
    } else if (msg.indexOf("has changed and you have requested strict checking", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        reportError(i18n("Host key for %1 has changed and you have requested strict checking."  , QString(GlobalConfig->TmpGatewayIP)));

        errorLine = __LINE__;
    } else if (msg.indexOf(": No route to host", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        reportError(i18n("No route to host %1"  , QString(GlobalConfig->TmpGatewayIP)));

        errorLine = __LINE__;
    } else if (msg.indexOf("Authentication succeeded", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = false;
        //    KMessageBox::error ( this, i18n ( "Authentication succeeded" ) );
        debugMessage(0, i18n("Authentication succeeded") );
        //    errorLine = __LINE__;
    } else if (msg.indexOf("Remote: Failed to open the tunnel device.", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        reportError(i18n("Remote: Failed to open the tunnel device."));

        errorLine = __LINE__;
    } else if (msg.indexOf("open failed: administratively prohibited: open failed", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        reportError(i18n("Action administratively prohibited"));

        errorLine = __LINE__;
    } else if (msg.indexOf("Connection established.", 0, Qt::CaseInsensitive) > -1) {
        //    KMessageBox::error ( this, i18n ( "Low level connection to host %1 established."  , QString( GlobalConfig->TmpGatewayIP )));
        debugMessage(0, i18n("Low level connection to host %1 established." , QString(GlobalConfig->TmpGatewayIP)) );
    } else if (msg.indexOf("No more authentication methods to try.", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = true;
        reportError(i18n("No more authentication methods to try."));

        errorLine = __LINE__;
    } else if (msg.indexOf("Permission denied", 0, Qt::CaseInsensitive) > -1) {
        connectCounter = 0;
        reportError(i18n("Authentication has failed."));

        errorLine = __LINE__;
        reason = DISCONNECTION_REASON_AUTHENTICATION_FAILED;
    } else if (msg.indexOf("'s password:", 0, Qt::CaseInsensitive) > -1) {
        ErrorMsg = false;
        debugMessage(0, i18n("Password asked, send it..."));
        SshPty->write(GlobalConfig->TmpPassword.toUtf8());
        SshPty->write("\n");
    }



    if (ErrorMsg)
        errorMessage("[ssh error] " + msg);
    else
        debugMessage(2, "[ssh2] " + msg);

    // success
    if (connectSuccess) {
        // TBD: the old code deferred the setFirewallAfterConnect(), executeCommandAfterConnect()
        // addAdditionalNetworkRoutes() and startConnectionStatusCheck() till after the ssh setup.
        // If we need to go back to that, we'll use a virutal callback.
        setStatusConnected(__LINE__);
        connectSuccess = false;

        successMessage(i18n("Connection established."));

        //    debugMessage( QString("connectstring: "+ProcessMsg_connect) );

        SshDevice = gui->pppdDevice();
        if (SshDevice.isEmpty())
        {
            if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun")
                SshDevice = "tun0";
            else
                SshDevice = "tap0";
        }

        // write ssh.<profile>.up
        QFile sshupfile(tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".up");
        QTextStream sshupstream(&sshupfile);
        if (sshupfile.open(QIODevice::WriteOnly)) {
            sshupstream <<  "#!" << GlobalConfig->InterpreterShell << "\n";
            sshupstream << "# generated by kvpnc. Do not edit it." << "\n";
            sshupstream << "# profile: " + GlobalConfig->currentProfile->getName() << "\n\n";
            sshupstream << "cat /etc/resolv.conf > " << tmpPath + "resolv.conf." + GlobalConfig->currentProfile->getName() << "\n";

            NetworkInterface iface(GlobalConfig, kapp);

            /* update dns? */
            if (GlobalConfig->currentProfile->getUseDnsUpdate()) {
                sshupstream << "if [ -x /sbin/resolvconf ] ; then\n";
                sshupstream << " echo > /dev/null" << "\n";
                sshupstream << "else" << "\n";
                sshupstream << " echo \"# generated by kvpnc. Do not edit it.\" > /etc/resolv.conf" << "\n";
                sshupstream << "fi\n";
            } else {
                /* dont update dns */
            }

            sshupstream << "\n";
            if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun")
                sshupstream << GlobalConfig->pathToIfconfig << " " + SshDevice + " " + GlobalConfig->currentProfile->getLocalVirtualIP() + " pointopoint " << GlobalConfig->currentProfile->getRemoteVirtualIP() << " up" << "\n";
            if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tap")
                sshupstream << GlobalConfig->pathToIfconfig << " " + SshDevice + " " + GlobalConfig->currentProfile->getLocalVirtualIP()  << " up" << "\n";

            gui->setTunnelInterfaceIP(iface.getInterfaceIP(SshDevice));

            QString resolvtemp = "";
            bool no_nameserver = true;
            /* update dns? */
            if (GlobalConfig->currentProfile->getUseDnsUpdate()) {
                sshupstream << "if [ -x /sbin/resolvconf ] ; then\n";
                sshupstream << " dev=$1\n";
                sshupstream << " if [ -z $dev ] ; then\n";
                if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun")
                    sshupstream << "  dev=\"tun0\"\n";
                else
                    sshupstream << "  dev=\"tap0\"\n";
                sshupstream << "fi\n";
                if (!TmpDns1.isEmpty() || !TmpDns2.isEmpty()) {
                    no_nameserver = false;
                    sshupstream << "if [ -x /sbin/resolvconf ] ; then\n";
                    if (TmpDns2.isEmpty()) {
                        resolvtemp += "nameserver " + TmpDns1 + "\n";
                    } else {
                        resolvtemp += "nameserver " + TmpDns1 + "\nnameserver " + TmpDns2 + "\n";
                    }

                    sshupstream << "else" << "\n";
                    sshupstream << "  echo >> /etc/resolv.conf\n";
                    sshupstream << "  echo \"# generated by kvpnc. Do not edit it.\" > /etc/resolv.conf" << "\n";
                    sshupstream << "  echo \"# profile: " + GlobalConfig->currentProfile->getName() << "\" >> /etc/resolv.conf" << "\n";
                    sshupstream << "  echo \"nameserver " << TmpDns1 << "\" >> /etc/resolv.conf" << "\n";
                    if (!TmpDns2.isEmpty())
                        sshupstream << "  echo \"nameserver " << TmpDns2 << "\" >> /etc/resolv.conf" << "\n";

                }

                sshupstream << "fi" << "\n";

                sshupstream << "# " << "\n";

                if ((GlobalConfig->currentProfile->getUseDnsServer() && !GlobalConfig->currentProfile->getDnsServer().isEmpty()) || (GlobalConfig->currentProfile->getUseSearchDomainInResolvConf()  && ! !GlobalConfig->currentProfile->getSearchDomainInResolvConf().isEmpty())) {
                    sshupstream << "if [  -x /sbin/resolvconf ] ; then\n";
                    sshupstream << " dev=$1\n";
                    sshupstream << " if [ -z $dev ] ; then\n";
                    if (GlobalConfig->currentProfile->getTunnelDeviceType() == "tun")
                        sshupstream << "  dev=\"tun0\"\n";
                    else
                        sshupstream << "  dev=\"tap0\"\n";
                    sshupstream << " fi\n";

                    if (GlobalConfig->currentProfile->getUseDnsServer() && !GlobalConfig->currentProfile->getDnsServer().isEmpty())
                        resolvtemp += "nameserver " + GlobalConfig->currentProfile->getDnsServer() + "\n";
                    if (GlobalConfig->currentProfile->getUseSearchDomainInResolvConf() && !GlobalConfig->currentProfile->getSearchDomainInResolvConf().isEmpty())
                        resolvtemp += "search " + GlobalConfig->currentProfile->getSearchDomainInResolvConf() + "\n";
                    sshupstream << "else\n";
                    if (GlobalConfig->currentProfile->getUseDnsServer() && !GlobalConfig->currentProfile->getDnsServer().isEmpty()) {
                        sshupstream << "  echo \"nameserver " << GlobalConfig->currentProfile->getDnsServer() + "\" >> /etc/resolv.conf\n";
                        no_nameserver = false;
                    }
                    if (GlobalConfig->currentProfile->getUseSearchDomainInResolvConf() && !GlobalConfig->currentProfile->getSearchDomainInResolvConf().isEmpty())
                        sshupstream << "  echo \"search " << GlobalConfig->currentProfile->getSearchDomainInResolvConf() + "\" >> /etc/resolv.conf\n";
                    sshupstream << "fi\n";
                }


                sshupstream << "if [ -x /sbin/resolvconf ] ; then\n";
                sshupstream << "  echo \"" + resolvtemp + "\" > " + tmpPath + "resolvconf." + GlobalConfig->currentProfile->getName() << "\n";
                if (no_nameserver == true) {
                    sshupstream << "   cat   " + tmpPath + "/resolv.conf.before.kvpnc_" + GlobalConfig->currentProfile->getName() + " | grep nameserver >> " + tmpPath + "/pppd.resolvconf.tmp" + "\n";
                }

                sshupstream << "  cat   " + tmpPath + "resolvconf." + GlobalConfig->currentProfile->getName()+ " | /sbin/resolvconf -a $dev\n";

                /* crissi: -u seems not nessary */
                //sshupstream << " cat   " + tmpPath + "/pppd.resolvconf.tmp | /sbin/resolvconf -u\n";

                if (!GlobalConfig->holdGeneratedScripts)
                    sshupstream << "  rm -f   " + tmpPath + "resolvconf." + GlobalConfig->currentProfile->getName()+"\n";

                if (no_nameserver == true) {
                    sshupstream << "else\n";
                    sshupstream << "  cat " << tmpPath + "/resolv.conf.before.kvpnc_" + GlobalConfig->currentProfile->getName() + " | grep nameserver >> /etc/resolv.conf\n";
                }

                sshupstream << "fi\n";
                //                sshupstream << "chmod u-w  /etc/resolv.conf\n";

            } else {
                /* dont update dns */
            }
            sshupstream << GlobalConfig->pathToIp << " route show | grep default > " << OldDefaultroute << "\n";

            if (GlobalConfig->currentProfile->getReplaceDefaultRoute()) {
                sshupstream << GlobalConfig->pathToIp + " route replace default dev " + SshDevice + "\n";

                debugMessage(3, i18n("Setting extra route: %1 over %2 gw %3"  , QString(GlobalConfig->currentProfile->getGateway()), GlobalConfig->OldDefaultDev, GlobalConfig->OldDefaultGw));

                sshupstream << GlobalConfig->pathToIp + " route add " + GlobalConfig->currentProfile->getGateway() + "/32 via " << GlobalConfig->OldDefaultGw << " dev " << GlobalConfig->OldDefaultDev << "\n";

            }
            //     NetworkInterface iface(GlobalConfig , parent);
            GlobalConfig->NewDefaultGw = iface.getGatewayOfDefaultInterface();

            if (GlobalConfig->NewDefaultGw != "0.0.0.0") {
                debugMessage(3, i18n("Setting extra route: %1 over %2 gw %3"  , QString("0.0.0.0"), SshDevice , GlobalConfig->NewDefaultGw));
                sshupstream << GlobalConfig->pathToIp + " route add 0.0.0.0 via " << GlobalConfig->NewDefaultGw << " dev " << SshDevice << "\n";
            }
            sshupfile.close();
        }


        QProcess SshUpProcess(this);
        QString proc = GlobalConfig->InterpreterShell;
        QStringList args;
        args.append(tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".up");
        SshUpProcess.setEnvironment(*env);
        SshUpProcess.start(proc, args);
        if (!SshUpProcess.waitForStarted()) {
            reportError(i18n("\"%1\" (%2) start failed."  , QString("SshUpScript")  , QString(tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".up")), QString(), KVpncEnum::info);
        } else {
            debugMessage(0, i18n("\"%1\" (%2) started."  , QString("SshUpScript"), QString((tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".up"))));
            waitForFinished(&SshUpProcess, 100);


            debugMessage(0, i18n("\"%1\" (%2) finished."  , QString("SshUpScript"), QString(tmpPath + "ssh." + GlobalConfig->currentProfile->getName() + ".up")) );
        }
        if (GlobalConfig->currentProfile->getReplaceDefaultRoute()) {
            tmpPath = KStandardDirs::locateLocal("data", "kvpnc/");
            QString SshReplaceDefaultRouteScript = tmpPath + "ssh_replace_defaultroute." + GlobalConfig->currentProfile->getName() + ".sh";

            QFile file(SshReplaceDefaultRouteScript);
            QTextStream stream(&file);
            if (file.open(QIODevice::WriteOnly)) {
                stream << "# generated by kvpnc. Do not edit it." << "\n";
                stream << "\n";
                file.close();
                QProcess ReplaceDefaultRouteProcess(this);
                QString proc = GlobalConfig->InterpreterShell;
                QStringList args;
                args.append(SshReplaceDefaultRouteScript);
                ReplaceDefaultRouteProcess.setEnvironment(*env);
                ReplaceDefaultRouteProcess.start(proc, args);
                if (!ReplaceDefaultRouteProcess.waitForStarted()) {
                    reportError(i18n("\"%1\" %2 start failed."  , QString(i18n("ssh replace route process")), QString((tmpPath + "pppd_replace_defaultroute." + GlobalConfig->currentProfile->getName() + ".sh"))), QString(), KVpncEnum::info);
                    //    setStatusDisconnected(__LINE__);
                    //    setStatusDisconnected(__LINE__);
                } else {
                    debugMessage(1, i18n("\"%1\" (%2) started."  , QString(i18n("ssh replace route process")) , QString((tmpPath + "ssh_replace_defaultroute." + GlobalConfig->currentProfile->getName() + ".sh"))) );

                    waitForFinished(&ReplaceDefaultRouteProcess, 100);

                    debugMessage(1, i18n("\"%1\" (%2) finished.", i18n("ssh replace route process"), tmpPath + "ssh_replace_defaultroute." + GlobalConfig->currentProfile->getName() + ".sh") );
                }

            } else {
                errorMessage(i18n("Could not write: \"%1\" (%2)." , QString(i18n("ssh replace route script")), SshReplaceDefaultRouteScript));
            }
        }
    }
    if (errorLine) {
        setStatusDisconnected(errorLine, reason);
    }


}

void SshHandler::sshExited(int, QProcess::ExitStatus)
{

}
