/* ksim - a system monitor for kde * * Copyright (C) 2001 Robbie Ward * * 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 #include #include #include #ifdef __FreeBSD__ #include #include #include #include #include #include static int mib[] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ksimnet.h" #include "netconfig.h" #include #define NET_UPDATE 1000 #define LED_UPDATE 125 KSIM_INIT_PLUGIN(NetPlugin) NetPlugin::NetPlugin(const char *name) : KSim::PluginObject(name) { setConfigFileName(instanceName()); } NetPlugin::~NetPlugin() { } KSim::PluginView *NetPlugin::createView(const char *className) { return new NetView(this, className); } KSim::PluginPage *NetPlugin::createConfigPage(const char *className) { return new NetConfig(this, className); } void NetPlugin::showAbout() { TQString version = kapp->aboutData()->version(); KAboutData aboutData(instanceName(), I18N_NOOP("KSim Net Plugin"), version.latin1(), I18N_NOOP("A net plugin for KSim"), KAboutData::License_GPL, "(C) 2001 Robbie Ward"); aboutData.addAuthor("Robbie Ward", I18N_NOOP("Author"), "linuxphreak@gmx.co.uk"); aboutData.addAuthor("Heitham Omar", I18N_NOOP("FreeBSD ports"), "super_ice@ntlworld.com"); KAboutApplication(&aboutData).exec(); } NetView::NetView(KSim::PluginObject *parent, const char *name) : KSim::PluginView(parent, name) { #ifdef __linux__ m_procStream = 0L; if ((m_procFile = fopen("/proc/net/dev", "r"))) m_procStream = new TQTextStream(m_procFile, IO_ReadOnly); #endif #ifdef __FreeBSD__ m_buf = 0; m_allocSize = 0; #endif m_firstTime = true; m_netLayout = new TQVBoxLayout(this); m_networkList = createList(); addDisplay(); m_netTimer = new TQTimer(this); connect(m_netTimer, TQT_SIGNAL(timeout()), TQT_SLOT(updateGraph())); m_netTimer->start(NET_UPDATE); m_lightTimer = new TQTimer(this); connect(m_lightTimer, TQT_SIGNAL(timeout()), TQT_SLOT(updateLights())); m_lightTimer->start(LED_UPDATE); updateGraph(); } NetView::~NetView() { #ifdef __linux__ delete m_procStream; if (m_procFile) fclose(m_procFile); #endif cleanup(); } void NetView::reparseConfig() { Network::List networkList = createList(); if ( networkList == m_networkList ) return; m_netTimer->stop(); m_lightTimer->stop(); m_firstTime = true; cleanup(); m_networkList = networkList; addDisplay(); m_netTimer->start(NET_UPDATE); m_lightTimer->start(LED_UPDATE); } void NetView::cleanup() { Network::List::Iterator it; for ( it = m_networkList.begin(); it != m_networkList.end(); ++it ) { ( *it ).cleanup(); } m_networkList.clear(); } void NetView::addDisplay() { int i = 0; Network::List::Iterator it; for ( it = m_networkList.begin(); it != m_networkList.end(); ++it ) { KSim::LedLabel *led = addLedLabel( ( *it ).name() ); KSim::Label *label = ( ( *it ).showTimer() ? addLabel() : 0L ); TQPopupMenu * popup = ( ( *it ).commandsEnabled() ? addPopupMenu( ( *it ).name(), i ) : 0L ); KSim::Chart *chart = addChart(); //KSim::LedLabel *led = addLedLabel( ( *it ).name() ); //KSim::Label *label = ( ( *it ).showTimer() ? addLabel() : 0L ); //TQPopupMenu * popup = ( ( *it ).commandsEnabled() ? //addPopupMenu( ( *it ).name(), i ) : 0L ); if ( ( *it ).commandsEnabled() ) { if ( chart ) { chart->installEventFilter( this ); } if ( led ) { led->installEventFilter( this ); } if ( label ) { label->installEventFilter( this ); } } ( *it ).setDisplay( chart, led, label, popup ); ++i; } } // Run the connect command void NetView::runConnectCommand( int value ) { int i = 0; Network::List::ConstIterator it; for ( it = m_networkList.begin(); it != m_networkList.end(); ++it ) { if ( value == i ) { // I use KRun here as it provides startup notification if ( !( *it ).connectCommand().isNull() ) { KRun::runCommand( ( *it ).connectCommand() ); } break; } ++i; } } // Run the disconnect command void NetView::runDisconnectCommand( int value ) { int i = 0; Network::List::ConstIterator it; for ( it = m_networkList.begin(); it != m_networkList.end(); ++it ) { if ( value == i ) { // I use KRun here as it provides startup notification if ( !( *it ).disconnectCommand().isNull() ) { KRun::runCommand( ( *it ).disconnectCommand() ); } break; } ++i; } } Network::List NetView::createList() const { config()->setGroup( "Net" ); int amount = config()->readNumEntry( "deviceAmount", 0 ); Network::List list; for ( int i = 0; i < amount; ++i ) { if ( !config()->hasGroup( "device-" + TQString::number( i ) ) ) { continue; } config()->setGroup( "device-" + TQString::number( i ) ); list.append( Network( config()->readEntry( "deviceName" ), config()->readEntry( "deviceFormat" ), config()->readBoolEntry( "showTimer" ), config()->readBoolEntry( "commands" ), config()->readEntry( "cCommand" ), config()->readEntry("dCommand") ) ); } qHeapSort( list ); return list; } void NetView::updateLights() { Network::List::Iterator it; for ( it = m_networkList.begin(); it != m_networkList.end(); ++it ) { if ( isOnline( ( *it ).name() ) ) { unsigned long receiveDiff = ( *it ).data().in - ( *it ).oldData().in; unsigned long sendDiff = ( *it ).data().out - ( *it ).oldData().out; unsigned long halfMax = ( *it ).maxValue() / 2; ( *it ).led()->setMaxValue( ( *it ).maxValue() / 1024 ); ( *it ).led()->setValue( receiveDiff / 1024 ); if ( receiveDiff == 0 ) { ( *it ).led()->setOff( KSim::Led::First ); } else if ( ( receiveDiff / 1024 ) >= halfMax ) { ( *it ).led()->setOn( KSim::Led::First ); } else { ( *it ).led()->toggle( KSim::Led::First ); } if ( sendDiff == 0 ) { ( *it ).led()->setOff( KSim::Led::Second ); } else if ( ( sendDiff / 1024 ) >= halfMax ) { ( *it ).led()->setOn( KSim::Led::Second ); } else { ( *it ).led()->toggle( KSim::Led::Second ); } } else { ( *it ).led()->setMaxValue( 0 ); ( *it ).led()->setValue( 0 ); ( *it ).led()->setOff( KSim::Led::First ); ( *it ).led()->setOff( KSim::Led::Second ); } } } void NetView::updateGraph() { int timer = 0; int hours = 0; int minutes = 0; int seconds = 0; time_t start = 0; struct stat st; TQTime netTime; TQString timeDisplay; TQString pid( "/var/run/%1.pid" ); TQString newPid; Network::List::Iterator it; for ( it = m_networkList.begin(); it != m_networkList.end(); ++it ) { if ( isOnline( ( *it ).name() ) ) { NetData data; if ( ( *it ).label() ) { timeDisplay = ( *it ).format(); newPid = pid.tqarg( ( *it ).name() ); if ( TQFile::exists( newPid ) && stat( TQFile::encodeName( newPid ).data(), &st ) == 0 ) { start = st.st_mtime; timer = static_cast( difftime( time( 0 ), start ) ); hours = timer / 3600; minutes = (timer - hours * 3600) / 60; seconds = timer % 60; if ( netTime.isValid( hours, minutes, seconds ) ) netTime.setHMS( hours, minutes, seconds ); } // Keep backwards compat for now if ( timeDisplay.contains( '%' ) > 0 ) timeDisplay.replace( '%', "" ); ( *it ).label()->setText( netTime.toString( timeDisplay ) ); } netStatistics( ( *it ).name(), data ); ( *it ).setData( data ); unsigned long receiveDiff = data.in - ( *it ).oldData().in; unsigned long sendDiff = data.out - ( *it ).oldData().out; if ( m_firstTime ) { receiveDiff = sendDiff = 0; } ( *it ).chart()->setValue( receiveDiff, sendDiff ); ( *it ).setMaxValue( ( *it ).chart()->maxValue() ); TQString receiveString = KGlobal::locale()->formatNumber( ( float ) receiveDiff / 1024.0, 1 ); TQString sendString = KGlobal::locale()->formatNumber( ( float ) sendDiff / 1024.0, 1 ); ( *it ).chart()->setText( i18n( "in: %1k" ).tqarg( receiveString ), i18n( "out: %1k" ).tqarg( sendString ) ); } else { ( *it ).setData( NetData() ); ( *it ).chart()->setValue( 0, 0 ); ( *it ).chart()->setText( i18n( "in: %1k" ).tqarg( KGlobal::locale()->formatNumber( 0.0, 1 ) ), i18n( "out: %1k" ).tqarg( KGlobal::locale()->formatNumber( 0.0, 1 ) ) ); if ( ( *it ).label() ) ( *it ).label()->setText( i18n( "offline" ) ); } } if ( m_firstTime ) m_firstTime = false; } KSim::Chart *NetView::addChart() { KSim::Chart *chart = new KSim::Chart(false, 0, this); m_netLayout->addWidget(chart); chart->show(); return chart; } KSim::LedLabel *NetView::addLedLabel(const TQString &device) { KSim::LedLabel *ledLabel = new KSim::LedLabel(0, KSim::Types::Net, device, this); ledLabel->show(); m_netLayout->addWidget(ledLabel); return ledLabel; } KSim::Label *NetView::addLabel() { KSim::Label *label = new KSim::Label(KSim::Types::None, this); label->show(); m_netLayout->addWidget(label); return label; } TQPopupMenu *NetView::addPopupMenu(const TQString &device, int value) { TQPopupMenu *popup = new TQPopupMenu(this); popup->insertItem(SmallIcon("network"), i18n("Connect"), this, TQT_SLOT(runConnectCommand(int)), 0, 1); popup->setItemParameter(1, value); popup->insertItem(SmallIcon("network"), i18n("Disconnect"), this, TQT_SLOT(runDisconnectCommand(int)), 0, 2); popup->setItemParameter(2, value); menu()->insertItem(device, popup, 100 + value); return popup; } void NetView::netStatistics(const TQString &device, NetData &data) { #ifdef __linux__ if (m_procFile == 0) { data.in = 0; data.out = 0; return; } TQString output; TQString parser; // Parse the proc file while (!m_procStream->atEnd()) { parser = m_procStream->readLine(); // remove all the entries apart from the line containing 'device' if (parser.find(device) != -1) output = parser; } if (output.isEmpty()) { data.in = 0; data.out = 0; return; } // make sure our output doesn't contain "eth0:11210107" so we dont // end up with netList[1] actually being netList[2] output.replace(TQRegExp(":"), " "); TQStringList netList = TQStringList::split(' ', output); data.in = netList[1].toULong(); data.out = netList[9].toULong(); fseek(m_procFile, 0L, SEEK_SET); #endif #ifdef __FreeBSD__ struct if_msghdr *ifm, *nextifm; struct sockaddr_dl *sdl; char *lim, *next; size_t needed; char s[32]; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return; if (m_allocSize < needed) { if (m_buf != NULL) delete[] m_buf; m_buf = new char[needed]; if (m_buf == NULL) return; m_allocSize = needed; } if (sysctl(mib, 6, m_buf, &needed, NULL, 0) < 0) return; lim = m_buf + needed; next = m_buf; while (next < lim) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type != RTM_IFINFO) return; next += ifm->ifm_msglen; // get an interface with a network address while (next < lim) { nextifm = (struct if_msghdr *)next; if (nextifm->ifm_type != RTM_NEWADDR) break; next += nextifm->ifm_msglen; } // if the interface is up if (ifm->ifm_flags & IFF_UP) { sdl = (struct sockaddr_dl *)(ifm + 1); if (sdl->sdl_family != AF_LINK) continue; strncpy(s, sdl->sdl_data, sdl->sdl_nlen); s[sdl->sdl_nlen] = '\0'; if (strcmp(device.local8Bit().data(), s) == 0) { data.in = ifm->ifm_data.ifi_ibytes; data.out = ifm->ifm_data.ifi_obytes; return; } } } #endif } bool NetView::isOnline(const TQString &device) { #ifdef __linux__ TQFile file("/proc/net/route"); if (!file.open(IO_ReadOnly)) return -1; return (TQTextStream(&file).read().find(device) != -1 ? true : false); #endif #ifdef __FreeBSD__ struct if_msghdr *ifm, *nextifm; struct sockaddr_dl *sdl; char *lim, *next; size_t needed; char s[32]; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) return false; if (m_allocSize < needed) { if (m_buf != NULL) delete[] m_buf; m_buf = new char[needed]; if (m_buf == NULL) return false; m_allocSize = needed; } if (sysctl(mib, 6, m_buf, &needed, NULL, 0) < 0) return false; lim = m_buf + needed; next = m_buf; while (next < lim) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type != RTM_IFINFO) return false; next += ifm->ifm_msglen; // get an interface with a network address while (next < lim) { nextifm = (struct if_msghdr *)next; if (nextifm->ifm_type != RTM_NEWADDR) break; next += nextifm->ifm_msglen; } // if the interface is up if (ifm->ifm_flags & IFF_UP) { sdl = (struct sockaddr_dl *)(ifm + 1); if (sdl->sdl_family != AF_LINK) continue; strncpy(s, sdl->sdl_data, sdl->sdl_nlen); s[sdl->sdl_nlen] = '\0'; if (strcmp(s, device.local8Bit().data()) == 0) return true; } } return false; #endif } // EventFilter bool NetView::eventFilter( TQObject * o, TQEvent * e ) { // find out which interface we are int i = 0; Network::List::Iterator it; for ( it = m_networkList.begin(); it != m_networkList.end(); ++it ) { if ( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(( *it ).chart()) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(( *it ).label()) || TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(( *it ).led()) ) { break; } ++i; } if ( e->type() == TQEvent::MouseButtonPress ) { if ( TQT_TQMOUSEEVENT( e )->button() == Qt::RightButton ) { showMenu(i); } return true; } return false; } void NetView::showMenu(int i) { TQPopupMenu menu; menu.insertItem( SmallIcon("network"), i18n("Connect"), 1); menu.insertItem( SmallIcon("network"), i18n("Disconnect"), 2); switch (menu.exec(TQCursor::pos())) { case 1: runConnectCommand(i); break; case 2: runDisconnectCommand(i); break; } } #include "ksimnet.moc"