/***************************************************************************
 *   Copyright (C) 2005 by Pawel Nawrocki                                  *
 *   pnawrocki@interia.pl                                                  *
 *                                                                         *
 *   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 program 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 program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/
#include "wlassistant.h"
#include "netlistviewitem.h"
#include "waconfig.h"
#include "watools.h"
#include "ui_netparamswizard.h"
#include "ui_netparamsedit.h"

#include <iostream>
#include <linux/version.h> //provides LINUX_VERSION* macros

#include <tqregexp.h>
#include <tqlabel.h>
#include <tqprocess.h>
#include <tqcursor.h>
#include <tqeventloop.h>
#include <tqtimer.h>
#include <tqcheckbox.h>
#include <tqspinbox.h>
#include <tqwidgetstack.h>
#include <tqtooltip.h>

#include <kpushbutton.h>
#include <kcombobox.h>
#include <tdelistview.h>
#include <tdeapplication.h>
#include <kiconloader.h>
#include <tdemessagebox.h>
#include <tdepopupmenu.h>
#include <tdelocale.h>
#include <tdestandarddirs.h>

WirelessAssistant::WirelessAssistant(TQWidget* parent, const char* name, bool modal, WFlags fl)
                : mainWindow(parent,name, modal,fl)
{
        buttonScan->setIconSet( SmallIconSet("reload") );
        buttonConnect->setIconSet( SmallIconSet("connect_creating") );
        buttonOptions->setIconSet( SmallIconSet("configure") );
        buttonClose->setIconSet( SmallIconSet("window-close") );

        netList->setAllColumnsShowFocus(1);
        netList->setItemMargin(8);
        frameDevice->hide();

        /// Network List Widget
        connect( buttonScan, TQ_SIGNAL(clicked()),
                 this, TQ_SLOT(netScan()) );

        connect( buttonConnect, TQ_SIGNAL(clicked()),
                 this, TQ_SLOT(itemAction()) );

        connect( buttonClose, TQ_SIGNAL(clicked()),
                 this, TQ_SLOT(close()) );

        connect( devCombo, TQ_SIGNAL(activated( const TQString & )),
                 this, TQ_SLOT(setDev( const TQString & )) );

        connect( netList, TQ_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint&, int )),
                 TQ_SLOT(showItemContextMenu( TQListViewItem*, const TQPoint&, int )) );

        /// Settings Widget
        connect( buttonOptions, TQ_SIGNAL(toggled(bool)),
                 this, TQ_SLOT(togglePage(bool)) );

        connect( buttonEnableAllMessages, TQ_SIGNAL(clicked()),
                 this, TQ_SLOT(enableAllMessages()) );

        /// Global KDE Options
        connect( tdeApp, TQ_SIGNAL(settingsChanged(int)),
                 this, TQ_SLOT(updateConfiguration(int)) );

        setMouseBehaviour();

        TQTimer::singleShot(10, this, TQ_SLOT(init()) ); //WAIT FOR THE UI TO BE READY BEFORE FURTHER SETUP (msec)
}

WirelessAssistant::~WirelessAssistant()
{}

/*$SPECIALIZATION$*/


void WirelessAssistant::init()
{
        statusLabel->setText(i18n("Initializing..."));
        statusLabel->repaint();

        ////////////////////////////////////////
        ///// CHECK FOR SYSFS (KERNEL 2.6) /////
        if ( !TQFile::exists("/sys") ) {
                std::cout << "Sysfs not present. Exiting." << std::endl;
                KMessageBox::error( 0, i18n("Kernel 2.6 or later not present.\nWireless Assistant will now quit.") );
                close();
                return;
        }

        /////////////////////////////////////////////////////
        ///// LOAD CONFIG FILE INCL. ALL NET PARAMETERS /////
        WAConfig::self()->setCurrentGroup("Global Options");
        WAConfig::self()->addItemBool("Auto Quit", autoQuit);
	WAConfig::self()->addItemBool("Auto Reconnect", autoReconnect);
	WAConfig::self()->addItemBool("Auto Connect", autoConnect);
	WAConfig::self()->addItemInt("Delay Before Scanning", DelayBeforeScanning);
	WAConfig::self()->addItemBool("Group APs", groupAPs);
        WAConfig::self()->addItemInt("DHCP Client Timeout", DhcpTimeout);
        WAConfig::self()->addItemString("Interface", NetParams.iface);

        WAConfig::self()->setCurrentGroup("Paths");
        // Commented out cos no longer needed. Paths are detected when necessary.
        /*WAConfig::self()->addItemString("DHCP Info (dhcpcd)", dhcpcdInfoPath);
        WAConfig::self()->addItemString("DHCP PID File (dhcpcd)", dhcpcdPidPath);
        WAConfig::self()->addItemString("DHCP Info (dhclient)", dhclientInfoPath);
        WAConfig::self()->addItemString("DHCP PID File (dhclient)", dhclientPidPath);*/

        WAConfig::self()->setCurrentGroup("Network Parameters");
        WAConfig::self()->addItemStringList("NetParamsList", NetParamsList );
        WAConfig::self()->readConfig();
	checkAutoQuit->setChecked(autoQuit);
	checkAutoReconnect->setChecked(autoReconnect);
	checkAutoConnect->setChecked(autoConnect);
	checkGroupAPs->setChecked(groupAPs);
        if (!DelayBeforeScanning)
                DelayBeforeScanning = spinDelayBeforeScanning->value();
        else
                spinDelayBeforeScanning->setValue(DelayBeforeScanning);
        if (!DhcpTimeout)
                DhcpTimeout = spinDhcpTimeout->value();
        else
                spinDhcpTimeout->setValue(DhcpTimeout);

        std::cout << "Loaded application options." << std::endl;

        ///////////////////////////////////
        ///// DETECT WIRELESS DEVICES /////
        TQStringList devList = interfaceList();
        if ( devList.count()==0 ) {
                std::cout << "No wireless interfaces found. Exiting." << std::endl;
                KMessageBox::error(0, i18n("No usable wireless devices found.\nWireless Assistant will now quit."));
                close();
                return;
        }
        std::cout << "Wireless interface(s): " << devList.join(", ").ascii() << std::endl;
        devCombo->insertStringList(devList);

        if (devCombo->count() > 1) { //check if last used (saved) interface is available (only if more that 1 interface present).
                for (int i=0; i<devCombo->count(); i++) {
                        if ( devCombo->text(i)==NetParams.iface ) { //select matching interface.
                                devCombo->setCurrentItem( i );
                                break;
                        }
                }
                frameDevice->show(); //only if more than 1 wireless device.
        }
        NetParams.iface = devCombo->currentText();	// set interface name
        WATools::setInterface( NetParams.iface.ascii() );	// set fallback interface for WATools

        //////////////////////////////////
        ///// CHECK FILE PERMISSIONS /////
        if (!TQFileInfo("/etc/resolv.conf").isWritable()) {
                std::cout << "warning: /etc/resolv.conf not writable" << std::endl;
                KMessageBox::information(0, i18n("<qt><p>You might have insufficient permissions for Wireless Assistant to function properly.</p><p>Did you run it using '<tt>sudo</tt>'?</p></qt>") );
        }
        std::cout << "Permissions checked." << std::endl;

	//////////////////////////////////
	///// INITIALIZE COMMANDS
	Commands.init();

        ///////////////////////////////////////
        ///// INITIALIZE GLOBAL VARIABLES /////
	wpaAvailable = ( !( Commands.wpa_supplicant.isEmpty() || Commands.wpa_cli.isEmpty() ) );
        connectedItem = 0;
        timerGui = new TQTimer();
        timerConnectionCheck = new TQTimer();
        connect( timerGui, TQ_SIGNAL(timeout()), TQ_SLOT(updateConnectedItem()) );
        connect( timerConnectionCheck, TQ_SIGNAL(timeout()), TQ_SLOT(checkConnectionStatus()) );

        ////////////////////////
        ///// DETECT & SET PATHS /////
        if (!Commands.allFound) {	//all ok or ONLY dhcpcd not found (i.e. dhclient present).
                std::cout << "Missing executables (" << Commands.notFound.join("', '").ascii() << "). Exiting." << std::endl;
                KMessageBox::error(0, i18n("Executable(s) '%1' could not be found.\nWireless Assistant will now quit.").arg(Commands.notFound.join("', '")) );
                close();
                return;
        }

	TDEStandardDirs standardDirs;
	wpaConfigFile = standardDirs.saveLocation("config").append("wlassistantwpa");

        ///////////////////////////////////////
        ///// SCAN FOR AVAILABLE NETWORKS /////
	if ( autoConnect ) 
		TQTimer::singleShot( 0, this, TQ_SLOT(netAutoConnect()) );
	else
		TQTimer::singleShot( 0, this, TQ_SLOT(netScan()) );
}

