networkscanner.cpp

00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2001-2002 Michael Goffioul <kdeprint@swing.be>
00004  *
00005  *  This library is free software; you can redistribute it and/or
00006  *  modify it under the terms of the GNU Library General Public
00007  *  License version 2 as published by the Free Software Foundation.
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #define USE_QSOCKET
00021 
00022 #include "networkscanner.h"
00023 
00024 #include <qprogressbar.h>
00025 #include <kpushbutton.h>
00026 #include <qlayout.h>
00027 #include <qtimer.h>
00028 #include <qlabel.h>
00029 #include <qcombobox.h>
00030 #include <qlineedit.h>
00031 #include <qregexp.h>
00032 #include <qsocket.h>
00033 #include <klocale.h>
00034 #include <kextendedsocket.h>
00035 #include <kmessagebox.h>
00036 #include <knumvalidator.h>
00037 #include <kdebug.h>
00038 #include <unistd.h>
00039 
00040 class NetworkScanner::NetworkScannerPrivate
00041 {
00042 public:
00043     int port;
00044     QString prefixaddress;
00045     int currentaddress;
00046     int timeout;
00047     bool scanning;
00048     QPtrList<NetworkScanner::SocketInfo> printers;
00049 
00050     QProgressBar *bar;
00051     KPushButton *scan, *settings;
00052     QLabel *subnetlab;
00053     QTimer *timer;
00054 #ifdef USE_QSOCKET
00055     QSocket *socket;
00056 #else
00057     KExtendedSocket *socket;
00058 #endif
00059 
00060     NetworkScannerPrivate( int portvalue ) : port( portvalue )
00061     {
00062         prefixaddress = localPrefix();
00063         currentaddress = 1;
00064         timeout = 50;
00065         scanning = false;
00066         printers.setAutoDelete( true );
00067     }
00068     QString localPrefix();
00069     QString scanString();
00070 };
00071 
00072 QString NetworkScanner::NetworkScannerPrivate::localPrefix()
00073 {
00074     char    buf[256];
00075     buf[0] = '\0';
00076     if (!gethostname(buf, sizeof(buf)))
00077         buf[sizeof(buf)-1] = '\0';
00078     QPtrList<KAddressInfo>  infos = KExtendedSocket::lookup(buf, QString::null);
00079     infos.setAutoDelete(true);
00080     if (infos.count() > 0)
00081     {
00082         QString IPstr = infos.first()->address()->nodeName();
00083         int p = IPstr.findRev('.');
00084         IPstr.truncate(p);
00085         return IPstr;
00086     }
00087     return QString::null;
00088 }
00089 
00090 QString NetworkScanner::NetworkScannerPrivate::scanString()
00091 {
00092     QString s = prefixaddress + ".*";
00093     if ( port != -1 )
00094         s.append( ":" ).append( QString::number( port ) );
00095     return s;
00096 }
00097 
00098 NetworkScanner::NetworkScanner( int port, QWidget *parent, const char *name )
00099     : QWidget( parent, name )
00100 {
00101     d = new NetworkScannerPrivate( port );
00102     d->bar = new QProgressBar( 256, this );
00103     d->settings = new KPushButton( KGuiItem( i18n( "&Settings" ), "configure" ), this );
00104     d->scan = new KPushButton( KGuiItem( i18n( "Sc&an" ), "viewmag" ), this );
00105     d->timer = new QTimer( this );
00106 #ifdef USE_QSOCKET
00107     d->socket = new QSocket( this );
00108 #else
00109     d->socket = new KExtendedSocket();
00110 #endif
00111     QLabel *label = new QLabel( i18n( "Network scan:" ), this );
00112     d->subnetlab = new QLabel( i18n( "Subnet: %1" ).arg( d->scanString() ), this );
00113 
00114     QGridLayout *l0 = new QGridLayout( this, 4, 2, 0, 10 );
00115     l0->addMultiCellWidget( label, 0, 0, 0, 1 );
00116     l0->addMultiCellWidget( d->bar, 1, 1, 0, 1 );
00117     l0->addMultiCellWidget( d->subnetlab, 2, 2, 0, 1 );
00118     l0->addWidget( d->settings, 3, 0 );
00119     l0->addWidget( d->scan, 3, 1 );
00120 
00121     connect( d->timer, SIGNAL( timeout() ), SLOT( slotTimeout() ) );
00122     connect( d->settings, SIGNAL( clicked() ), SLOT( slotSettingsClicked() ) );
00123     connect( d->scan, SIGNAL( clicked() ), SLOT( slotScanClicked() ) );
00124 #ifdef USE_QSOCKET
00125     connect( d->socket, SIGNAL( connected() ), SLOT( slotConnectionSuccess() ) );
00126     connect( d->socket, SIGNAL( error( int ) ), SLOT( slotConnectionFailed( int ) ) );
00127 #else
00128     connect( d->socket, SIGNAL( connectionSuccess() ), SLOT( slotConnectionSuccess() ) );
00129     connect( d->socket, SIGNAL( connectionFailed( int ) ), SLOT( slotConnectionFailed( int ) ) );
00130 #endif
00131 }
00132 
00133 NetworkScanner::~NetworkScanner()
00134 {
00135 #ifndef USE_QSOCKET
00136     delete d->socket;
00137 #endif
00138     delete d;
00139 }
00140 
00141 void NetworkScanner::start()
00142 {
00143     if ( d->scanning )
00144         return;
00145 
00146     d->printers.clear();
00147     emit scanStarted();
00148     d->settings->setEnabled( false );
00149     d->scan->setGuiItem( KGuiItem( i18n( "&Abort" ), "stop" ) );
00150     d->currentaddress = -1;
00151     d->scanning = true;
00152     next();
00153 }
00154 
00155 void NetworkScanner::slotScanClicked()
00156 {
00157     if ( !d->scanning )
00158     {
00159         if ( d->localPrefix() == d->prefixaddress ||
00160                 KMessageBox::warningContinueCancel( this->parentWidget(),
00161                     i18n( "You are about to scan a subnet (%1.*) that does not "
00162                           "correspond to the current subnet of this computer (%2.*). Do you want "
00163                           "to scan the specified subnet anyway?" ).arg( d->prefixaddress ).arg( d->localPrefix() ),
00164                     QString::null, KGuiItem( i18n( "&Scan" ), "viewmag" ), "askForScan" ) == KMessageBox::Continue )
00165             start();
00166     }
00167     else
00168     {
00169 #ifdef USE_QSOCKET
00170         d->socket->close();
00171 #else
00172         d->socket->cancelAsyncConnect();
00173 #endif
00174         finish();
00175     }
00176 }
00177 
00178 void NetworkScanner::finish()
00179 {
00180     if ( !d->scanning )
00181         return;
00182 
00183     d->settings->setEnabled( true );
00184     d->scan->setGuiItem( KGuiItem( i18n( "Sc&an" ), "viewmag" ) );
00185     d->bar->reset();
00186     d->scanning = false;
00187     emit scanFinished();
00188 }
00189 
00190 void NetworkScanner::slotSettingsClicked()
00191 {
00192     NetworkScannerConfig dlg( this );
00193     dlg.exec();
00194 }
00195 
00196 void NetworkScanner::slotNext()
00197 {
00198     if ( !d->scanning )
00199         return;
00200 
00201     d->timer->stop();
00202 #ifdef USE_QSOCKET
00203     d->socket->connectToHost( d->prefixaddress + "." + QString::number( d->currentaddress ), d->port );
00204     kdDebug() << "Address: " << d->socket->peerName() << ", Port: " << d->socket->peerPort() << endl;
00205 #else
00206     d->socket->setAddress( d->prefixaddress + "." + QString::number( d->currentaddress ), d->port );
00207     d->socket->startAsyncLookup();
00208     kdDebug() << "Address: " << d->socket->host() << ", Port: " << d->socket->port() << endl;
00209 #endif
00210     d->timer->start( d->timeout, true );
00211 }
00212 
00213 void NetworkScanner::next()
00214 {
00215     //kdDebug() << "Next" << endl;
00216     d->currentaddress++;
00217     if ( d->currentaddress >= 256 )
00218         finish();
00219     else
00220     {
00221         d->bar->setProgress( d->currentaddress );
00222         QTimer::singleShot( 0, this, SLOT( slotNext() ) );
00223     }
00224 }
00225 
00226 void NetworkScanner::slotTimeout()
00227 {
00228     kdDebug() << "Timeout" << endl;
00229     if ( !d->scanning )
00230         return;
00231 
00232 #ifdef USE_QSOCKET
00233     d->socket->close();
00234 #else
00235     d->socket->cancelAsyncConnect();
00236 #endif
00237     next();
00238 }
00239 
00240 void NetworkScanner::slotConnectionSuccess()
00241 {
00242     kdDebug() << "Success" << endl;
00243 #ifdef USE_QSOCKET
00244     KSocketAddress *addr = KExtendedSocket::peerAddress( d->socket->socket() );
00245 #else
00246     KSocketAddress *addr = const_cast<KSocketAddress*>( d->socket->peerAddress() );
00247 #endif
00248     kdDebug() << "Connection success: " << ( addr ? addr->pretty() : QString( "ERROR" ) ) << endl;
00249     kdDebug() << "Socket: " << d->socket->socket() << endl;
00250     if ( addr )
00251     {
00252         SocketInfo *info = new SocketInfo;
00253 #ifdef USE_QSOCKET
00254         info->IP = d->socket->peerName();
00255 #else
00256         info->IP = d->socket->host();
00257 #endif
00258         info->Port = d->port;
00259         QString portname;
00260         KExtendedSocket::resolve( addr, info->Name, portname );
00261         d->printers.append( info );
00262         d->socket->close();
00263         delete addr;
00264     }
00265     else
00266         kdDebug() << "Unconnected socket, skipping" << endl;
00267     next();
00268 }
00269 
00270 void NetworkScanner::slotConnectionFailed( int )
00271 {
00272     kdDebug() << "Failure" << endl;
00273     next();
00274 }
00275 
00276 const QPtrList<NetworkScanner::SocketInfo>* NetworkScanner::printerList()
00277 {
00278     return &( d->printers );
00279 }
00280 
00281 int NetworkScanner::timeout() const
00282 {
00283     return d->timeout;
00284 }
00285 
00286 void NetworkScanner::setTimeout( int to )
00287 {
00288     d->timeout = to;
00289 }
00290 
00291 QString NetworkScanner::subnet() const
00292 {
00293     return d->prefixaddress;
00294 }
00295 
00296 void NetworkScanner::setSubnet( const QString& sn )
00297 {
00298     d->prefixaddress = sn;
00299     d->subnetlab->setText( i18n( "Subnet: %1" ).arg( d->scanString() ) );
00300 }
00301 
00302 int NetworkScanner::port() const
00303 {
00304     return d->port;
00305 }
00306 
00307 void NetworkScanner::setPort( int p )
00308 {
00309     d->port = p;
00310     d->subnetlab->setText( i18n( "Subnet: %1" ).arg( d->scanString() ) );
00311 }
00312 
00313 bool NetworkScanner::checkPrinter( const QString& host, int port )
00314 {
00315     // try first to find it in the SocketInfo list
00316     QPtrListIterator<NetworkScanner::SocketInfo> it( d->printers );
00317     for ( ; it.current(); ++it )
00318     {
00319         if ( port == it.current()->Port && ( host == it.current()->IP ||
00320                     host == it.current()->Name ) )
00321             return true;
00322     }
00323 
00324     // not found in SocketInfo list, try to establish connection
00325     KExtendedSocket extsock( host, port );
00326     extsock.setBlockingMode( false );
00327     extsock.setTimeout( 0, d->timeout * 1000 );
00328     return ( extsock.connect() == 0 );
00329 }
00330 
00331 NetworkScannerConfig::NetworkScannerConfig(NetworkScanner *scanner, const char *name)
00332     : KDialogBase(scanner, name, true, QString::null, Ok|Cancel, Ok, true)
00333 {
00334     scanner_ = scanner;
00335     QWidget *dummy = new QWidget(this);
00336     setMainWidget(dummy);
00337         KIntValidator *val = new KIntValidator( this );
00338     QLabel  *masklabel = new QLabel(i18n("&Subnetwork:"),dummy);
00339     QLabel  *portlabel = new QLabel(i18n("&Port:"),dummy);
00340     QLabel  *toutlabel = new QLabel(i18n("&Timeout (ms):"),dummy);
00341     QLineEdit   *mm = new QLineEdit(dummy);
00342     mm->setText(QString::fromLatin1(".[0-255]"));
00343     mm->setReadOnly(true);
00344     mm->setFixedWidth(fontMetrics().width(mm->text())+10);
00345 
00346     mask_ = new QLineEdit(dummy);
00347     mask_->setAlignment(Qt::AlignRight);
00348     port_ = new QComboBox(true,dummy);
00349         if ( port_->lineEdit() )
00350             port_->lineEdit()->setValidator( val );
00351     tout_ = new QLineEdit(dummy);
00352         tout_->setValidator( val );
00353 
00354     masklabel->setBuddy(mask_);
00355     portlabel->setBuddy(port_);
00356     toutlabel->setBuddy(tout_);
00357 
00358     mask_->setText(scanner_->subnet());
00359     port_->insertItem("631");
00360     port_->insertItem("9100");
00361     port_->insertItem("9101");
00362     port_->insertItem("9102");
00363     port_->setEditText(QString::number(scanner_->port()));
00364     tout_->setText(QString::number(scanner_->timeout()));
00365 
00366     QGridLayout *main_ = new QGridLayout(dummy, 3, 2, 0, 10);
00367     QHBoxLayout *lay1 = new QHBoxLayout(0, 0, 5);
00368     main_->addWidget(masklabel, 0, 0);
00369     main_->addWidget(portlabel, 1, 0);
00370     main_->addWidget(toutlabel, 2, 0);
00371     main_->addLayout(lay1, 0, 1);
00372     main_->addWidget(port_, 1, 1);
00373     main_->addWidget(tout_, 2, 1);
00374     lay1->addWidget(mask_,1);
00375     lay1->addWidget(mm,0);
00376 
00377     resize(250,130);
00378     setCaption(i18n("Scan Configuration"));
00379 }
00380 
00381 NetworkScannerConfig::~NetworkScannerConfig()
00382 {
00383 }
00384 
00385 void NetworkScannerConfig::slotOk()
00386 {
00387     QString msg;
00388     QRegExp re("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})");
00389     if (!re.exactMatch(mask_->text()))
00390         msg = i18n("Wrong subnetwork specification.");
00391     else
00392     {
00393         for (int i=1; i<=3; i++)
00394             if (re.cap(i).toInt() >= 255)
00395             {
00396                 msg = i18n("Wrong subnetwork specification.");
00397                 break;
00398             }
00399     }
00400 
00401     bool    ok(false);
00402     int     v = tout_->text().toInt(&ok);
00403     if (!ok || v <= 0)
00404         msg = i18n("Wrong timeout specification.");
00405     v = port_->currentText().toInt(&ok);
00406     if (!ok || v <= 0)
00407         msg = i18n("Wrong port specification.");
00408     if (!msg.isEmpty())
00409     {
00410         KMessageBox::error(this,msg);
00411         return;
00412     }
00413 
00414     scanner_->setTimeout( tout_->text().toInt() );
00415     scanner_->setSubnet( mask_->text() );
00416     scanner_->setPort( port_->currentText().toInt() );
00417 
00418     KDialogBase::slotOk();
00419 }
00420 
00421 #include "networkscanner.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys