You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wlassistant/src/wlassistant.cpp

1265 lines
50 KiB

/***************************************************************************
* 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 <kstandarddirs.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( TDEApplication::kApplication(), 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"