void WirelessAssistant::checkConnectionStatus()
{
	TQListViewItem* lvi;
	if (groupAPs) lvi = getItemByEssid( WATools::essid(NetParams.iface.ascii()));
	else lvi = getItemByAp( WATools::ap(NetParams.iface.ascii() ));
	bool needsKey;
	lvi ? needsKey = static_cast<NetListViewItem*>(lvi)->enc() : needsKey = 0;
	if ( WATools::isConnected(NetParams.iface.ascii()) && WATools::hasKey(NetParams.iface.ascii())==needsKey ) { //connection OK
		if (!connectedItem) {
			std::cout << "Now connected to '" << WATools::essid(NetParams.iface.ascii()) << "'" << std::endl;
			if (groupAPs && NetParams.ap=="any") {
				setConnectedItem( WATools::essid( NetParams.iface.ascii() ) );
				setNetParamsFromConfig( WATools::essid( NetParams.iface.ascii() ) );
			} else {
				setConnectedItem( WATools::ap( NetParams.iface.ascii() ) );
				setNetParamsFromConfig( WATools::ap( NetParams.iface.ascii() ) );
			}
			setNetParamsFromList( connectedItem );
		}
	} else if (connectedItem) { //connection LOST
		setConnectedItem(0);
		timerConnectionCheck->stop();
		if ( autoReconnect || KMessageBox::questionYesNo(0, i18n("Connection to '%1' has been lost!\nWould you like to reconnect?").arg(NetParams.essid), i18n("Connection Lost") , KStdGuiItem::yes(), KStdGuiItem::no() ) == KMessageBox::Yes ) {
                                        netDisconnect( true );
                                        netConnect();
		}
		timerConnectionCheck->start( WA_CONNECTION_CHECK_INTERVAL );
	}
}

void WirelessAssistant::removeNetParams()
{
        NetListViewItem *nvi = static_cast<NetListViewItem*>(netList->selectedItem());
        TQString ap = nvi->ap(); TQString essid = nvi->essid();
        for (TQStringList::Iterator nps = NetParamsList.begin(); nps != NetParamsList.end(); nps++) {
                if ( (*nps).section(",",2,2)==ap && (*nps).section(",",1,1)==essid) {
                        if ( KMessageBox::warningContinueCancel(0, i18n("<qt><p>Settings for network '<b>%1</b>' are about to be deleted.</p><p>Would you like to continue?</p></qt>").arg(essid)) == KMessageBox::Continue ) {
                                if (nvi->hidden())	// hiddenEssid = 1
                                        nvi->setEssid("<hidden>");
                                NetParamsList.remove(nps);
                                WAConfig::self()->writeConfig();
                                statusLabel->setText( i18n("Settings deleted.") );
                        }
                        break;
                }
        }
}


void WirelessAssistant::setDNS( const WANetParams & np )
{
        TQFile f("/etc/resolv.conf");
        if (f.open( IO_WriteOnly | IO_Truncate )) {
                TQTextStream s( &f );
                if (!np.domain.isEmpty()) {
                        s << TQString("domain " + np.domain + "\n");
                        std::cout << "resolv.conf: domain " << np.domain.ascii() << std::endl;
                }
                if (!np.dns1.isEmpty()) {
                        s << TQString("nameserver " + np.dns1 + "\n");
                        std::cout << "resolv.conf: nameserver " << np.dns1.ascii() << std::endl;
                }
                if (!np.dns2.isEmpty()) {
                        s << TQString("nameserver " + np.dns2 + "\n");
                        std::cout << "resolv.conf: nameserver " << np.dns2.ascii() << std::endl;
                }
                f.close();
        } else {
                std::cout << "dns setup error: " << f.name().ascii() << " is not writeable." << std::endl;
                KMessageBox::error(0, i18n("<qt><p>File '<i>%1</i>' could not be opened for writing.</p><p>Nameserver(s) and/or domain are not set.</p></qt>").arg(f.name()) );
        }
}

void WirelessAssistant::netScan()
{
        timerConnectionCheck->stop(); //stop while scanning.
        netScan( NetParams );
        if (netList->childCount() > 0) {
		TQTimer::singleShot( 0, this, TQ_SLOT(checkConnectionStatus()) );
                timerConnectionCheck->start(WA_CONNECTION_CHECK_INTERVAL);
	}
}

