/*****************************************************************************
 * Copyright (C) 2004-2009 Christoph Thielecke <crissi99@gmx.de>             *
 *                                                                           *
 * This program is free software; you can redistribute it and/or modify      *
 * it under the terms of the GNU General Public License as published by      *
 * the Free Software Foundation; either version 2 of the License, or         *
 * (at your option) any later version.                                       *
 *                                                                           *
 * This 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 "toolinfo.h"

#include <QtCore/QFile>
#include <QtCore/QStringList>
#include <QtCore/QTimer>
#include <QtCore/QProcess>
#include <QtCore/QFileInfo>

#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>

#include <cstdlib>
#include <unistd.h>
#include <iostream>

ToolInfo::ToolInfo(const QString &Name)
{
    this->Name = Name;
    this->programsInPath = programsInPath;
    this->found = false;
    TryPath_first = "";
    /*
     if (!PathToExec.isEmpty())
      SearchPathList.append(PathToExec);*/

    Version = i18n("No info");

    env << "LC_ALL=C" << "LANG=C" << "PATH=/usr/local/bin:/usr/local/sbin;/bin:/usr/bin:/usr/sbin:/sbin";

    collectRunning = false;
    collectOpenvpnCapabilitiesRunning = false;
    collectToolInfo();
}

bool ToolInfo::collectToolInfo()
{
    if (programsInPath) {
        addSearchPath("/usr/local/sbin");
        addSearchPath("/usr/sbin");
        addSearchPath("/sbin");
        addSearchPath("/usr/local/bin");
        addSearchPath("/usr/bin");
        addSearchPath("/bin");

        addSearchPath(QString(QString(getenv("HOME")) + "/bin"));
    }
    if (TryPath_first.isEmpty())
        TryPath_first = Name;

    bool success = false;

    QList<QString>::iterator it;
    if (QFile(TryPath_first).exists() && QFileInfo(TryPath_first).isFile()) {
        found = true;
        PathToExec = TryPath_first;
    } else {
        for (it = SearchPathList.begin(); it != SearchPathList.end(); ++it) {
            QString TryPath = *it + "/" + Name;
            if (!TryPath.isEmpty() && QFile(TryPath).exists() && QFileInfo(TryPath).isFile()) {
                found = true;
                PathToExec = TryPath;
                break;
            }
        }
    }

    if (found) {
        bool run = true;

        Version = "";
        QString proc = "";
        QStringList args;
        //FIXME how it could be better?
        proc =  PathToExec;
        if (Name == "vpnc")
            args.append("--version");
        else if (Name == "vpnclient") ;
        else if (Name == "ipsec")
            args.append("--version");
        else if (Name == "racoon") {
            proc = QString(PathToExec.left(PathToExec.length() - 6) + "setkey");
            args.append("-V");
        } else if (Name == "setkey")
            args.append("-V");
        else if (Name == "openvpn")
            args.append("--version");
        else if (Name == "openssl")
            args.append("version");
        else if (Name == "pppd")
            args.append("--version");
        else if (Name == "iptables")
            args.append("-V");
        else if (Name == "kill") {
            //    run=false;
            //    success=true;
            args.append("-V");
        } else if (Name == "killall")
            args.append("-V");
        else if (Name == "ping")
            args.append("-V");
        else if (Name == "ip")
            args.append("-V");
        else if (Name == "ifconfig")
            args.append("-V");
        else if (Name == "route")
            args.append("-V");
        else if (Name == "pptp")
            ;
        else if (Name == "l2tpd")
            args.append("-D");
        else if (Name == "xl2tpd")
            args.append("-v");
        else if (Name == "openl2tpd") {
            args.append("-c");
            args.append("-");
            args.append("-f");
        } else if (Name == "pkcs11-tool")
            args.append("-I");
        else if (Name == "vtund")
            args.append("-h");
        else if (Name == "cisco_cert_mgr");
        else if (Name == "tail")
            args.append("--version");
        else if (Name == "ssh")
            args.append("-V");
        else if (Name == "ksshaskpass")
            args.append("--version");
		else if (Name =="gnome-ssh-askpass") {
//    args.append( "--version");
		}
		else if (Name == "netstat")
			args.append("--version");
		else {
            run = false;
            success = false;
        }

        if (PathToExec.isEmpty())
            run = false;

        collectRunning = false;

        if (run) {
//    std::cout << "DEBUG ==> CollectToolInfoProcess: "<< qPrintable(proc) << ", args: " << qPrintable(QString(args.join(" "))) << std::endl;
            CollectToolInfoProcess = new QProcess;
//    CollectToolInfoProcess->setEnvironment(env);
            //   CollectToolInfoProcess->setOutputChannelMode(KProcess::MergedChannels);
//      CollectToolInfoProcess->setPtyChannels(KPtyProcess::AllChannels);
//    CollectToolInfoProcess->setReadChannel(KProcess::StandardOutput);
            connect(CollectToolInfoProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOutCollectToolInfo()));
            connect(CollectToolInfoProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStdErrCollectToolInfo()));
            //connect(CollectToolInfoProcess, SIGNAL(finished ( int, QProcess::ExitStatus )), this, SLOT(processFinished( int, QProcess::ExitStatus )));
//    CollectToolInfoProcess->setProgram(proc, args);
//    CollectToolInfoProcess->start();
            CollectToolInfoProcess->setEnvironment(env);
            CollectToolInfoProcess->start(proc, args);
            if (!CollectToolInfoProcess->waitForStarted()) {
//     std::cout << "DEBUG ==> CollectToolInfoProcess not started!" << std::endl;
                //delete CollectToolInfoProcess;
                collectRunning = false;
                success = false;
            } else {
//     std::cout << "DEBUG ==> CollectToolInfoProcess started!" << std::endl;
                collectRunning = true;

//     int WaitCount=0;
//     while (CollectToolInfoProcess->state() == QProcess::Running) {
//      if ((Name == "l2tpd" || Name == "pkcs11-tool" || Name == "cisco_cert_mgr"  || Name == "vpnclient") && WaitCount > 500) {
//       WaitCount+= 100;
//       CollectToolInfoProcess->kill();
//      }
//      usleep(100);
//     }
                CollectToolInfoProcess->waitForFinished();
                //     std::cout << "DEBUG ==> CollectToolInfoProcess finished!" << std::endl;
//     std::cout << "DEBUG ==> CollectToolInfoProcess Version: \"" << qPrintable(Version) << "\" " << std::endl;
                //KMessageBox::information(0,QString("Name: "+Name+", Path: "+PathToExec+", Version: "+Version),"aaa");
                disconnect(CollectToolInfoProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOutCollectToolInfo()));
                disconnect(CollectToolInfoProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStdErrCollectToolInfo()));
                delete CollectToolInfoProcess;
                success = true;
            }
        }



        if (Name == "openvpn") {
            getOpenvpnCapabilities();
        }
    }
    return success;
}

