/*************************************************************************** * 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 #include //provides LINUX_VERSION* macros #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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, TQT_SIGNAL(clicked()), this, TQT_SLOT(netScan()) ); connect( buttonConnect, TQT_SIGNAL(clicked()), this, TQT_SLOT(itemAction()) ); connect( buttonClose, TQT_SIGNAL(clicked()), this, TQT_SLOT(close()) ); connect( devCombo, TQT_SIGNAL(activated( const TQString & )), this, TQT_SLOT(setDev( const TQString & )) ); connect( netList, TQT_SIGNAL(rightButtonPressed( TQListViewItem*, const TQPoint&, int )), TQT_SLOT(showItemContextMenu( TQListViewItem*, const TQPoint&, int )) ); /// Settings Widget connect( buttonOptions, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(togglePage(bool)) ); connect( buttonEnableAllMessages, TQT_SIGNAL(clicked()), this, TQT_SLOT(enableAllMessages()) ); /// Global KDE Options connect( TDEApplication::kApplication(), TQT_SIGNAL(settingsChanged(int)), this, TQT_SLOT(updateConfiguration(int)) ); setMouseBehaviour(); TQTimer::singleShot(10, this, TQT_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; icount(); 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("

You might have insufficient permissions for Wireless Assistant to function properly.

Did you run it using 'sudo'?

") ); } 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, TQT_SIGNAL(timeout()), TQT_SLOT(updateConnectedItem()) ); connect( timerConnectionCheck, TQT_SIGNAL(timeout()), TQT_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, TQT_SLOT(netAutoConnect()) ); else TQTimer::singleShot( 0, this, TQT_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(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(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("

Settings for network '%1' are about to be deleted.

Would you like to continue?

").arg(essid)) == KMessageBox::Continue ) { if (nvi->hidden()) // hiddenEssid = 1 nvi->setEssid(""); 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("

File '%1' could not be opened for writing.

Nameserver(s) and/or domain are not set.

").arg(f.name()) ); } } void WirelessAssistant::netScan() { timerConnectionCheck->stop(); //stop while scanning. netScan( NetParams ); if (netList->childCount() > 0) { TQTimer::singleShot( 0, this, TQT_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 "" essid = ""; else continue; //some cards report one '' essid even when no network's present. Workaround. } if (essid=="") { 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(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(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(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( 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( 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("

Can not connect to network '%1'.

The network you are trying to connect to requires WPA authentication. The necessary executables wpa_supplicant and wpa_cli could not be found. Install wpa_supplicant and restart Wireless Assistant to connect.

").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=="") || (!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(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 ""; } 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(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("

You are about to disconnect from '%1'.

Would you like to continue?

").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(lvi)-> ap() == ap ) { break; } lvi = lvi->nextSibling(); } return lvi; } TQListViewItem* WirelessAssistant::getItemByEssid( const TQString & essid ) { TQListViewItem* lvi = netList->firstChild(); while (lvi) { if ( static_cast(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, TQT_SIGNAL(selectionChanged(TQListViewItem*)), this, TQT_SLOT(updateConnectButton(TQListViewItem*)) ); disconnect( netList, TQT_SIGNAL(doubleClicked(TQListViewItem*, const TQPoint &, int)), this, TQT_SLOT(itemAction()) ); connect( netList, TQT_SIGNAL(clicked(TQListViewItem*, const TQPoint &, int)), this, TQT_SLOT(itemAction()) ); buttonConnect->hide(); } else { disconnect( netList, TQT_SIGNAL(clicked(TQListViewItem*, const TQPoint &, int)), this, TQT_SLOT(itemAction()) ); connect( netList, TQT_SIGNAL(selectionChanged(TQListViewItem*)), this, TQT_SLOT(updateConnectButton(TQListViewItem*)) ); connect( netList, TQT_SIGNAL(doubleClicked(TQListViewItem*, const TQPoint &, int)), this, TQT_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( TQT_TQOBJECT(this) ); p->setArguments( cmd ); p->start(); if (detached) { p = 0; return TQString(); } TQTimer* timerProc = new TQTimer(); //timeout timer if ( timeout>0 && !detached ) { connect( timerProc, TQT_SIGNAL(timeout()), p, TQT_SLOT(kill()) ); timerProc->start(timeout*1000); //convert sec to msec } connect(buttonClose, TQT_SIGNAL(clicked()), p, TQT_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, TQT_SIGNAL(clicked()), this, TQT_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, TQT_SIGNAL(clicked()), p, TQT_SLOT(kill()) ); if (i>27) {//set 'stop' back to 'close' if needed connect(buttonClose, TQT_SIGNAL(clicked()), this, TQT_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(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, TQT_SLOT(netDisconnect()) ); //icm->insertItem( SmallIcon("reload"), i18n("Reconnect"), this, TQT_SLOT(netConnect()) ); } else icm->insertItem( SmallIcon("connect_creating"), i18n("Connect"), this, TQT_SLOT(netConnect()) ); icm->insertSeparator(); icm->insertItem(i18n("Forget Settings..."), this, TQT_SLOT(removeNetParams()) ); icm->insertItem(i18n("Edit Settings..."), this, TQT_SLOT(editNetParams()) ); } else { if (nvi->isConnected()) { icm->insertItem( SmallIcon("connect_no"), i18n("Disconnect..."), this, TQT_SLOT(netDisconnect()) ); //icm->insertItem( SmallIcon("reload"), i18n("Configure and Reconnect..."), this, TQT_SLOT(netConnect()) ); } else icm->insertItem( SmallIcon("connect_creating"), i18n("Configure and Connect..."), this, TQT_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( TQT_TQOBJECT(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"