void WirelessAssistant::netScan( const WANetParams & np )
{
        if (!radioEnabled()) {
                statusLabel->setText("Radio off. Scanning aborted.");
                std::cout << "Radio is off!" << std::endl;
                setUi(1);
                return;
        }

        setUi(0);

        bool wasConnected = false;
        if (connectedItem) {
                wasConnected = true;
                setConnectedItem( 0 );
        }

        if ( !WATools::isUp(np.iface.ascii()) ) {
                statusLabel->setText(i18n("Bringing interface %1 up...").arg(np.iface.ascii()));
                //runCommand( Commands.cmd("ifup",np) );
		WATools::setUp(true, np.iface.ascii());
		if (DelayBeforeScanning>0) {
        		statusLabel->setText(i18n("Waiting before scanning..."));
        		statusLabel->repaint();
			TDEApplication::eventLoop()->processEvents( TQEventLoop::ExcludeUserInput );
			usleep(DelayBeforeScanning * 1000000); // delay * 1000ms
		}
        }

        statusLabel->setText(i18n("Scanning..."));
        statusLabel->repaint();

        netList->clear();

        TQString result;
        statusLabel->setText(i18n("Scanning..."));
        result = runCommand( Commands.cmd("scan",np) );

	parseScan( result );

        if (netList->childCount() > 0) {
                std::cout << "Networks found: " << TQString::number( netList->childCount() ).ascii() << std::endl;
                if (wasConnected)
			groupAPs ? setConnectedItem( WATools::essid() ) : setConnectedItem( WATools::ap() ); //mark item as connected.
                statusLabel->setText( i18n("Done.") );
        } else {
                //Workaround for cards overusing cache - bringing if down seems to solve it.
                //runCommand( Commands.cmd("ifdown", NetParams) ); //Commented out b/c it seems to cause more problems than it solves. (like no scan results)
                std::cout << "No networks found!" << std::endl;
                statusLabel->setText( i18n("No networks found.") );
                if ( result.find("Resource temporarily unavailable")>-1 ) {
                        std::cout << "Radio switch seems to be off." << std::endl;
                        KMessageBox::information(0, i18n("Radio of your wireless card seems to be turned off using an external switch on your computer.\nYou need turn it on to be able to use wireless networks.") );
                }
        }
        setNetListColumns();
}

void WirelessAssistant::parseScan( const TQString & output )
{
        TQString essid;
	TQStringList essidList;
        TQString channel;
        TQString mode;
        int qualInt;
        bool enc; //default to false
        bool hidden; //default to false
        TQString ap;
	
	// security parameters
	bool wpa;
	TQStringList wpaSettings;
	//TQString wpaVersion, wpaGroupCipher, wpaPairwiseCipher, wpaAuthenticationSuite;
	

        bool ok_channel = true;	//does iwlist return channel?
        TQString section;

        netList->setUpdatesEnabled( false ); //do not redraw while adding items to avoid flicker.

        for (int i=1; (!output.section("Cell ",i,i).isEmpty()); i++ ) {
                section = output.section("Cell ",i,i);

                // GET ESSID VALUE
                essid = getVal(section, "ESSID\\W+\"(.+)\"");

                // GET CHANNEL NUMBER
                channel = getVal(section, "Channel\\D+(\\d+)" );
                if (channel.isEmpty()) {
                        channel = getVal(section, "Frequency\\D+(\\d.+)Hz");
                        ok_channel = false;
                }

                // GET MODE VALUE
                mode = getVal(section, "Mode:(\\w)"); //get 1st letter of mode.
                if (mode.upper()!="M") //this covers both Managed and Master. Other are unsupported.
                        continue;

                // GET AP
                ap = getVal(section, "Address\\W+(\\S+)");

                if (essid.isEmpty()) {
                        if (!ap.isEmpty()) //older wireless-tools report "", not "<hidden>"
                                essid = "<hidden>";
                        else
                                continue;	//some cards report one '' essid even when no network's present. Workaround.
                }

                if (essid=="<hidden>") {
                        hidden = true;
                        essid = matchEssidForAp( ap );
                } else
                        hidden=false;

                // GET QUALITY
                int wsignal;
                //check if driver reports quality directly
                qualInt = getVal(section, "Quality\\D+(\\d+)").toInt();

                if (qualInt == 0) { //noise not reported? estimate.
                        wsignal = getVal(section, "Signal level\\D+(\\d+)" ).toInt();
                        qualInt = 100-wsignal;
                }
                qualInt = (100*qualInt)/50; //adjust and normalize quality (0-100). 50 is the best (6 stars) noise/signal difference
        	if (qualInt > 100) qualInt = 100;

                // GET ENCRYPTION
                if (getVal(section, "Encryption key\\W+(\\w+)" ).upper()=="OFF")
                        enc = false;
                else {
                        enc = true;

			wpaSettings.clear();
			if ( section.contains("WPA2 Version") ) wpaSettings << "WPA2"; //prefer WPA2 over WPA
			else if ( section.contains("WPA Version") ) wpaSettings << "WPA";

			wpa = ( !wpaSettings.isEmpty() );
			if (wpa) {
				wpaSettings << getVal(section, "Group Cipher : (\\w+)") \
				<< getVal(section, "Pairwise Ciphers \\(\\d+\\) : ([\\w ]+)[\n\r]") \
				<< getVal(section, "Authentication Suites \\(\\d+\\) : ([\\w ]+)[\n\r]");
			}
		}

		// CHECK IF SAME ESSID ALREADY FOUND, if necessary
		if (groupAPs) {
			if ( !hidden && essidList.contains(essid) ) {
				NetListViewItem* sameEssid = static_cast<NetListViewItem*>(getItemByEssid(essid));
				sameEssid->setAp("any");
				if (sameEssid->quality() < qualInt) {
					sameEssid->setQuality(qualInt);
					sameEssid->setChannel(channel);
				}
				continue;
			}
		essidList << essid;
		}

                NetListViewItem* nvi = new NetListViewItem( netList, essid, channel, qualInt, enc, ap, hidden );
		if (wpa) nvi->setWpaSettings( wpaSettings );
        }

        if (!ok_channel)
                netList->setColumnText( 1, i18n("Freq (Hz)") );

        /// @fixme HACK: Test item for the network list.
        /// new NetListViewItem( netList, "Test Net", "9", 76, 1, "00:00:00:00:00:11", 0 );


        netList->setUpdatesEnabled( true );
        setUi(1);
}

