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/smb4kpreviewer.cpp

362 line
10 KiB

/***************************************************************************
smb4kpreviewer - This class queries a remote share for a preview
-------------------
begin : Mo Mai 28 2007
copyright : (C) 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>
// KDE includes
#include <kapplication.h>
#include <kdebug.h>
// application specific includes
#include "smb4kpreviewer.h"
#include "smb4kpreviewitem.h"
#include "smb4kdefs.h"
#include "smb4kglobal.h"
#include "smb4kpasswordhandler.h"
#include "smb4kauthinfo.h"
#include "smb4ksambaoptionshandler.h"
#include "smb4kerror.h"
using namespace Smb4KGlobal;
Smb4KPreviewer::Smb4KPreviewer( TQObject *parent, const char *name )
: TQObject( parent, name )
{
m_item = NULL;
m_buffer = TQString();
m_working = false;
m_proc = new KProcess( this, "PreviewProcess" );
m_proc->setUseShell( 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 ) ) );
}
Smb4KPreviewer::~Smb4KPreviewer()
{
// Do not delete m_item here, because it belongs to an
// outside class.
}
bool Smb4KPreviewer::preview( Smb4KPreviewItem *item )
{
// If there is no item, stop right here.
if ( !item )
{
return false;
}
if ( TQString::compare( item->share(), "homes" ) == 0 )
{
TQString share_name = specifyUser( item->host(), kapp->mainWidget() ? kapp->mainWidget() : 0, "SpecifyUser" );
if ( !share_name.isEmpty() )
{
// The Smb4KPreviewItem::setShare() function will take care
// that no share name is overwritten, that is *not* named
// 'homes'.
item->setShare( share_name );
}
else
{
return false;
}
}
m_timer_id = startTimer( TIMER_INTERVAL );
m_queue.enqueue( item );
return true;
}
void Smb4KPreviewer::abort()
{
m_queue.clear();
if ( m_proc->isRunning() )
{
m_proc->kill();
}
}
void Smb4KPreviewer::timerEvent( TQTimerEvent * )
{
if ( m_working )
{
return;
}
// Declare the previewer working:
emit state( PREVIEWER_START );
m_working = true;
m_item = m_queue.dequeue();
// Assemble the command.
//
// Here are some things to remember:
// (a) Do not convert the path to local 8 bit. It won't work with umlauts or other
// special characters.
// (b) Do not pass the path unquoted, or you'll get a NT_STATUS_OBJECT_NAME_NOT_FOUND
// error message in the case the path is empty.
TQString command;
command.append( TQString( "smbclient //%1/%2 " ).tqarg( KProcess::quote( m_item->host() ), KProcess::quote( m_item->share() ) ) );
command.append( TQString( " -d1 -W %1 -D %2 " ).tqarg( KProcess::quote( m_item->workgroup() ), KProcess::quote( m_item->path() ) ) );
command.append( " -c \"ls\" " );
if ( !m_item->ip().isEmpty() )
{
command.append( TQString( " -I %1 " ).tqarg( m_item->ip() ) );
}
command.append( optionsHandler()->smbclientOptions( "//"+m_item->host()+"/"+m_item->share() ) );
Smb4KAuthInfo *auth = passwordHandler()->readAuth( new Smb4KAuthInfo( m_item->workgroup(), m_item->host(), m_item->share() ) );
if ( !auth->user().isEmpty() )
{
command.append( TQString( " -U %1" ).tqarg( KProcess::quote( auth->user() ) ) );
if ( !auth->password().isEmpty() )
{
m_proc->setEnvironment( "PASSWD", auth->password() );
}
}
else
{
command.append( " -U guest%" );
}
delete auth;
*m_proc << command;
TQApplication::setOverrideCursor( waitCursor );
m_proc->start( KProcess::NotifyOnExit, KProcess::AllOutput );
}
/////////////////////////////////////////////////////////////////////////////
// TQT_SLOT IMPLEMENTATIONS
/////////////////////////////////////////////////////////////////////////////
void Smb4KPreviewer::slotReceivedStdout( KProcess *, char *buf, int len )
{
m_buffer.append( TQString::fromLocal8Bit( buf, len ) );
}
void Smb4KPreviewer::slotReceivedStderr( KProcess *, char *buf, int len )
{
m_buffer.append( TQString::fromLocal8Bit( buf, len ) );
}
void Smb4KPreviewer::slotProcessExited( KProcess * )
{
// Disconnect the timer:
if ( m_queue.isEmpty() )
{
killTimer( m_timer_id );
}
m_proc->clearArguments();
TQStringList list = TQStringList::split( "\n", m_buffer, false );
m_buffer = TQString();
// Check whether an error occurred:
if ( list.grep( "NT_STATUS" ).count() != 0 )
{
// Something went wrong. Let's check if this "only" an
// authentication issue or if we have to error out:
TQString error_code = list.grep( "NT_STATUS" ).first().stripWhiteSpace().section( " ", 0, 0 );
// The error output of smbclient is a little bit inconsistent:
if ( error_code.contains( "NT_STATUS" ) == 0 )
{
error_code = list.grep( "NT_STATUS" ).first().stripWhiteSpace().section( " ", -1, -1 );
}
// Authentication issue?
if ( TQString::compare( error_code, "NT_STATUS_ACCESS_DENIED" ) == 0 ||
TQString::compare( error_code, "NT_STATUS_LOGON_FAILURE" ) == 0 )
{
int state = Smb4KPasswordHandler::None;
if ( TQString::compare( error_code, "NT_STATUS_ACCESS_DENIED" ) == 0 )
{
state = Smb4KPasswordHandler::AccessDenied;
}
else if ( TQString::compare( error_code, "NT_STATUS_LOGON_FAILURE" ) == 0 )
{
state = Smb4KPasswordHandler::LogonFailure;
}
if ( passwordHandler()->askpass( m_item->workgroup(), m_item->host(),
m_item->share(), state,
kapp->mainWidget() ? kapp->mainWidget() : 0,
"AskPass" ) )
{
// Now we have a password. Retry.
// NOTE: Since the item is appended to the queue, there might
// be the case, that another preview is generated before the
// retry is executed. I think, we can live with that.
preview( m_item );
}
else
{
// The user cancelled the askpass dialog. We won't show an
// error dialog here, but will only clear the contents of
// the preview item and emit the failed() signal.
m_item->clearContents();
emit failed();
}
}
else
{
// OK, error out. We cannot recover from it:
Smb4KError::error( ERROR_GETTING_PREVIEW, TQString(), m_buffer );
m_item->clearContents();
emit failed();
}
}
else if ( list.grep( "Connection to" ).count() != 0 ||
(list.grep( "Error returning browse list:" ).count() != 0 &&
list.grep( "NT_STATUS" ).count() == 0) )
{
// These are errors that we cannot work around. Error out.
Smb4KError::error( ERROR_GETTING_PREVIEW, TQString(), m_buffer );
m_item->clearContents();
emit failed();
}
else
{
for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
{
if ( (*it).stripWhiteSpace().startsWith( "Domain" ) ||
(*it).stripWhiteSpace().startsWith( "OS" ) ||
(*it).stripWhiteSpace().startsWith( "Anonymous" ) )
{
continue;
}
else if ( (*it).contains( "blocks of size" ) != 0 )
{
continue;
}
else
{
TQString tmp = (*it).stripWhiteSpace().section( " ", 0, -9 ).stripWhiteSpace();
TQString item = tmp.section( " ", 0, -2 ).stripWhiteSpace();
if ( !item.isEmpty() && tmp.section( " ", -1, -1 ).contains( "D" ) != 0 )
{
// We have a directory here.
if ( item.startsWith( "." ) &&
(TQString::compare( item.stripWhiteSpace(), "." ) != 0 &&
TQString::compare( item.stripWhiteSpace(), ".." ) != 0) )
{
m_item->addContents( ContentsItem( Smb4KPreviewItem::HiddenDirectory, item ) );
}
else
{
m_item->addContents( ContentsItem( Smb4KPreviewItem::Directory, item ) );
}
continue;
}
else if ( item.isEmpty() || tmp.section( " ", -1, -1 ).contains( "D" ) == 0 )
{
// We have a file
if ( item.isEmpty() )
{
if ( tmp.startsWith( "." ) )
{
m_item->addContents( ContentsItem( Smb4KPreviewItem::HiddenFile, tmp ) );
}
else
{
m_item->addContents( ContentsItem( Smb4KPreviewItem::File, tmp ) );
}
}
else
{
if ( item.startsWith( "." ) )
{
m_item->addContents( ContentsItem( Smb4KPreviewItem::HiddenFile, item ) );
}
else
{
m_item->addContents( ContentsItem( Smb4KPreviewItem::File, item ) );
}
}
continue;
}
else
{
continue;
}
}
}
}
emit result( m_item );
TQApplication::restoreOverrideCursor();
m_working = false;
emit state( PREVIEWER_STOP );
}
#include "smb4kpreviewer.moc"