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.
smb4k/smb4k/core/smb4kscanner.cpp

1721 lines
48 KiB

/***************************************************************************
smb4kscanner.cpp - The network scan core class of Smb4K.
-------------------
begin : Sam Mai 31 2003
copyright : (C) 2003-2007 by Alexander Reinholdt
email : dustpuppy@users.berlios.de
***************************************************************************/
/***************************************************************************
* 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 *
***************************************************************************/
// TQt includes
#include <tqapplication.h>
#include <tqmap.h>
#include <tqdeepcopy.h>
// KDE includes
#include <klocale.h>
#include <kapplication.h>
#include <kdebug.h>
#include <ksocketaddress.h>
// system includes
#include <stdlib.h>
// Application specific includes.
#include "smb4kscanner.h"
#include "smb4kscanner_p.h"
#include "smb4kauthinfo.h"
#include "smb4kerror.h"
#include "smb4kglobal.h"
#include "smb4ksambaoptionshandler.h"
#include "smb4kpasswordhandler.h"
#include "smb4knetworkitems.h"
#include "smb4ksettings.h"
using namespace Smb4KGlobal;
static bool created_workgroups_list = false;
static bool created_hosts_list = false;
Smb4KScanner::Smb4KScanner( TQValueList<Smb4KWorkgroupItem *> *workgroups, TQValueList<Smb4KHostItem *> *hosts,
TQObject *parent, const char *name )
: TQObject( parent, name ), m_workgroups_list( workgroups ), m_hosts_list( hosts )
{
m_priv = new Smb4KScannerPrivate;
if ( !m_workgroups_list )
{
created_workgroups_list = true;
m_workgroups_list = new TQValueList<Smb4KWorkgroupItem *>;
}
else
{
// The list was passed to the constructor from outside.
}
if ( !m_hosts_list )
{
created_hosts_list = true;
m_hosts_list = new TQValueList<Smb4KHostItem *>;
}
else
{
// The list was passed to the constructor from outside.
}
m_proc = new KProcess( this, "ScannerMainProcess" );
m_proc->setUseShell( true );
m_working = false;
m_queue.setAutoDelete( true );
connect( m_proc, TQT_SIGNAL( receivedStdout( KProcess *, char *, int ) ),
this, TQT_SLOT( slotReceivedStdout( KProcess *, char *, int ) ) );
connect( m_proc, TQT_SIGNAL( processExited( KProcess* ) ),
this, TQT_SLOT( slotProcessExited( KProcess * ) ) );
connect( m_proc, TQT_SIGNAL( receivedStderr( KProcess *, char *, int ) ),
this, TQT_SLOT( slotReceivedStderr( KProcess *, char *, int ) ) );
}
Smb4KScanner::~Smb4KScanner()
{
abort();
// Delete the list of workgroups, if necessary:
if ( created_workgroups_list )
{
for ( TQValueList<Smb4KWorkgroupItem *>::Iterator it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it )
{
delete *it;
}
m_workgroups_list->clear();
delete m_workgroups_list;
}
else
{
// The list of workgroups is handled outside of this class.
}
// Delete the list of hosts, if necessary:
if ( created_hosts_list )
{
for ( TQValueList<Smb4KHostItem *>::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it )
{
delete *it;
}
m_hosts_list->clear();
delete m_hosts_list;
}
else
{
// The list of hosts is handled outside of this class.
}
delete m_priv;
}
void Smb4KScanner::init()
{
m_timer_id = startTimer( TIMER_INTERVAL );
rescan();
}
void Smb4KScanner::rescan()
{
m_queue.enqueue( new TQString( TQString( "%1:" ).arg( Init ) ) );
}
/****************************************************************************
Scans for workgroup members. (public part)
****************************************************************************/
void Smb4KScanner::getWorkgroupMembers( const TQString &workgroup, const TQString &master, const TQString &ip )
{
m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Hosts ).arg( workgroup, master, ip ) ) );
}
/****************************************************************************
Scans for shares on a selected host. (public part)
****************************************************************************/
void Smb4KScanner::getShares( const TQString &workgroup, const TQString &host, const TQString &ip, const TQString &protocol )
{
m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4:%5" ).arg( Shares ).arg( workgroup, host, ip ).arg( protocol ) ) );
}
/****************************************************************************
Gets more info on a selected host. (public part)
****************************************************************************/
void Smb4KScanner::getInfo( const TQString &workgroup, const TQString &host, const TQString &ip )
{
Smb4KHostItem *item = getHost( host, workgroup );
if ( item && item->infoChecked() )
{
emit info( item );
return;
}
else
{
// Avoid several queueing up:
item->setInfoChecked( true );
}
m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Info ).arg( workgroup, host, ip ) ) );
}
/****************************************************************************
Searches for a host. (public part)
****************************************************************************/
void Smb4KScanner::search( const TQString &host )
{
// Check whether we already have this host in
// the list:
Smb4KHostItem *item = getHost( host );
if ( item )
{
emit searchResult( item );
return;
}
m_queue.enqueue( new TQString( TQString( "%1:%2" ).arg( Search ).arg( host ) ) );
}
/****************************************************************************
Aborts any process that is running.
****************************************************************************/
void Smb4KScanner::abort()
{
m_queue.clear();
if ( m_proc->isRunning() )
{
m_proc->kill();
}
}
/****************************************************************************
This function retrieves the initial browse list
****************************************************************************/
void Smb4KScanner::scanNetwork()
{
abort();
TQString command;
// Look up the workgroups/domains and their master browsers.
// At the moment we have three methods:
// (1) Smb4KSettings::EnumBrowseList::LookupDomains: This method is
// the most reliable one. It uses nmblookup and will only find
// *active* workgroup master browsers and thus active domains.
// (2) Smb4KSettings::EnumBrowseList::QueryCurrentMaster: This
// method will query the current master browser of the local
// workgroup/domain. This method is not as reliable as the first
// one, because you might get wrong (i. e. outdated) master
// browsers for the workgroups or even empty workgroups.
// (3) Smb4KSettings::EnumBrowseList::QueryCustomMaster: This method
// is similar to the second one, but the user has defined a fixed
// host name or IP address.
// (4) Smb4KSettings::EnumBrowseList::ScanBroadcastAreas: Scan the
// user given broadcast addresses for active hosts (IP scan)
switch ( Smb4KSettings::browseList() )
{
case Smb4KSettings::EnumBrowseList::LookupDomains:
{
command.append( "nmblookup -M " );
command.append( optionsHandler()->nmblookupOptions() );
command.append( " -- - | grep '<01>' | awk '{print $1}'" );
command.append( !optionsHandler()->winsServer().isEmpty() ?
TQString( " | xargs nmblookup -R -U %1 -A " ).arg( optionsHandler()->winsServer() ) :
" | xargs nmblookup -A " );
command.append( optionsHandler()->nmblookupOptions() );
*m_proc << command;
startProcess( Workgroups );
break;
}
case Smb4KSettings::EnumBrowseList::QueryCurrentMaster:
{
command.append( "net " );
command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::LookupMaster,
Smb4KSettings::domainName() ) );
command.append( " -U % | xargs net " );
command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::Domain,
TQString() ) );
command.append( " -U % -S" );
*m_proc << command;
startProcess( QueryHost );
break;
}
case Smb4KSettings::EnumBrowseList::QueryCustomMaster:
{
command.append( "net " );
command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::LookupHost,
Smb4KSettings::customMasterBrowser() ) );
command.append( " -U % -S "+KProcess::quote( Smb4KSettings::customMasterBrowser() ) );
command.append( " | xargs net " );
command.append( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::Domain,
TQString() ) );
command.append( " -U % -S "+KProcess::quote( Smb4KSettings::customMasterBrowser() )+" -I " );
*m_proc << command;
startProcess( QueryHost );
break;
}
case Smb4KSettings::EnumBrowseList::ScanBroadcastAreas:
{
// Get the broadcast addresses that are to be scanned:
TQStringList addresses = TQStringList::split( ",", Smb4KSettings::broadcastAreas(), false );
// Build the command:
for ( TQStringList::ConstIterator it = addresses.begin(); it != addresses.end(); ++it )
{
if ( !(*it).isEmpty() )
{
command.append( "nmblookup " );
// We want all globally defined options for nmblookup, except
// the broadcast address, because that is needed for the IP
// scan:
command.append( optionsHandler()->nmblookupOptions( false ) );
command.append( " -B "+*it+" -- '*' " );
command.append( "| sed -e /querying/d | awk '{print $1}' " );
command.append( "| xargs nmblookup " );
// This time we want to have the globally defined broadcast
// address:
command.append( optionsHandler()->nmblookupOptions() );
// Include the WINS server:
command.append( !optionsHandler()->winsServer().isEmpty() ?
" -R -U "+optionsHandler()->winsServer()+" " : "" );
command.append( " -A" );
command.append( " ; " );
continue;
}
else
{
continue;
}
}
// Get rid of the last 3 characters (" ; "):
command.truncate( command.length() - 3 );
*m_proc << command;
startProcess( IPScan );
break;
}
default:
{
break;
}
}
}
/****************************************************************************
Scans for workgroup members. (private part)
****************************************************************************/
void Smb4KScanner::scanForWorkgroupMembers( const TQString &workgroup, const TQString &master, const TQString &ip )
{
m_priv->setWorkgroup( workgroup );
m_priv->setHost( master );
m_priv->setIP( ip );
TQString command;
if ( !ip.isEmpty() )
{
command.append( "net "+optionsHandler()->netOptions( Smb4KSambaOptionsHandler::ServerDomain, TQString() ) );
command.append( " -I "+ip );
command.append( " -w "+KProcess::quote( workgroup ) );
command.append( " -S "+KProcess::quote( master ) );
Smb4KAuthInfo authInfo( workgroup, master, TQString() );
(void) passwordHandler()->readAuth( &authInfo );
if ( !authInfo.user().isEmpty() )
{
command.append( TQString( " -U %1" ).arg( KProcess::quote( authInfo.user() ) ) );
if ( !authInfo.password().isEmpty() )
{
m_proc->setEnvironment( "PASSWD", authInfo.password() );
}
}
else
{
command.append( " -U %" );
}
}
else
{
command.append( "net "+optionsHandler()->netOptions( Smb4KSambaOptionsHandler::LookupHost, KProcess::quote( master ) ) );
command.append( " -S "+KProcess::quote( master )+" -w "+KProcess::quote( workgroup )+" -U % " );
// FIXME: Maybe we need to know the shell if the user does not use a
// sh-compatible one...?
command.append( "| xargs -IIPADDR " );
command.append( getenv( "SHELL" ) );
command.append( " -c 'echo \"*** "+master+": IPADDR ***\" && " );
command.append( "net "+optionsHandler()->netOptions( Smb4KSambaOptionsHandler::ServerDomain, TQString() ) );
command.append( " -I IPADDR" );
command.append( " -w "+KProcess::quote( workgroup ) );
command.append( " -S "+KProcess::quote( master ) );
Smb4KAuthInfo authInfo( workgroup, master, TQString() );
(void) passwordHandler()->readAuth( &authInfo );
if ( !authInfo.user().isEmpty() )
{
command.append( TQString( " -U %1'" ).arg( KProcess::quote( authInfo.user() ) ) );
if ( !authInfo.password().isEmpty() )
{
m_proc->setEnvironment( "PASSWD", authInfo.password() );
}
}
else
{
command.append( " -U %'" );
}
}
*m_proc << command;
startProcess( Hosts );
}
/****************************************************************************
Scans for shares on a selected host. (private part)
****************************************************************************/
void Smb4KScanner::scanForShares( const TQString &workgroup, const TQString &host, const TQString &ip, const TQString &protocol )
{
m_priv->setWorkgroup( workgroup );
m_priv->setHost( host );
m_priv->setIP( ip );
Smb4KAuthInfo *auth = passwordHandler()->readAuth( new Smb4KAuthInfo( workgroup, host, TQString() ) );
TQString command;
command = TQString( "net %1 -w %2 -S %3" ).arg( optionsHandler()->netOptions( Smb4KSambaOptionsHandler::Share, host, protocol ) ).arg( KProcess::quote( workgroup ), KProcess::quote( host ) );
if ( !ip.isEmpty() )
{
command.append( TQString( " -I %1" ).arg( KProcess::quote( ip ) ) );
}
if ( !auth->user().isEmpty() )
{
command.append( TQString( " -U %1" ).arg( KProcess::quote( auth->user() ) ) );
if ( !auth->password().isEmpty() )
{
m_proc->setEnvironment( "PASSWD", auth->password() );
}
}
else
{
command.append( " -U guest%" );
}
delete auth;
*m_proc << command;
startProcess( Shares );
}
/****************************************************************************
Gets more info on a selected host. (private part)
****************************************************************************/
void Smb4KScanner::scanForInfo( const TQString &workgroup, const TQString &host, const TQString &ip )
{
m_priv->setWorkgroup( workgroup );
m_priv->setHost( host );
m_priv->setIP( ip );
TQString smbclient_options = optionsHandler()->smbclientOptions();
TQString command = TQString( "smbclient -d1 -U guest% -W %1 -L %2" ).arg( KProcess::quote( workgroup ) ).arg( KProcess::quote( host ) );
if ( !ip.isEmpty() )
{
command.append( TQString( " -I %1" ).arg( KProcess::quote( ip ) ) );
}
if ( !smbclient_options.stripWhiteSpace().isEmpty() )
{
command.append( smbclient_options );
}
*m_proc << command;
startProcess( Info );
}
/****************************************************************************
Searches for a host. (private part)
****************************************************************************/
void Smb4KScanner::searchForHost( const TQString &host )
{
// We need this because smbclient won't return the host name.
KNetwork::KIpAddress ip_address = KNetwork::KIpAddress( host );
if ( Smb4KSettings::searchMethod() == Smb4KSettings::EnumSearchMethod::Smbclient &&
(ip_address.isIPv4Addr() || ip_address.isIPv6Addr()) )
{
Smb4KError::error( ERROR_IP_CANNOT_BE_USED );
m_working = false;
emit state( SCANNER_STOP );
return;
}
m_priv->setHost( host );
TQString wins = optionsHandler()->winsServer();
TQString nmblookup_options = optionsHandler()->nmblookupOptions();
TQString smbclient_options = optionsHandler()->smbclientOptions();
TQString command;
switch ( Smb4KSettings::searchMethod() )
{
case Smb4KSettings::EnumSearchMethod::Nmblookup:
{
command = TQString( "nmblookup" );
if ( !nmblookup_options.stripWhiteSpace().isEmpty() )
{
command.append( nmblookup_options );
}
if ( host.contains( '.', true ) != 3 )
{
if ( !wins.isEmpty() )
{
command.append( TQString( " -R -U %1 %2 -S | grep '<00>' | sed -e 's/<00>.*//'" ).arg( wins ).arg( m_priv->host() ) );
}
else
{
command.append( TQString( " %1 -S | grep '<00>' | sed -e 's/<00>.*//'" ).arg( m_priv->host() ) );
}
}
else
{
if ( !wins.isEmpty() )
{
command.append( TQString( " -R -U %1 %2 -A | grep '<00>' | sed -e 's/<00>.*//'" ).arg( wins ).arg( m_priv->host() ) );
}
else
{
command.append( TQString( " %1 -A | grep '<00>' | sed -e 's/<00>.*//'" ).arg( m_priv->host() ) );
}
}
break;
}
case Smb4KSettings::EnumSearchMethod::Smbclient:
{
command = TQString( "smbclient -d2 -U % -L %1" ).arg( m_priv->host() );
if ( !smbclient_options.stripWhiteSpace().isEmpty() )
{
command.append( smbclient_options );
}
break;
}
default:
{
// Something went wrong. Stop here.
return;
}
}
*m_proc << command;
startProcess( Search );
}
/****************************************************************************
Starts the process of the scanner.
****************************************************************************/
void Smb4KScanner::startProcess( int state )
{
m_state = state;
m_buffer = TQString();
if ( state != Info )
{
TQApplication::setOverrideCursor( waitCursor );
}
m_proc->start( KProcess::NotifyOnExit, KProcess::AllOutput );
}
/****************************************************************************
End the process and tell, what to do with the data.
****************************************************************************/
void Smb4KScanner::endProcess()
{
switch ( m_state )
{
case Workgroups:
case QueryHost:
processWorkgroups();
break;
case IPScan:
processIPScan();
break;
case Hosts:
processWorkgroupMembers();
break;
case Shares:
processShares();
break;
case Info:
processInfo();
break;
case Search:
processSearch();
break;
default:
break;
}
m_state = Idle;
m_priv->clearData();
TQApplication::restoreOverrideCursor();
m_proc->clearArguments();
m_working = false;
emit state( SCANNER_STOP );
}
/****************************************************************************
Process the list of workgroups.
****************************************************************************/
void Smb4KScanner::processWorkgroups()
{
TQStringList list = TQStringList::split( '\n', m_buffer, false );
for ( TQValueList<Smb4KWorkgroupItem *>::Iterator it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it )
{
delete *it;
}
for ( TQValueList<Smb4KHostItem *>::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it )
{
delete *it;
}
m_workgroups_list->clear();
m_hosts_list->clear();
if ( m_state == Workgroups )
{
TQString workgroup, master, ip;
for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
{
if ( (*it).stripWhiteSpace().startsWith( "Looking" ) )
{
ip = (*it).section( "of", 1, 1 ).stripWhiteSpace();
continue;
}
else if ( (*it).contains( "<00>" ) != 0 && (*it).contains( "<GROUP>" ) == 0 )
{
if ( workgroup.isEmpty() && master.isEmpty() && !ip.isEmpty() )
{
master = (*it).section( "<00>", 0, 0 ).stripWhiteSpace();
}
continue;
}
else if ( (*it).contains( "<00>" ) != 0 && (*it).contains( "<GROUP>" ) != 0 )
{
if ( workgroup.isEmpty() && !master.isEmpty() && !ip.isEmpty() )
{
workgroup = (*it).left( (*it).find( "<00>" ) ).stripWhiteSpace();
m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, master, ip ) );
Smb4KHostItem *master_item = new Smb4KHostItem( workgroup, master, TQString(), ip );
master_item->setMaster( true );
m_hosts_list->append( master_item );
workgroup = TQString();
master = TQString();
ip = TQString();
}
continue;
}
}
}
else if ( m_state == QueryHost )
{
bool process = false;
for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
{
TQString line = (*it).stripWhiteSpace();
if ( line.startsWith( "-------------" ) )
{
process = true;
continue;
}
if ( process && !line.isEmpty() )
{
TQString workgroup = line.section( " ", 0, 0 ).stripWhiteSpace();
TQString master = line.section( " ", 1, -1 ).stripWhiteSpace();
m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, master, TQString() ) );
Smb4KHostItem *master_item = new Smb4KHostItem( workgroup, master );
master_item->setMaster( true );
m_hosts_list->append( master_item );
continue;
}
else
{
continue;
}
}
}
lookupIPAddresses();
emit workgroups( *m_workgroups_list );
emit hostListChanged();
}
/****************************************************************************
Process the data from the IP range scan
****************************************************************************/
void Smb4KScanner::processIPScan()
{
TQStringList list = TQStringList::split( '\n', m_buffer, true );
for ( TQValueList<Smb4KWorkgroupItem *>::Iterator it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it )
{
delete *it;
}
for ( TQValueList<Smb4KHostItem *>::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it )
{
delete *it;
}
m_workgroups_list->clear();
m_hosts_list->clear();
// Process the data:
for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
{
if ( (*it).startsWith( "Looking up status of" ) )
{
TQString workgroup, host, ip;
bool master = false;
// Get the IP address of this host.
ip = (*it).section( "of", 1, 1 ).stripWhiteSpace();
// Loop through the data:
for ( TQStringList::ConstIterator i = it; i != list.end(); ++i )
{
if ( (*i).contains( " <00> " ) != 0 )
{
if ( (*i).contains( " <GROUP> " ) != 0 )
{
workgroup = (*i).section( "<00>", 0, 0 ).stripWhiteSpace();
}
else
{
host = (*i).section( "<00>", 0, 0 ).stripWhiteSpace();
}
continue;
}
else if ( (*i).contains( "__MSBROWSE__" ) != 0 && (*i).contains( " <01> " ) != 0 )
{
master = true;
continue;
}
else if ( (*i).contains( "MAC Address" ) != 0 || (*i).stripWhiteSpace().isEmpty() )
{
it = i;
break;
}
else
{
continue;
}
}
if ( !workgroup.isEmpty() )
{
Smb4KWorkgroupItem *workgroup_item = getWorkgroup( workgroup );
if ( workgroup_item )
{
if ( master )
{
workgroup_item->setMaster( host, ip );
}
else
{
// Do nothing
}
}
else
{
if ( master )
{
m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, host, ip ) );
}
else
{
m_workgroups_list->append( new Smb4KWorkgroupItem( workgroup, TQString(), TQString() ) );
}
}
Smb4KHostItem *host_item = new Smb4KHostItem( workgroup, host, TQString(), ip );
host_item->setMaster( master );
m_hosts_list->append( host_item );
}
else
{
// Do nothing
}
}
else
{
continue;
}
}
// No extra lookup of IP addresses is needed since
// we searched for IP addresses. :)
emit workgroups( *m_workgroups_list );
emit members( m_priv->workgroup(), *m_hosts_list );
emit hostListChanged();
}
/****************************************************************************
Process the member list of a workgroup.
****************************************************************************/
void Smb4KScanner::processWorkgroupMembers()
{
TQStringList list = TQStringList::split( '\n', m_buffer, false );
switch ( Smb4KSettings::browseList() )
{
case Smb4KSettings::EnumBrowseList::LookupDomains:
case Smb4KSettings::EnumBrowseList::QueryCurrentMaster:
case Smb4KSettings::EnumBrowseList::QueryCustomMaster:
{
if ( m_buffer.contains( "NT_STATUS_ACCESS_DENIED" ) != 0 ||
m_buffer.contains( "NT_STATUS_LOGON_FAILURE" ) != 0 ||
m_buffer.contains( "The username or password was not correct" ) != 0 )
{
// Authentication failed:
emit failed();
if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(),
TQString(), Smb4KPasswordHandler::AccessDenied,
kapp->mainWidget() ? kapp->mainWidget() : 0, "AskPass" ) )
{
m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Hosts ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip() ) ) );
}
return;
}
else if ( m_buffer.contains( "Could not connect to server" ) != 0 ||
m_buffer.contains( "Unable to find a suitable server" ) != 0 ||
m_buffer.contains( "Invalid ip address specified" ) != 0 )
{
// If the IP address is empty, the shell output contains
// the IP address. Remove it, because it will confuse
// the user:
if ( m_priv->ip().isEmpty() )
{
list.remove( list.first() );
}
// Notify the rest of the program, that something went wrong.
emit failed();
// Notify the user:
Smb4KError::error( ERROR_GETTING_MEMBERS, TQString(), list.join( "\n" ) );
return;
}
else
{
// Do nothing
}
TQValueList<Smb4KHostItem *> hosts;
bool process = false;
for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
{
TQString line = (*it).stripWhiteSpace();
if ( !process )
{
// Find the IP address in case we did not know it at the beginning
// of the scan process and put it into m_priv.ip():
if ( m_priv->ip().isEmpty() && line.startsWith( "***" ) && line.endsWith( "***" ) )
{
m_priv->setIP( line.section( ":", 1, 1 ).section( "***", 0, 0 ).stripWhiteSpace() );
continue;
}
// Find the line after that we will have to process the output
// to get the servers belonging to this workgroup:
if ( line.startsWith( "-------------" ) )
{
process = true;
continue;
}
continue;
}
else
{
if ( !line.isEmpty() )
{
TQString host, comment;
if ( line.contains( " " ) == 0 )
{
host = line;
}
else
{
host = line.section( " ", 0, 0 ).stripWhiteSpace();
comment = line.section( " ", 1, -1 ).stripWhiteSpace();
}
Smb4KHostItem *item = new Smb4KHostItem( m_priv->workgroup(), host, comment );
if ( TQString::compare( item->name(), m_priv->host() ) == 0 )
{
// The item is identical to the master browser! Give the
// respective workgroup item the IP address of the master
// if it is not already present.
Smb4KWorkgroupItem *workgroupItem = getWorkgroup( m_priv->workgroup() );
if ( workgroupItem && workgroupItem->masterIP().isEmpty() )
{
workgroupItem->setMasterIP( m_priv->ip() );
}
// Set the IP address for new item (we only know it at this point,
// because this is the workgroup master):
item->setIPAddress( m_priv->ip() );
// Set it to be the master:
item->setMaster( true );
}
hosts.append( item );
continue;
}
else
{
continue;
}
}
}
// If the list is empty, put the master in.
if ( hosts.isEmpty() )
{
Smb4KHostItem *item = new Smb4KHostItem( m_priv->workgroup(), m_priv->host() );
item->setMaster( true );
hosts.append( item );
}
emit members( m_priv->workgroup(), hosts );
// Now put the hosts in m_hosts_list:
for ( TQValueList<Smb4KHostItem *>::Iterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it )
{
if ( TQString::compare( (*it)->workgroup(), m_priv->workgroup() ) == 0 )
{
bool found = false;
for ( TQValueList<Smb4KHostItem *>::Iterator i = hosts.begin(); i != hosts.end(); ++i )
{
if ( *i && TQString::compare( (*i)->name(), (*it)->name() ) == 0 )
{
found = true;
// The only thing that might be missing is the comment.
(*it)->setComment( (*i)->comment() );
delete *i;
*i = NULL;
break;
}
else
{
continue;
}
}
if ( !found )
{
delete *it;
*it = NULL;
}
}
else
{
continue;
}
}
m_hosts_list->remove( NULL );
hosts.remove( NULL );
// Append the list:
*m_hosts_list += hosts;
// Lookup IP addresses.
lookupIPAddresses();
break;
}
case Smb4KSettings::EnumBrowseList::ScanBroadcastAreas:
{
if ( m_buffer.contains( "NT_STATUS_ACCESS_DENIED" ) != 0 ||
m_buffer.contains( "NT_STATUS_LOGON_FAILURE" ) != 0 ||
m_buffer.contains( "The username or password was not correct" ) != 0 )
{
// Authentication failed:
emit failed();
if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(),
TQString(), Smb4KPasswordHandler::AccessDenied,
kapp->mainWidget() ? kapp->mainWidget() : 0, "AskPass" ) )
{
m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4" ).arg( Hosts ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip() ) ) );
}
return;
}
else if ( m_buffer.contains( "Could not connect to server" ) != 0 ||
m_buffer.contains( "Unable to find a suitable server" ) != 0 ||
m_buffer.contains( "Invalid ip address specified" ) != 0 )
{
// We are in IP scan mode, so we can ignore the error and emit
// what we already have:
emit members( m_priv->workgroup(), *m_hosts_list );
emit hostListChanged();
return;
}
// We will not remove any host from the list in IP scan mode,
// but we will add additional infomation, if available.
bool process = false;
for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
{
if ( (*it).stripWhiteSpace().startsWith( "-------------" ) )
{
process = true;
continue;
}
if ( process && !(*it).stripWhiteSpace().isEmpty() )
{
TQString line = (*it).stripWhiteSpace();
// Extract host name and comment:
TQString host, comment;
if ( line.contains( " " ) == 0 )
{
host = line;
}
else
{
host = line.section( " ", 0, 0 ).stripWhiteSpace();
comment = line.section( " ", 1, -1 ).stripWhiteSpace();
}
// Now add the comment to the host item or do nothing if
// no comment was found:
if ( !comment.isEmpty() )
{
Smb4KHostItem *item = getHost( host, m_priv->workgroup() );
if ( item )
{
item->setComment( comment );
}
continue;
}
else
{
continue;
}
}
}
emit members( m_priv->workgroup(), *m_hosts_list );
break;
}
default:
{
break;
}
}
emit hostListChanged();
}
/****************************************************************************
Process the share list of a host.
****************************************************************************/
void Smb4KScanner::processShares()
{
// Error handling
if ( m_buffer.contains( "The username or password was not correct.", true ) != 0 ||
m_buffer.contains( "NT_STATUS_ACCOUNT_DISABLED" ) != 0 /* Active Directory error */ )
{
// Authentication failed:
emit failed();
if ( passwordHandler()->askpass( m_priv->workgroup(), m_priv->host(), TQString(), Smb4KPasswordHandler::AccessDenied, kapp->mainWidget() ? kapp->mainWidget() : 0, "AskPass" ) )
{
m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4:%5" ).arg( Shares ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip(), TQString() ) ) );
}
return;
}
else if ( m_buffer.contains( "could not obtain sid for domain", true ) != 0 )
{
// FIXME: Does this error only occur when we scan a server that is
// only capable of the RAP protocol or also under other conditions?
m_queue.enqueue( new TQString( TQString( "%1:%2:%3:%4:%5" ).arg( Shares ).arg( m_priv->workgroup(), m_priv->host(), m_priv->ip(), "rap" ) ) );
m_priv->retry = true;
return;
}
else if ( (m_buffer.contains( "Could not connect to server", true ) != 0 &&
m_buffer.contains( "The username or password was not correct.", true ) == 0) ||
m_buffer.contains( "Unable to find a suitable server" ) != 0 )
{
// We could not get the list of shares:
emit failed();
// Notify the user:
Smb4KError::error( ERROR_GETTING_SHARES, TQString(), m_buffer );
return;
}
TQStringList list = TQStringList::split( '\n', m_buffer, false );
TQValueList<Smb4KShareItem *> share_list;
bool process = false;
for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
{
if ( (*it).startsWith( "---" ) )
{
process = true;
}
if ( process )
{
TQString name, type, comment;
if ( (*it).contains( " Disk ", true ) != 0 )
{
name = (*it).section( " Disk ", 0, 0 ).stripWhiteSpace();
type = "Disk";
comment = (*it).section( " Disk ", 1, 1 ).stripWhiteSpace();
}
else if ( (*it).contains( " Print ", true ) != 0 )
{
name = (*it).section( " Print ", 0, 0 ).stripWhiteSpace();
type = "Printer";
comment = (*it).section( " Print ", 1, 1 ).stripWhiteSpace();
}
else if ( (*it).contains( " IPC ", true ) != 0 )
{
name = (*it).section( " IPC ", 0, 0 ).stripWhiteSpace();
type = "IPC";
comment = (*it).section( " IPC ", 1, 1 ).stripWhiteSpace();
}
else
{
continue;
}
share_list.append( new Smb4KShareItem( m_priv->workgroup(), m_priv->host(), name, type, comment ) );
}
else
{
continue;
}
}
emit shares( m_priv->host(), share_list );
}
/****************************************************************************
Process the search data.
****************************************************************************/
void Smb4KScanner::processSearch()
{
// NOTE: We do not emit Smb4KScanner::failed() here, because
// errors are handled in a different way by the search dialog.
// Stop right here if the user searched for illegal
// strings like #, ', () etc.
if ( m_buffer.contains( "Usage:", true ) != 0 ||
m_buffer.contains( "/bin/sh:", true ) != 0 )
{
emit searchResult( new Smb4KHostItem() );
return;
}
TQStringList data = TQStringList::split( '\n', m_buffer.stripWhiteSpace(), false );
switch ( Smb4KSettings::searchMethod() )
{
case Smb4KSettings::EnumSearchMethod::Nmblookup:
{
if ( !data.isEmpty() )
{
// The last entry in the list is the workgroup:
TQString workgroup = data.last().stripWhiteSpace();
TQString host, ip;
if ( m_priv->host().contains( ".", true ) != 3 )
{
// The IP address is in the first entry:
ip = data.first().stripWhiteSpace().section( " ", 0, 0 );
// The host.
host = m_priv->host().upper();
}
else
{
ip = m_priv->host();
host = data[0].stripWhiteSpace();
}
emit searchResult( new Smb4KHostItem( workgroup, host, TQString(), ip ) );
}
else
{
emit searchResult( new Smb4KHostItem() );
}
break;
}
case Smb4KSettings::EnumSearchMethod::Smbclient:
{
if ( data.count() > 1 && !data[1].isEmpty() )
{
if ( m_buffer.contains( TQString( "Connection to %1 failed" ).arg( m_priv->host() ) ) != 0 )
{
emit searchResult( new Smb4KHostItem() );
}
else
{
TQString workgroup = data.grep( "Domain" ).first().section( "Domain=[", 1, 1 ).section( "]", 0, 0 );
TQString ip = data.grep( "Got a positive name query" ).first().section( "(", 1, 1 ).section( ")", 0, 0 ).stripWhiteSpace();
emit searchResult( new Smb4KHostItem( workgroup, m_priv->host().upper(), TQString(), ip ) );
}
}
else
{
emit searchResult( new Smb4KHostItem() );
}
break;
}
default:
{
break;
}
}
}
/****************************************************************************
Process the information about a host.
****************************************************************************/
void Smb4KScanner::processInfo()
{
if ( m_proc->normalExit() )
{
TQStringList list = TQStringList::split( '\n', m_buffer, false );
Smb4KHostItem *host = getHost( m_priv->host(), m_priv->workgroup() );
if ( host )
{
for ( TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it )
{
if ( (*it).stripWhiteSpace().startsWith( "Domain" ) || (*it).stripWhiteSpace().startsWith( "OS" ) )
{
// The OS string.
host->setOSString( (*it).section( "OS=[", 1, 1 ).section( "]", 0, 0 ).stripWhiteSpace() );
// The Server string.
host->setServerString( (*it).section( "Server=[", 1, 1 ).section( "]", 0, 0 ).stripWhiteSpace() );
break;
}
else if ( (*it).contains( "Connection to", true ) != 0 )
{
// The lookup of the info failed:
emit failed();
break;
}
}
emit info( host );
}
}
else
{
// In case the process was aborted, we need to enable checking
// again:
Smb4KHostItem *host = getHost( m_priv->host(), m_priv->workgroup() );
if ( host )
{
host->setInfoChecked( false );
}
}
}
/****************************************************************************
Get a workgroup item out of the workgroup list.
****************************************************************************/
Smb4KWorkgroupItem *Smb4KScanner::getWorkgroup( const TQString &workgroup )
{
TQValueListIterator<Smb4KWorkgroupItem *> it;
for ( it = m_workgroups_list->begin(); it != m_workgroups_list->end(); ++it )
{
if ( TQString::compare( (*it)->name(), workgroup ) == 0 )
{
break;
}
else
{
continue;
}
}
return it == m_workgroups_list->end() ? NULL : *it;
}
/****************************************************************************
Get a workgroup item out of the workgroup list.
****************************************************************************/
Smb4KHostItem *Smb4KScanner::getHost( const TQString &name, const TQString &workgroup )
{
TQValueListIterator<Smb4KHostItem *> it;
for ( it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it )
{
if ( !workgroup.stripWhiteSpace().isEmpty() &&
TQString::compare( (*it)->workgroup().upper(), workgroup.upper() ) != 0 )
{
continue;
}
if ( TQString::compare( (*it)->name().upper(), name.upper() ) == 0 )
{
break;
}
else
{
continue;
}
}
return it == m_hosts_list->end() ? NULL : *it;
}
/****************************************************************************
Add a host to the host list
****************************************************************************/
void Smb4KScanner::insertHost( Smb4KHostItem *host )
{
if ( host && !getHost( host->name(), host->workgroup() ) )
{
// Use the copy constructor here, so that we do not run into
// trouble when/if host is deleted.
Smb4KHostItem *host_item = new Smb4KHostItem( *host );
m_hosts_list->append( host_item );
// Check if the workgroup is already known. If not, create a new Smb4KWorkgroupItem,
// declare the host a pseudo master and add the workgroup to the list.
if ( !getWorkgroup( host_item->workgroup() ) )
{
Smb4KWorkgroupItem *workgroup_item = new Smb4KWorkgroupItem( host_item->workgroup(),
host_item->name(), host_item->ip() );
workgroup_item->setPseudoMaster();
host_item->setMaster( true ); // pseudo master
appendWorkgroup( workgroup_item );
}
// Lookup at least the IP address of this host, if necessary:
if ( host_item->ip().isEmpty() )
{
lookupIPAddresses();
}
emit hostAdded( host_item );
emit hostListChanged();
}
}
/****************************************************************************
Appends an item to the list of workgroups.
****************************************************************************/
void Smb4KScanner::appendWorkgroup( Smb4KWorkgroupItem *item )
{
if ( !getWorkgroup( item->name() ) )
{
m_workgroups_list->append( item );
emit workgroups( *m_workgroups_list );
}
}
void Smb4KScanner::timerEvent( TQTimerEvent * )
{
// Look for the thing to do (next).
// At this point, the topmost item will not be
// dequeued. This will be done below.
int todo = Idle;
TQString *head = NULL;
if ( (head = m_queue.head()) != 0 )
{
todo = head->section( ":", 0, 0 ).toInt();
}
if ( !m_working && !m_queue.isEmpty() )
{
// Start processing with dequeueing the item:
TQString *item = m_queue.dequeue();
// Tell the program, that the scanner is running.
m_working = true;
switch ( todo )
{
case Init:
{
emit state( SCANNER_INIT );
scanNetwork();
break;
}
case Hosts:
{
emit state( SCANNER_OPENING_WORKGROUP );
scanForWorkgroupMembers( item->section( ":", 1, 1 ), item->section( ":", 2, 2 ), item->section( ":", 3, 3 ) );
break;
}
case Shares:
{
if ( !m_priv->retry )
{
emit state( SCANNER_OPENING_HOST );
}
else
{
emit state( SCANNER_RETRYING_OPENING_HOST );
m_priv->retry = false;
}
scanForShares( item->section( ":", 1, 1 ), item->section( ":", 2, 2 ), item->section( ":", 3, 3 ), item->section( ":", 4, 4 ) );
break;
}
case Info:
{
emit state( SCANNER_RETRIEVING_INFO );
scanForInfo( item->section( ":", 1, 1 ), item->section( ":", 2, 2 ), item->section( ":", 3, 3 ) );
break;
}
case Search:
{
emit state( SCANNER_SEARCHING );
searchForHost( item->section( ":", 1, 1 ) );
break;
}
default:
break;
}
delete item;
}
}
/////////////////////////////////////////////////////////////////////////////
// TQT_SLOT IMPLEMENTATIONS
/////////////////////////////////////////////////////////////////////////////
/****************************************************************************
Internal slots.
****************************************************************************/
void Smb4KScanner::slotReceivedStdout( KProcess *, char *buf, int len )
{
m_buffer.append( TQString::fromLocal8Bit( buf, len ) );
}
void Smb4KScanner::slotProcessExited( KProcess * )
{
endProcess();
}
void Smb4KScanner::slotReceivedStderr( KProcess *, char *buf, int len )
{
m_buffer.append( TQString::fromLocal8Bit( buf, len ) );
}
/***************************************************************************
* *
* Lookup for IP addresses *
* *
***************************************************************************/
/****************************************************************************
Start the scanning for IP addresses
****************************************************************************/
void Smb4KScanner::lookupIPAddresses()
{
bool start = false;
TQString command = TQString();
for ( TQValueList<Smb4KHostItem *>::ConstIterator it = m_hosts_list->begin(); it != m_hosts_list->end(); ++it )
{
if ( (*it)->ip().stripWhiteSpace().isEmpty() && !(*it)->ipAddressChecked() )
{
if ( !start )
{
start = true;
}
(*it)->setIPAddressChecked( true );
command.append( "nmblookup" );
command.append( optionsHandler()->nmblookupOptions() );
command.append( optionsHandler()->winsServer().isEmpty() ? "" : " -R -U "+KProcess::quote( optionsHandler()->winsServer() ) );
command.append( " -- "+KProcess::quote( (*it)->name() )+" | grep '<00>'" );
command.append( " ; " );
continue;
}
else
{
continue;
}
}
command.truncate( command.length() - 3 );
if ( start )
{
KProcess *proc = new KProcess( this );
proc->setUseShell( true );
connect( proc, TQT_SIGNAL( receivedStdout( KProcess *, char *, int ) ),
this, TQT_SLOT( slotReceivedIPAddresses( KProcess *, char *, int ) ) );
connect( proc, TQT_SIGNAL( processExited( KProcess * ) ),
this, TQT_SLOT( slotIPAddressProcessExited( KProcess * ) ) );
*proc << command;
proc->start( KProcess::NotifyOnExit, KProcess::Stdout );
}
}
/****************************************************************************
Processes IP addresses if data occurrs on stdout.
****************************************************************************/
void Smb4KScanner::slotReceivedIPAddresses( KProcess *, char *buf, int len )
{
// WARNING: Do not implement error handling here!!!
TQString buffer = TQString::fromLocal8Bit( buf, len );
if ( !buffer.stripWhiteSpace().isEmpty() )
{
TQString ip = buffer.stripWhiteSpace().section( " ", 0, 0 ).stripWhiteSpace();
TQString host = buffer.stripWhiteSpace().section( " ", 1, 1 ).section( "<00>", 0, 0 ).stripWhiteSpace();
if ( !host.isEmpty() && !ip.isEmpty() )
{
Smb4KHostItem *item = getHost( host );
if ( item )
{
item->setIPAddress( ip );
if ( item->isMaster() )
{
Smb4KWorkgroupItem *workgroup = getWorkgroup( item->workgroup() );
if ( workgroup )
{
workgroup->setMasterIP( ip );
}
}
emit ipAddress( item );
}
}
}
}
/****************************************************************************
End IP address scan.
****************************************************************************/
void Smb4KScanner::slotIPAddressProcessExited( KProcess *p )
{
delete p;
}
#include "smb4kscanner.moc"