bool WirelessAssistant::radioEnabled()
{
        bool r;
        if ( WATools::txpower()==-1 ) {
                if (KMessageBox::questionYesNo(0, i18n("Radio of your wireless card is off.\nWould you like to turn it on?") )== KMessageBox::Yes) {
                        runCommand( Commands.cmd("radio_on", NetParams) );
                        r = true;
                } else {
                        r = false;
                }
        } else
                r = true;

        return r;
}

void WirelessAssistant::setNetParamsFromList( TQListViewItem* lvi )
{
        NetListViewItem *nvi = static_cast<NetListViewItem*>(lvi);
        NetParams.essid = nvi->essid();
        NetParams.hiddenEssid = nvi->hidden();
        //NetParams.mode = nvi->mode();
        NetParams.channel = nvi->channel();
        NetParams.ap = nvi->ap();
	NetParams.wpaSettings = nvi->wpaSettings();
        NetParams.wep = ( nvi->enc() && NetParams.wpaSettings.isEmpty() );
	NetParams.wpa = ( nvi->enc() && !NetParams.wpaSettings.isEmpty() );
}

bool WirelessAssistant::setNetParamsFromConfig( const TQString & s )
{
        for (TQStringList::Iterator nps = NetParamsList.begin(); nps != NetParamsList.end(); nps++) {
                if ( (*nps).section(",",2,2)==s || ( (*nps).section(",",1,1)==s && (*nps).section(",",2,2)=="any") ) {
                        NetParams.loadNetParamsString( *nps );
			if (!s.contains(":")) NetParams.ap = "any"; //if searched by essid
                        return 1;
                }
        }
        return 0;
}

void WirelessAssistant::itemAction()
{
        TQListViewItem* lvi = netList->selectedItem();
        if (!lvi)
                return;

        NetListViewItem* nvi = static_cast<NetListViewItem*>(lvi);
        ///////////////////
        ///// ACTIONS /////
        if (nvi->isConnected()) {
                std::cout << "ACTION: DISCONNECT." << std::endl;
                netDisconnect();
                return;
        } else {
                std::cout << "ACTION: CONNECT." << std::endl;
                netConnect();
                return;
        }
}

void WirelessAssistant::netAutoConnect()
{
	netScan();
	if ( WATools::isConnected(NetParams.iface.ascii()) ) return;

	int bestItem = -1;
	int bestQuality = 0;
	for ( int i = 0; i < netList->childCount(); i++ ) {
		NetListViewItem* nvi = static_cast<NetListViewItem*>( netList->itemAtIndex(i) );
		TQString search = nvi->ap();
		if (search == "any") search = nvi->essid();
		if ( setNetParamsFromConfig(search) ) {
			if ( nvi->quality() > bestQuality ) {
				bestQuality = nvi->quality();
				bestItem = i;
			}
		}
	}

	if ( bestItem != -1 ) {
		NetListViewItem* nvi = static_cast<NetListViewItem*>( netList->itemAtIndex( bestItem ) );
		setNetParamsFromList( nvi );
		TQString search = nvi->ap();
		if (search == "any") search = nvi->essid();
		setNetParamsFromConfig( search );
		timerConnectionCheck->stop();
		netConnect( NetParams );
		timerConnectionCheck->start(WA_CONNECTION_CHECK_INTERVAL);
	} else {
		statusLabel->setText( i18n("Auto connection failed.") );
		std::cout << "Auto connection failed: no available configured networks found." << std::endl;
	}
}

void WirelessAssistant::netConnect()
{
        timerConnectionCheck->stop();
	setNetParamsFromList( netList->selectedItem() );
	//can't connect if WPA needed, and wpa_supplicant and wpa_cli not available
	if ( NetParams.wpa && !wpaAvailable ) {
		KMessageBox::error(0, i18n("<qt><p><b>Can not connect to network '%1'.</b></p><p>The network you are trying to connect to requires WPA authentication. The necessary executables <i>wpa_supplicant</i> and <i>wpa_cli</i> could not be found. Install <i>wpa_supplicant</i> and restart Wireless Assistant to connect.</p></qt>").arg(NetParams.essid) );
		timerConnectionCheck->start(WA_CONNECTION_CHECK_INTERVAL); //resume connection checking
		return;
	}
	TQString search = NetParams.ap;
	if (search == "any") search = NetParams.essid;
        if ( (NetParams.essid=="<hidden>") || (!setNetParamsFromConfig( search )) ) {
                ui_NetParamsWizard *netwiz = new ui_NetParamsWizard;
                if (!NetParams.hiddenEssid)
                        netwiz->setCaption( i18n("%1 - First Connection Wizard").arg(NetParams.essid) );
                netwiz->setEssidEnabled( NetParams.hiddenEssid );
                netwiz->setWepEnabled( NetParams.wep );
		netwiz->setWpaEnabled( NetParams.wpa, NetParams.wpaSettings );
                netwiz->exec();
                if (netwiz->result()==TQDialog::Rejected) {
                        delete netwiz;
			timerConnectionCheck->start(WA_CONNECTION_CHECK_INTERVAL); //resume connection checking
                        return;
                } else {
                        NetParams = netwiz->readNetParams( NetParams );
                        NetParams.wasHiddenEssid = NetParams.hiddenEssid; //first time values.
                        NetParams.wasWep = NetParams.wep;
                        NetParamsList << NetParams.netParamsString();
                        if (NetParams.hiddenEssid)
                                static_cast<NetListViewItem*>(netList->selectedItem())->setEssid( NetParams.essid );
                        WAConfig::self()->writeConfig();
                        delete netwiz;
                }
        }

        if (NetParams.review())
                editNetParams();
        updateNetParams();
        netConnect( NetParams );
        timerConnectionCheck->start(WA_CONNECTION_CHECK_INTERVAL);
}

void WirelessAssistant::updateNetParams()
{
        for (TQStringList::Iterator nps = NetParamsList.begin(); nps != NetParamsList.end(); nps++) {
                if ( (*nps).section(",",2,2)==NetParams.ap ) {
                        TQString newNps = NetParams.netParamsString();
                        if ( newNps!=(*nps) ) {
                                (*nps) = newNps;
                                WAConfig::self()->writeConfig();
                                std::cout << "Network settings updated." << std::endl;
                                statusLabel->setText( i18n("Network settings updated.") );
                                break;
                        }
                }
        }
}

