/*
   
        (c) 2006 by Thomas Michel <tom.michel@arcor.de>

        Kwlan is free software; you can redistribute it and/or modify
        it under the terms of the GNU Library General Public License as
        published by the Free Software Foundation; either version 2 of
        the License, or (at your option) any later version.

        Kwlan 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 Library General Public License for more details.

        You should have received a copy of the GNU Library General Public License
        along with this library; see the file COPYING.LIB.  If not, write to
        the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
        Boston, MA 02110-1301, USA.
*/

#include "kdialup.h"
#include "wlanlib.h"
#include "kwlansuprocess.h"
#include "kdialupstatusdlg.h"
#include "kwlaninterface.h"
#include "kwlantraywin.h"
#include "dialup.h"
#include "dialupclass.h"
#include "globals.h"
#include "kdialupconfigdlg.h"
#include "kdialupconnectdlg.h"

#include <QString>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <k3process.h>
#include <QRegExp>
#include <QStringList>
#include <QCheckBox>
#include <QList>
#include <QByteArray>


KDialup::KDialup(QObject * parent, const char *name) :QObject(parent)
{
    //if (parent) parent->setName(name);
    m_pppdPath = getPath("pppd");
    if (m_pppdPath.isEmpty())
        kDebug() << i18n("pppd not found. Dialup networking will not work.");
    m_pppInterface = "";
    m_traywin = 0L;
    m_interface = 0L;
    m_connected = FALSE;
    m_connecting = FALSE;
}


KDialup::~KDialup()
{
    if (m_traywin) delete (m_traywin);
    if (m_interface) delete (m_interface);
    //m_interface = 0L;
    
}

void KDialup::connectNetwork( QString network)
{
    if (m_connecting ||m_connected) return;
    m_connecting = TRUE;
    m_network = network;
    if (m_pppdPath.isEmpty()) return;
    // Ask fro username / password
    dialupClass *dialup = new dialupClass();
    connect(dialup,SIGNAL(dataWritten()),this,SLOT(slotConnect()));
    dialup->readData( network);
    KDialupConnectDlg *connectDlg = new KDialupConnectDlg();
    connectDlg->leUser->setText(dialup->getData()->user);
    connectDlg->lePassword->setText(dialup->getData()->password);
    connectDlg->cbSavePassword->setChecked(dialup->getData()->storepassword);
    int ret = connectDlg->exec();
    if (ret != QDialog::Accepted) return;
    // check for password remember option
    m_storePassword = connectDlg->cbSavePassword->isChecked();
    dialup->getData()->user = connectDlg->leUser->text();
    dialup->getData()->password = connectDlg->lePassword->text();
    
    // temporarily store password to allow connection to be made 
    // other option would be to pass it to pppd but than it can be seen using ps -ef
    dialup->getData()->storepassword = TRUE;
    dialup->writeData(network);
}

void KDialup::slotConnect()
{

    //TODO: check if connection is already active
    // start tail process to check connection process
    kDebug() << "Connection...";
    K3Process *tailProcess = new K3Process();
    *tailProcess << "tail" << "-f" << "-n1" << "/var/log/syslog";

    connect (tailProcess, SIGNAL(receivedStdout(K3Process *, char *, int)),
             this, SLOT(pppdStatus(K3Process *, char *, int)));
    connect (tailProcess, SIGNAL(receivedStderr(K3Process *, char *, int)),
             this, SLOT(pppdStatus(K3Process *, char *, int)));
    if(!tailProcess->start(K3Process::NotifyOnExit, K3Process::Stdout))
	    delete tailProcess;
    
    //create Log window to display connection process
    KDialupStatusDlg *log = new KDialupStatusDlg();
    log->init(m_network,tailProcess);
    connect (this, SIGNAL(logEvent(QString)), log, SLOT(addEvent(QString)));
    connect (log, SIGNAL(disconnectNetwork(QString)), this, SLOT(disconnectNetwork(QString)));
    connect (this, SIGNAL(connectionEstablished()), log, SLOT(close()));

    // now start connection
    K3Process *connectProcess = new K3Process();
    QString network = "kwlan/" + m_network;
    *connectProcess << m_pppdPath << "call" << network;
    if(!connectProcess->start())
	 delete connectProcess;
    //show the log window
    log->show();
    log->exec();
    // check for password remember option
    dialupClass *dialup = new dialupClass();
    dialup->readData( m_network);
    dialup->getData()->storepassword = m_storePassword;
    dialup->writeData( m_network);
}