void ToolInfo::readStdOutCollectToolInfo()
{
    //  std::cout << "DEBUG ==> CollectToolInfoProcess readyReadStandardOutput!" << std::endl;
    QStringList msg_list = QString(CollectToolInfoProcess->readAllStandardOutput()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
//   std::cout << qPrintable(QString("DEBUG ==> ")) << qPrintable(msg) << std::endl;
        //FIXME how it could be better?
        if (Name == "vpnc") {
            if (msg.indexOf("version", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.simplified().section(' ', 2, 2);
            }
            if ( msg.indexOf( "Built without openssl (certificate) support", 0, Qt::CaseInsensitive ) > -1 )
			{
				// 				Capabilities+=i18n("no openssl support")+";";
			}
			else if ( msg.indexOf( "Built with openssl (certificate) support", 0, Qt::CaseInsensitive ) > -1 )
			{
				Capabilities=i18n("openssl (certificate) support")+";";	
			}
			
        } else if (Name == "vpnclient" || Name == "cisco_cert_mgr") {
            if (msg.indexOf("Cisco Systems VPN Client", 0, Qt::CaseInsensitive) > -1)
                Version = msg.section(' ', 5, 6); // "Cisco Systems VPN Client Version 4.8.00 (0490)"
        } else if (Name == "ipsec") {
            if (msg.indexOf("wan", 0, Qt::CaseInsensitive) > -1) {
//     if ( msg.indexOf( "openswan", 0, false ) > -1 )
//      Version = msg.section(' ',2,2);
//     else
                Version = msg.section(' ', 1, 2); // "Openswan Ux.x.x/kx.x.x"
                if (msg.section(' ', 1, 2).contains('/'))
                    Version = msg.section(' ', 1, 2).section('/', 0, 0); // "Openswan Ux.x.x"
                else
                    Version = msg.section(' ', 1, 2);
            }
        } else if (Name == "racoon" || Name == "racoonctl") {

            if (msg.indexOf("ipsec-tools", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 3, 3);
            }
        } else if (Name == "setkey") {
            if (msg.indexOf("ipsec-tools", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 3, 3);
            }
        } else if (Name == "openvpn") {
            if (msg.indexOf("built", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 1, 1);
            }
        } else if (Name == "openssl") {
            if (msg.indexOf("OpenSSL", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 1, 1);
            }
        } else if (Name == "pppd") {
            if (msg.indexOf("version", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2);
            }
        } else if (Name == "iptables") {
            if (msg.indexOf("iptables", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 1, 1);
            }
        } else if (Name == "ping") {
            if (msg.indexOf("ping", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2);
            }
        } else if (Name == "ip") {
            if (msg.indexOf("ip", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2);
            }
        } else if (Name == "kill") {
            if (msg.indexOf("kill", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 3, 3).section(')', 0, 0);
            }
        } else if (Name == "pkcs11-tool") {
            if (msg.indexOf("version", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2);
            } else if (msg.indexOf("Error: can't open /var/run/openct/status", 0, Qt::CaseInsensitive) > -1) {
                CollectToolInfoProcess->kill();
            }
        } else if (Name == "xl2tpd") {
            if (msg.indexOf("version:", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 3, 3).trimmed();
            }
        } else if (Name == "openl2tpd") {
            if (msg.indexOf("OpenL2TP V", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 1, 1).remove(',').remove('V');
                CollectToolInfoProcess->kill();
            }
        } else if (Name == "vtund") {
            if (msg.indexOf("VTun ver", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 3).trimmed();
            }
        } else if (Name == "tail") {
            if (msg.indexOf("tail ", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 3, 3).trimmed();
            }
        } else if (Name == "ksshaskpass") {
            if (msg.indexOf("Ksshaskpass:", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 1, 1).trimmed();
            }
        } else if (Name == "gnome-ssh-askpass") {
//    if ( msg.find( "askpass", 0, false ) > -1 )
            {
//     Version = msg.section(' ',3,3).trimmed();
                Version = i18n("unknown");
            }
		} else if (Name == "netstat") {
			if (msg.indexOf("netstat ", 0, Qt::CaseInsensitive) > -1) {
				Version = msg.section(' ', 1, 1).trimmed();
			}
		} else {
//             KMessageBox::information(0, QString("Name: " + Name + ", Path: " + PathToExec + ", Version: " + Version + ", err: " + msg), "aaa");
        }
    }
    collectRunning = false;
}

void ToolInfo::readStdErrCollectToolInfo()
{
    //  std::cout << "DEBUG ==> CollectToolInfoProcess readyReadStandardError!" << std::endl;
    QStringList msg_list = QString(CollectToolInfoProcess->readAllStandardError()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
//   std::cerr << qPrintable(QString("DEBUG ERR ==> ")) << qPrintable(msg) << std::endl;
        if (Name == "pppd") {
            if (msg.indexOf("version", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2);
            }
        } else if (Name == "killall") {
            if (msg.indexOf("killall", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2);
            }
        } else if (Name == "ifconfig") {
            //KMessageBox::information(0,QString("Name: "+Name+", Path: "+PathToExec+", Version: "+Version),"aaa");
            if (msg.indexOf("ifconfig", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 1, 1);
            }
        } else if (Name == "route") {
            if (msg.indexOf("route", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 1, 1);
            }
        } else if (Name == "pptp") {
            if (msg.indexOf("pptp version", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2).section(')', 0, 0);
            }
        } else if (Name == "l2tpd") {
            if (msg.indexOf("l2tpd", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2).section(')', 0, 0);
            }
        } else if (Name == "pkcs11-tool") {
            if (msg.indexOf("version", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 2, 2);
            } else if (msg.indexOf("Error: can't open /var/run/openct/status", 0, Qt::CaseInsensitive) > -1) {
                CollectToolInfoProcess->kill();
            }
        } else if (Name == "ssh") {
            if (msg.indexOf("OpenSSH", 0, Qt::CaseInsensitive) > -1) {
                Version = msg.section(' ', 0, 0).section('_', 1, 1).trimmed();
            }
        } else {
//    KMessageBox::information(0,QString("Name: "+Name+", Path: "+PathToExec+", Version: "+Version+", err: "+msg),"aaa");
        }
    }
}

void ToolInfo::readStdOutCollectOpenvpnCapabilies()
{
    QStringList msg_list = QString(CollectOpenvpnCapabilitiesProcess->readAllStandardOutput()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
        if (msg.indexOf("PKCS#11 Options:", 0, Qt::CaseInsensitive) > -1)
            Capabilities += i18n("pkcs11 support") + ";";
    }
    collectOpenvpnCapabilitiesRunning = false;
}

void ToolInfo::readStdErrCollectOpenvpnCapabilies()
{
    // FIXME: is it still needed ?
    QStringList msg_list = QString(CollectOpenvpnCapabilitiesProcess->readAllStandardError()).split('\n');
    for (int i = 0; i < msg_list.size(); ++i) {
        QString msg = msg_list.at(i);
    }
}

void ToolInfo::collectOpenvpnCapabilitiesProcessFinished(int, QProcess::ExitStatus)
{
    collectRunning = false;
    collectOpenvpnCapabilitiesRunning = false;
}

void ToolInfo::addSearchPath(const QString& path)
{
    if (!path.isEmpty())
        SearchPathList.insert(SearchPathList.end(), QString(path));
    else
        return;
}

void ToolInfo::removeSearchPath(const QString& path)
{
    if (!path.isEmpty())
        SearchPathList.removeAll(QString(path));
    else
        return;
}

void ToolInfo::getOpenvpnCapabilities()
{

    if (Name == "openvpn" && !PathToExec.isEmpty()) {

        CollectOpenvpnCapabilitiesProcess = new QProcess(this);
        connect(CollectOpenvpnCapabilitiesProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOutCollectOpenvpnCapabilies()));
        connect(CollectOpenvpnCapabilitiesProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStdErrCollectOpenvpnCapabilies()));
        connect(CollectOpenvpnCapabilitiesProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(collectOpenvpnCapabilitiesProcessFinished(int, QProcess::ExitStatus)));

        //FIXME how it could be better?
        QString proc = PathToExec;
        QStringList args;

        collectOpenvpnCapabilitiesRunning = false;

        CollectOpenvpnCapabilitiesProcess->start(proc, args);
        if (!CollectToolInfoProcess->waitForStarted()) {
            //delete CollectToolInfoProcess;
            collectOpenvpnCapabilitiesRunning = false;
        } else {
            collectOpenvpnCapabilitiesRunning = true;
            CollectOpenvpnCapabilitiesProcess->waitForFinished();


        }
        disconnect(CollectOpenvpnCapabilitiesProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOutCollectOpenvpnCapabilies()));
        disconnect(CollectOpenvpnCapabilitiesProcess, SIGNAL(readyReadStandardError()), this, SLOT(readStdErrCollectOpenvpnCapabilies()));
        //   delete CollectOpenvpnCapabilitiesProcess;
    }
}

#include "toolinfo.moc"