TQString WirelessAssistant::matchEssidForAp( const TQString & ap )
{
        for (TQStringList::Iterator nps = NetParamsList.begin(); nps != NetParamsList.end(); nps++) {
                if ( (*nps).section(",",2,2)==ap ) {
                        return (*nps).section(",",1,1); //essid
                }
        }
        return "<hidden>";
}

void WirelessAssistant::netConnect( const WANetParams & np )
{
        setUi(0);

        if (connectedItem)
                netDisconnect( true );
        else if ( dhcpClientRunning() )
                runCommand( Commands.cmd("kill_dhcp", np) ); //kill any stale DHCP client running

	if ( !np.preConnectionCommand.isEmpty() ) {
		std::cout << "Running pre-connection command: " << np.preConnectionCommand.ascii() << std::endl;
		statusLabel->setText( i18n("Running pre-connection command...") );
		runCommand( TQStringList::split( " ", np.preConnectionCommand ), np.preConnectionTimeout, np.preConnectionDetached );
	} else
		std::cout << "No pre-connection command specified." << std::endl;


        statusLabel->setText( i18n("Connecting to '%1'...").arg(np.essid) );
        statusLabel->repaint();
	if (!WATools::isUp(np.iface.ascii()) ) WATools::setUp( true, np.iface.ascii() );
        //runCommand( Commands.cmd("ifup", np) );
        if ( runCommand( Commands.cmd("iwconfig_set", np) ).find("8B04") > -1 ) { // error 8B04 - Request 'Set Frequency' not supported.
        	WANetParams np2 = np;
        	np2.channel = "0";
        	runCommand( Commands.cmd("iwconfig_set", np2) );
        }

        runCommand( Commands.cmd("iwconfig_ap", np) );

	///////////////////////
	///// RUN WPA CLIENT IF NEEDED
	if (np.wpa) {
		if ( generateWpaConfigFile( np.essid, np.wpaSettings, np.wpaKey ) ) {
			if ( !setWpaClientEnabled( true, np.iface ) ) {
	                        setUi(1);
        	                std::cout << "CONNECTION FAILED." << std::endl;
                	        statusLabel->setText( i18n("Connection failed.") );
				runCommand( Commands.cmd("disconnect", np ) );
				return;
			}
		}
	}

	////////////////////////
	///// CONFIGURE IP ADDRESS etc.
	if (np.dhcp) { //DHCP config
                TQString dhcp_out = runCommand( Commands.cmd("ifconfig_dhcp", np), DhcpTimeout );
                if ( dhcp_out.contains("::ERR::") && !dhcp_out.contains("bound to ") ) { // 'bound to' is a check for dhclient, which gives some output to stderr even when succeeded
                        if ( dhcpClientRunning() )
                                runCommand( Commands.cmd("kill_dhcp", np) ); //kill any stale DHCP client running (seems it's dhclient only)
                        setUi(1);
                        std::cout << "CONNECTION FAILED." << std::endl;
                        statusLabel->setText( i18n("Connection failed.") );
			runCommand( Commands.cmd("disconnect", np ) );
                        return;
                }
        } else { //manual config
                runCommand( Commands.cmd("ifconfig_manual", np) );
                setDNS( np );
                runCommand( Commands.cmd("route_add", np) );
        }

	if ( !np.postConnectionCommand.isEmpty() ) {
		std::cout << "Running post-connection command: " << np.postConnectionCommand.ascii() << std::endl;
		statusLabel->setText( i18n("Running post-connection command...") );
		runCommand( TQStringList::split( " ", np.postConnectionCommand ), np.postConnectionTimeout, np.postConnectionDetached );
	} else
		std::cout << "No post-connection command specified." << std::endl;

        //////////////////////
        ///// CHECK CONNECTION
        statusLabel->setText(i18n("Testing connection..."));
	usleep(200*1000);	//sleep 200ms to make sure all parameters are set.
        if ( WATools::isConnected(np.iface.ascii())) {
                if (autoQuit)
                        this->close();
                groupAPs ? setConnectedItem( np.essid ) : setConnectedItem( np.ap );
                statusLabel->setText( i18n("Successfully connected to '%1'.").arg(np.essid) );
                setUi(1);
        } else {
		std::cout << "CONNECTION FAILED." << std::endl;
                statusLabel->setText(i18n("Connection failed."));
		runCommand( Commands.cmd("disconnect", np ) );
                setConnectedItem( 0 );
                setUi(1);
                if (KMessageBox::questionYesNo(0, i18n("Connection failed.\nWould you like to review settings for this network?"), i18n("Review Settings?") , KStdGuiItem::yes(), KStdGuiItem::no(), "ReviewSettings" ) == KMessageBox::Yes)
                        editNetParams();
        }
}

void WirelessAssistant::updateConnectedItem()
{
        connectedItem->setQuality( WATools::quality() );
}

void WirelessAssistant::setConnectedItem( const TQString & netid )
{
	timerConnectionCheck->stop(); //stop timer while changing currentItem
        if (connectedItem) {
		timerGui->stop();
                connectedItem->setConnected( false );
                connectedItem = 0;
        }
        if (!netid.isEmpty()) {
                TQListViewItem* lvi;
		if (netid.contains(":")) lvi = getItemByAp( netid ); //netid is an AP address
		else lvi = getItemByEssid( netid );
                if (lvi) {
                        NetListViewItem* nvi = static_cast<NetListViewItem*>(lvi);
                        nvi->setConnected( true );
                        connectedItem = nvi;
                        netList->sort();	// sort to make sure new connectedItem is 1st.
                }
        }

        if (connectedItem) {
                timerGui->start(2500); //update quality indicator every 2.5seconds
        }
        updateConnectButton( netList->selectedItem() );
        timerConnectionCheck->start(WA_CONNECTION_CHECK_INTERVAL);
}

