/*
   
        (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 Steet, 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.h>
#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kprocess.h>
#include <qregexp.h>
#include <qstringlist.h>
#include <qlineedit.h>
#include <qcheckbox.h>


KDialup::KDialup(QObject * parent, const char *name) :QObject(parent,name)
{
    m_pppdPath = getPath("pppd");
    if (m_pppdPath.isEmpty())
        kdDebug() << 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
    KProcess *tailProcess = new KProcess();
    *tailProcess << "tail" << "-f" << "-n1" << "/var/log/syslog";

    connect (tailProcess, SIGNAL(receivedStdout(KProcess *, char *, int)),
             this, SLOT(pppdStatus(KProcess *, char *, int)));
    connect (tailProcess, SIGNAL(receivedStderr(KProcess *, char *, int)),
             this, SLOT(pppdStatus(KProcess *, char *, int)));
    tailProcess->start(KProcess::NotifyOnExit, KProcess::Stdout);
    
    //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
    KProcess *connectProcess = new KProcess();
    QString network = "kwlan/" + m_network;
    *connectProcess << m_pppdPath << "call" << network;
    connectProcess->start();
    //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) kdDebug() << "Disconnecting " << network << endl;
    // 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) kdDebug() << "Now starting script before disconnect << endl";
        KDialupConfigDlg *dlg = new KDialupConfigDlg();
        dlg->init(network);
        QString script = dlg->getData()->getData()->scriptBeforeDisconnect;
        bool scriptStartRoot = dlg->getData()->getData()->scriptBeforeDisconnectRoot;
        delete dlg;
        if(!scriptStartRoot)
        {
            KProcess *proc = new KProcess;
            *proc << script;
            proc->start();
        }
        else {
            KwlanSuProcess *proc = new KwlanSuProcess();
            *proc << script;
            proc->setDescription( i18n("start script before disconnect"));
            proc->start();
        }
        m_connected = FALSE;
    }
    KProcess*killProcess = new KProcess;
    // 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(KProcess *)), this, SLOT(slotProcessExited(KProcess *)));
    killProcess->start();
    m_connected = FALSE;
}

void KDialup::pppdStatus(KProcess *proc, char *buffer, int buflen)
{
    
    QString output = QString::fromLatin1(buffer, buflen);
    QStringList events = QStringList::split( "\n", output);
    QStringList::iterator it;
    for ( it = events.begin(); it != events.end(); ++it )
    {
        if ((*it).find("chat")!=-1)
        {
            //it's a chat related syslog entry
            emit logEvent(*it);
        }
        if ((*it).find("pppd")!=-1)
        {
        //it's a pppd related syslog entry
        //check which ppp interface is used
            QRegExp regExp( "Using interface \"?([^\"]*)\"?" );
            if ( regExp.search( *it ) > -1 )
            {
                m_pppInterface = regExp.cap( 1 );
            }
        //kdDebug() <<"pppdStatus: " << output << endl;
            emit logEvent(*it);
        }
        if ((*it).find("local  IP address")!=-1)
        {
            if (m_pppInterface.isEmpty()) 
            {
                kdDebug() << "No  ppp interface found!" << endl;
                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);
                
                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)
                {
                    KProcess *proc = new KProcess;
                    *proc << script;
                    proc->start();
                }
                else {
                    KwlanSuProcess *proc = new KwlanSuProcess();
                    *proc << script;
                    proc->setDescription( i18n("start script after connect"));
                    proc->start();
                }

            }
            else kdDebug() << "Interface or Traywin are already created!" << endl;
            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(KProcess *proc)
{
    if (proc->exitStatus() != 0)
    {
        QString command;
        QValueList<QCString> args = proc->args();
        QValueList<QCString>::Iterator it  = args.begin();
        while (it != args.end())
        {
            command += " " +*it;
            it++;
        }
        KMessageBox::sorry(0,QString(i18n("Failed to execute process:\n%1").arg(command)));
    }
}