void KDialup::disconnectNetwork(QString network)
{

    if (debugOutput) kDebug() << "Disconnecting " << network;
    // find out whether we have to start a script first
    // to avoid double coidng use a kdialupconfigdlg class
    // This is upgly and should be change to seperate the dialog from the data into
    // tow classes so that we can use the data class here
    if (m_connected)
    {
        if (debugOutput) kDebug() << "Now starting script before disconnect";
        KDialupConfigDlg *dlg = new KDialupConfigDlg();
        dlg->init(network);
        QString script = dlg->getData()->getData()->scriptBeforeDisconnect;
        bool scriptStartRoot = dlg->getData()->getData()->scriptBeforeDisconnectRoot;
        delete dlg;
        if(!scriptStartRoot)
        {
            K3Process *proc = new K3Process;
            *proc << script;
            proc->start();
        }
        else {
            KwlanSuProcess *proc = new KwlanSuProcess();
            *proc << script;
            proc->setDescription( i18n("start script before disconnect"));
            proc->start();
        }
        m_connected = FALSE;
    }
    K3Process*killProcess = new K3Process;
    // use ps to find out all ppppd pids
    //This line will give us the pid of a corresponding pppd process and kill it
    network = "kwlan\\/"+network;
    QString killString = QString("kill -9 $(ps -o pid,cmd axw | awk \"/^ *[0-9]* *(\\/usr\\/sbin\\/)?pppd call %1( |\\$)/  {print \\$1}\")").arg(network);
    *killProcess << "bash" << "-c" << killString;
    connect (killProcess, SIGNAL(processExited(K3Process *)), this, SLOT(slotProcessExited(K3Process *)));
    killProcess->start();
    m_connected = FALSE;
}

void KDialup::pppdStatus(K3Process *proc, char *buffer, int buflen)
{
    
    QString output = QString::fromLatin1(buffer, buflen);
    QStringList events = output.split( "\n");
    QStringList::iterator it;
    for ( it = events.begin(); it != events.end(); ++it )
    {
        if ((*it).indexOf("chat")!=-1)
        {
            //it's a chat related syslog entry
            emit logEvent(*it);
        }
        if ((*it).indexOf("pppd")!=-1)
        {
        //it's a pppd related syslog entry
        //check which ppp interface is used
            QRegExp regExp( "Using interface \"?([^\"]*)\"?" );
            if ( regExp.indexIn( *it ) > -1 )
            {
                m_pppInterface = regExp.cap( 1 );
            }
        //kDebug() <<"pppdStatus: " << output;
            emit logEvent(*it);
        }
        if ((*it).indexOf("local  IP address")!=-1)
        {
            if (m_pppInterface.isEmpty()) 
            {
                kDebug() << "No  ppp interface found!";
                return;
            }
        //kill tail process and close connection progress window
        // create a new kwlaninterface for monitoring
            if (!m_interface && !m_traywin)
            {
                m_interface = new KwlanInterface(NULL);
                m_interface->setType(KwlanInterface::PPP);
                m_interface->init(m_pppInterface,0);
                
                m_traywin = new KwlanTrayWin();
                m_traywin->setInterface(m_interface);
                m_traywin->setInterfaceName(m_pppInterface);
                m_traywin->setProfile(m_network);
                //connect(m_interface, SIGNAL(connectionStatusChanged( bool )),m_traywin, SLOT(setConnectionStatus(bool)));
                connect (m_interface, SIGNAL(interfaceGone()), this, SLOT (close( )));
                connect (m_traywin, SIGNAL(interfaceEnable(bool)), this, SLOT (interfaceEnable( bool)));
                
                m_traywin->show();
                m_connected = TRUE;
                m_connecting = FALSE;
                emit connectionEstablished();
                
    // find out whether we have to start a script after connect
    // to avoid double coidng use a kdialupconfigdlg class
    // This is upgly and should be change to seperate the dialog from the data into
    // tow classes so that we can use the data class here
                KDialupConfigDlg *dlg = new KDialupConfigDlg();
                dlg->init(m_network);
                QString script = dlg->getData()->getData()->scriptAfterConnect;
                bool scriptStartRoot = dlg->getData()->getData()->scriptAfterConnectRoot;
                delete dlg;
                
                if(!scriptStartRoot)
                {
                    K3Process *proc = new K3Process;
                    *proc << script;
                    proc->start();
                }
                else {
                    KwlanSuProcess *proc = new KwlanSuProcess();
                    *proc << script;
                    proc->setDescription( i18n("start script after connect"));
                    proc->start();
                }

            }
            else kDebug() << "Interface or Traywin are already created!";
            proc->kill();
        } 
        
    }

}

void KDialup::interfaceEnable(bool enable)
{
    if (enable) return;
    disconnectNetwork(m_network);
}

void KDialup::close()
{
    //disconnect(m_interface, SIGNAL(connectionStatusChanged( bool )),m_traywin, SLOT(setConnectionStatus(bool)));
    delete (this);
}

void KDialup::slotProcessExited(K3Process *proc)
{
    if (proc->exitStatus() != 0)
    {
        QString command;
        QList<QByteArray> args = proc->args();
        QList<QByteArray>::Iterator it  = args.begin();
        while (it != args.end())
        {
            command += " " +*it;
            it++;
        }
        KMessageBox::sorry(0,i18n("Failed to execute process:\n%1",command));
    }
}

#include "kdialup.moc"
                  