void WirelessAssistant::netDisconnect( const bool & quiet )
{
        if ( (quiet) || (KMessageBox::warningContinueCancel(0, i18n("<qt><p>You are about to disconnect from '<b>%1</b>'.</p><p>Would you like to continue?</p></qt>").arg(connectedItem->essid()) )== KMessageBox::Continue ) ) {
                timerConnectionCheck->stop(); //stop while disconnecting.

		if ( !NetParams.preDisconnectionCommand.isEmpty() ) {
			std::cout << "Running pre-disconnection command: " << NetParams.preDisconnectionCommand.ascii() << std::endl;
			statusLabel->setText( i18n("Running pre-disconnection command...") );
			runCommand( TQStringList::split( " ", NetParams.preDisconnectionCommand ), NetParams.preDisconnectionTimeout, NetParams.preDisconnectionDetached );
		} else
			std::cout << "No pre-disconnection command specified." << std::endl;


		statusLabel->setText( i18n("Disconnecting...") );
                statusLabel->repaint();
                setConnectedItem( 0 );
                if ( NetParams.dhcp ) {
			if ( dhcpClientRunning() ) {
                        	runCommand( Commands.cmd( "kill_dhcp", NetParams ) );
                        	statusLabel->setText( i18n("Waiting for DHCP client to shut down...") );
                        	statusLabel->repaint();
                        	TQTimer* tmr = new TQTimer();
                        	tmr->start(1500, true);	//wait 1.5sec for dhcp client to really shutdown, single shot.
                        	while ( tmr->isActive() ) {
                                	TDEApplication::eventLoop()->processEvents( TQEventLoop::AllEvents );
                                	usleep(75*1000); //75msec on Linux
                        	}
                        	delete tmr;
			}
                } else {
			runCommand( Commands.cmd( "route_del", NetParams ) );
		}
                runCommand( Commands.cmd( "disconnect", NetParams ) );
                WATools::setUp( false, NetParams.iface.ascii() );

		if ( NetParams.wpa )
			setWpaClientEnabled( false );

                std::cout << "DISCONNECTED." << std::endl;

		if ( !NetParams.postDisconnectionCommand.isEmpty() ) {
			std::cout << "Running post-disconnection command: " << NetParams.postDisconnectionCommand.ascii() << std::endl;
			statusLabel->setText( i18n("Running post-disconnection command...") );
			runCommand( TQStringList::split( " ", NetParams.postDisconnectionCommand ), NetParams.postDisconnectionTimeout, NetParams.postDisconnectionDetached );
		} else
			std::cout << "No post-disconnection command specified." << std::endl;


                statusLabel->setText( i18n("Done.") );
                timerConnectionCheck->start(WA_CONNECTION_CHECK_INTERVAL);
        } else {
                statusLabel->setText( i18n("Cancelled.") );
        }
}

TQListViewItem* WirelessAssistant::getItemByAp( const TQString & ap )
{
        TQListViewItem* lvi = netList->firstChild();
        while (lvi) {
                if ( static_cast<NetListViewItem*>(lvi)->
                                ap() == ap ) {
                        break;
                }
                lvi = lvi->nextSibling();
        }
        return lvi;
}

TQListViewItem* WirelessAssistant::getItemByEssid( const TQString & essid )
{
        TQListViewItem* lvi = netList->firstChild();
        while (lvi) {
                if ( static_cast<NetListViewItem*>(lvi)->
                                essid() == essid ) {
                        break;
                }
                lvi = lvi->nextSibling();
        }
        return lvi;
}


void WirelessAssistant::updateConfiguration(int category)
{
        if (category == TDEApplication::SETTINGS_MOUSE) {
                setMouseBehaviour();
                return;
        }
        if (category == -1) {
                autoQuit = checkAutoQuit->isChecked();
		autoReconnect = checkAutoReconnect->isChecked();
		autoConnect = checkAutoConnect->isChecked();
		groupAPs = checkGroupAPs->isChecked();
		DelayBeforeScanning = spinDelayBeforeScanning->value();
                DhcpTimeout = spinDhcpTimeout->value();
        }
}

void WirelessAssistant::togglePage(bool options)
{
        buttonScan->setDisabled(options);
        buttonConnect->setDisabled(options);
        if (options) {
                if (WAConfig::self()->config()->groupList().contains("Notification Messages")>0)
                        buttonEnableAllMessages->setEnabled(true);
                else
                        buttonEnableAllMessages->setEnabled(false);
                widgetStack->raiseWidget(optionsPage);
        } else {
                widgetStack->raiseWidget(netPage);
                updateConfiguration(-1);
        }
}

void WirelessAssistant::enableAllMessages()
{
        KMessageBox::enableAllMessages();
        buttonEnableAllMessages->setEnabled( false );
}

void WirelessAssistant::setMouseBehaviour()
{
        if ( TDEGlobalSettings::singleClick() ) {
                disconnect( netList, TQ_SIGNAL(selectionChanged(TQListViewItem*)),
                            this, TQ_SLOT(updateConnectButton(TQListViewItem*)) );
                disconnect( netList, TQ_SIGNAL(doubleClicked(TQListViewItem*, const TQPoint &, int)),
                            this, TQ_SLOT(itemAction()) );
                connect( netList, TQ_SIGNAL(clicked(TQListViewItem*, const TQPoint &, int)),
                         this, TQ_SLOT(itemAction()) );
                buttonConnect->hide();
        } else {
                disconnect( netList, TQ_SIGNAL(clicked(TQListViewItem*, const TQPoint &, int)),
                            this, TQ_SLOT(itemAction()) );

                connect( netList, TQ_SIGNAL(selectionChanged(TQListViewItem*)),
                         this, TQ_SLOT(updateConnectButton(TQListViewItem*)) );
                connect( netList, TQ_SIGNAL(doubleClicked(TQListViewItem*, const TQPoint &, int)),
                         this, TQ_SLOT(itemAction()) );
                buttonConnect->show();
        }
}

void WirelessAssistant::updateConnectButton(TQListViewItem* lvi)
{
        TQToolTip::remove
                (buttonConnect);
        if ( lvi == connectedItem ) {
                buttonConnect->setText( i18n("&Disconnect") );
                TQToolTip::add
                        ( buttonConnect, i18n("Disconnect from the selected network") );

        } else {
                buttonConnect->setText( i18n("&Connect") );
                TQToolTip::add
                        ( buttonConnect, i18n("Connect to the selected network") );

        }
}

void WirelessAssistant::setDev( const TQString & ifname)
{
        NetParams.iface = ifname;
        WATools::setInterface( ifname.ascii() );
        std::cout << "Selected interface: " << ifname.ascii() << std::endl;
        netScan();
}

TQString WirelessAssistant::runCommand( const TQStringList & cmd, int timeout, bool detached )
{
        if (cmd.isEmpty())
                return TQString();

	// a very basic and easy-to-workaround attepmt to restrict using dangerous commands via custom commands setting. This *REALLY* needs a working solution.
	if ( cmd[0] == "rm" || cmd[0] == "mv" || cmd[0] == "cp" || cmd[0] == "ln" ) return TQString();

	TQProcess* p = new TQProcess( this );
        p->setArguments( cmd );

        p->start();
	if (detached) {
		p = 0;
		return TQString();
	}

	TQTimer* timerProc = new TQTimer(); //timeout timer
        if ( timeout>0 && !detached ) {
                connect( timerProc, TQ_SIGNAL(timeout()), p, TQ_SLOT(kill()) );
                timerProc->start(timeout*1000); //convert sec to msec
        }

        connect(buttonClose, TQ_SIGNAL(clicked()),
                p, TQ_SLOT(kill()) );
        int i = 0;

        while ( p->isRunning() ) { // PROCESS USER EVENTS
                TDEApplication::eventLoop()->processEvents( TQEventLoop::AllEvents );
                usleep(75*1000); //75msec on Linux (75000msec on Windows...)
                if (i==27) { // ca 2sec have passed and the process is still running. Replace the 'Close' button with 'Stop'.
                        disconnect(buttonClose, TQ_SIGNAL(clicked()),
                                   this, TQ_SLOT(close()) );
                        buttonClose->setIconSet( SmallIconSet("process-stop") );
                        buttonClose->setText( i18n("&Stop") );
                        TQToolTip::remove
                                (buttonClose);
                        TQToolTip::add
                                ( buttonClose, i18n("Terminate current process\n(%1)").arg( p->arguments().join(" ") ) );
                }
                i++;
        }

        disconnect(buttonClose, TQ_SIGNAL(clicked()),
                   p, TQ_SLOT(kill()) );
        if (i>27) {//set 'stop' back to 'close' if needed
                connect(buttonClose, TQ_SIGNAL(clicked()),
                        this, TQ_SLOT(close()) );
                buttonClose->setIconSet( SmallIconSet("window-close") );
                buttonClose->setText( i18n("&Quit") );
                TQToolTip::remove
                        (buttonClose);
                TQToolTip::add
                        ( buttonClose, i18n("Quit the application") );
        }

        if (timerProc->isActive())
                timerProc->stop();
        delete timerProc;
        TQString e = TQString( p->readStderr() );
        TQString o = TQString( p->readStdout() );
        if (!p->normalExit()) {
                o.append("::ERR::killed");
                //std::cout << "Process terminated (timed out)." << std::endl; //too much output when checking for internet when it's not available.
        }
        delete p;

        if (!e.isEmpty()) {
                std::cout << "==>stderr: " << e.ascii();// << std::endl;
                o.append("::ERR::");
                o.append(e);
        }

        return o;
}

void WirelessAssistant::setUi(int uiState)
{

        if (uiState==0) {
                devCombo->setEnabled( false );
                buttonScan->setEnabled( false );
                buttonConnect->setEnabled( false );
                buttonOptions->setEnabled( false );
                TDEApplication::setOverrideCursor( TQCursor(TQt::BusyCursor) );
        } else {
                if (devCombo->count() > 0) {
                        devCombo->setEnabled( true );
                        buttonScan->setEnabled( true );
                }
                if (netList->childCount() > 0)
                        buttonConnect->setEnabled( true );
                buttonOptions->setEnabled( true );
                TDEApplication::restoreOverrideCursor();
        }
}

void WirelessAssistant::showItemContextMenu( TQListViewItem* i, const TQPoint& p, int c )
{
        if (!i)
                return;

        NetListViewItem *nvi = static_cast<NetListViewItem*>(i);

	TQString search = nvi->ap();
	if (search == "any") search = nvi->essid();
        bool isConfigured = setNetParamsFromConfig(search);

        TDEPopupMenu *icm = new TDEPopupMenu();
        icm->insertTitle(nvi->essid());
        if (isConfigured) {
                if (nvi->isConnected()) {
                        icm->insertItem( SmallIcon("connect_no"), i18n("Disconnect..."), this, TQ_SLOT(netDisconnect()) );
                        //icm->insertItem( SmallIcon("reload"), i18n("Reconnect"), this, TQ_SLOT(netConnect()) );
                } else
                        icm->insertItem( SmallIcon("connect_creating"), i18n("Connect"), this, TQ_SLOT(netConnect()) );
                icm->insertSeparator();
                icm->insertItem(i18n("Forget Settings..."), this, TQ_SLOT(removeNetParams()) );
                icm->insertItem(i18n("Edit Settings..."), this, TQ_SLOT(editNetParams()) );
        } else {
                if (nvi->isConnected()) {
                        icm->insertItem( SmallIcon("connect_no"), i18n("Disconnect..."), this, TQ_SLOT(netDisconnect()) );
                        //icm->insertItem( SmallIcon("reload"), i18n("Configure and Reconnect..."), this, TQ_SLOT(netConnect()) );
                } else
                        icm->insertItem( SmallIcon("connect_creating"), i18n("Configure and Connect..."), this, TQ_SLOT(netConnect()) );
        }
        icm->exec( TQCursor::pos() );
}

void WirelessAssistant::editNetParams()
{
        setNetParamsFromList( netList->selectedItem() );	//prepare NetParams
        if (NetParams.ap!="any") setNetParamsFromConfig( NetParams.ap );	//prepare NetParams
	else setNetParamsFromConfig( NetParams.essid );

        ui_NetParamsEdit *netedit = new ui_NetParamsEdit();
        netedit->setValues( NetParams );
        netedit->setCaption( i18n("%1 Settings").arg(NetParams.essid) );
        netedit->exec();
        if (netedit->result() == TQDialog::Rejected) {
                delete netedit;
                return;
        } else {	//accepted
                NetParams = netedit->readNetParams( NetParams );
                updateNetParams();
        }
}

void WirelessAssistant::setNetListColumns()
{
        int realWidth = netList->viewportSize( netList->contentsWidth(), netList->contentsHeight() ).width(); //calculate actual width taking scrollbars into account
        int essidWidth = realWidth - netList->columnWidth(1) - netList->columnWidth(2) - netList->columnWidth(3);

        netList->setColumnWidth(0, essidWidth);
        netList->triggerUpdate();
}

bool WirelessAssistant::dhcpClientRunning()
{
        TQStringList pidPaths;
        TQString pidFile;
        pidPaths << "/etc/" << "/etc/dhcpc/" << "/var/run/";
        if ( Commands.dhcpClient=="dhcpcd" )
                pidFile = TQString("dhcpcd-%1.pid").arg(NetParams.iface.ascii());
        else
                pidFile = TQString("dhclient.pid");

        for ( TQStringList::Iterator it = pidPaths.begin(); it != pidPaths.end(); ++it ) {
                if ( TQFile( TQString(*it).append(pidFile) ).exists() ) {
                        std::cout << "Running DHCP client found." << std::endl;
                        return true;
                }
        }
        std::cout << "No DHCP client running." << std::endl;
        return false;
}

TQStringList WirelessAssistant::interfaceList()
{
	TQDir d("/sys/class/net");
	TQStringList ifList = d.entryList( TQDir::Dirs );
	ifList.remove("."); ifList.remove(".."); ifList.remove("lo");
	std::cout << "All interfaces: " << ifList.join(", ").ascii() << std::endl;
	for (TQStringList::Iterator nps = ifList.begin(); nps != ifList.end(); nps++) {
		const char* i = (*nps).ascii();
		bool w = WATools::isWireless( i );
		if ( !WATools::isWireless( (*nps).ascii() ) ) {
			nps = ifList.remove( nps ); nps--;
		}
	}
	return ifList;
}

TQString WirelessAssistant::getVal(const TQString & str, const TQString & rxs)
{
        TQRegExp rx(rxs);
        rx.search(str);
        return rx.cap(1).stripWhiteSpace();
}

bool WirelessAssistant::generateWpaConfigFile( const TQString& essid, const TQStringList& wpaSettings, const TQString& wpaKey )
{
	// 0 WPA version (1 or 2), 1 group, 2 pairwise, 3 suite
	if ( wpaSettings.isEmpty() ) return false;
	TQString c = "ctrl_interface=/var/run/wpa_supplicant\nnetwork={\nscan_ssid=0\nssid=\""; //fast_reauth=1\n
	c.append(essid).append("\"\n");

	// WPA version
	c.append("proto=").append(wpaSettings[0]).append("\n");

	//WPA authentication suite
	c.append("key_mgmt=");
	if ( wpaSettings[3].contains("PSK") ) c.append("WPA-PSK\n");
	else return false; // not supported

	//WPA pairwise cipher
	c.append("pairwise=");
	c.append( wpaSettings[2] ).append("\n");

	//WPA group cipher
	c.append("group=");
	c.append( wpaSettings[1] ).append("\n");

	//WPA key
	TQString k = TQString();
	if (wpaKey.left(2)=="s:") { // PASSPHRASE
		k.append("\"");
		k.append( wpaKey.right( wpaKey.length() - 2 ) );
		k.append("\"\n");
	} else
		k.append( wpaKey ).append("\n"); // HEX KEY
	
	c.append("psk=").append(k);

	c.append("}\n");
	//std::cout << "WPA Config:\n" << c << std::endl;

// # WPA protected network, supply your own ESSID and WPAPSK here:
// network={
//   scan_ssid=0
//   ssid="your_essid_here"
//   proto=WPA
//   key_mgmt=WPA-PSK
//   pairwise=CCMP TKIP
//   group=CCMP TKIP WEP104 WEP40
//   psk=your_psk_here
// }

	TQFile file( wpaConfigFile );
	if (file.exists()) file.remove();
	if ( file.open( IO_WriteOnly ) ) {
		TQTextStream stream( &file );
		stream << c;
		file.close();
		//std::cout << "Wrote WPA config: " << wpaConfigFile << std::endl;
		return 1;
	} else
		return 0;
}

bool WirelessAssistant::setWpaClientEnabled( bool e, const TQString& iface, TQString driver )
{
	if (!e) {
		if ( runCommand( TQStringList(Commands.wpa_cli) << TQString("-i%1").arg(NetParams.iface) << "terminate" ).contains("OK") ) {
			TQFile( wpaConfigFile ).remove();
			return 1;
		} else
			return 0; // wpa client was not running.
	}

	if ( !runCommand( TQStringList(Commands.wpa_cli) << TQString("-i%1").arg(NetParams.iface) << "status" ).contains("Failed to connect") ) {
		std::cout << "WPA client already running. Reconfiguring..." << std::endl;
		runCommand( TQStringList(Commands.wpa_cli) << "reconfigure" );
	} else {
		if ( driver.isEmpty() ) { //detect needed driver
			TQString k = WATools::kernelModule( iface.ascii() );
			if ( k.contains("hermes") ) driver = "hermes";
			else if ( k.contains("atmel") ) driver = "atmel";
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 13)
			else if ( k.contains("ipw") ) driver = "ipw"; //wext should be used for kernels newer than 2.6.12
#endif
			//Commented out, because ndiswrapper newer than 1.13 works with wext driver.
			//else if ( k.contains("ndiswrapper") ) driver = "ndiswrapper";
			//Commented out, because madwifi-ng works with wext driver.
			//else if ( k.contains("ath") ) driver = "madwifi";
			else driver = "wext";
			std::cout << "Using wpa_supplicant driver: " << driver.ascii() << std::endl;
		}

		TQProcess* wp = new TQProcess( this );
		wp->clearArguments();
		wp->addArgument( Commands.wpa_supplicant );
		wp->addArgument( "-W" ); //wait for control interface
		wp->addArgument( TQString("-D%1").arg(driver) );
		wp->addArgument( TQString("-i%1").arg(iface) );
		wp->addArgument( TQString("-c%1").arg(wpaConfigFile) );
		//std::cout << "Starting WPA client: " << wp->arguments().join(" ").ascii() << std::endl;
		if ( !wp->start() ) {
			std::cout << "Failed to start WPA client." << std::endl;
			return 0;
		}
		wp = 0;
		std::cout << "WPA client started. Waiting for status..." << std::endl;
	}

	usleep(200*1000); //200msec for wpa_supplicant to initiate

	TQString o;
	int i = 0;
	while ( !(o =runCommand( TQStringList(Commands.wpa_cli) << TQString("-i%1").arg(NetParams.iface) << "status" )).contains("Failed to connect") ) {
		for (int c = 0; c < 15; c++) {
			usleep(75*1000); //75msec
			TDEApplication::eventLoop()->processEvents( TQEventLoop::AllEvents );
			i++;
		}
		if (i>400) { //more than 30sec have passed
			runCommand( TQStringList(Commands.wpa_cli) << TQString("-i%1").arg(NetParams.iface) << "terminate" );
			return 0;
		}
		if ( o.contains("wpa_state=COMPLETED") ) {
			std::cout << "WPA Authorisation successful." << std::endl;
			return 1;
		}
	}
	return 0;
}


bool WirelessAssistant::close()
{
	updateConfiguration(-1);	//read values from setingsPage;
        WAConfig::self()->writeConfig();
        std::cout << "Application options saved." << std::endl;
        WATools::cleanup();
        std::cout << "Kernel socket closed." << std::endl;
        return TQWidget::close();
}


#include "wlassistant.moc"
