diff options
Diffstat (limited to 'smb4k/core/smb4kpreviewer.cpp')
-rw-r--r-- | smb4k/core/smb4kpreviewer.cpp | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/smb4k/core/smb4kpreviewer.cpp b/smb4k/core/smb4kpreviewer.cpp new file mode 100644 index 0000000..2d3c850 --- /dev/null +++ b/smb4k/core/smb4kpreviewer.cpp @@ -0,0 +1,361 @@ +/*************************************************************************** + 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 * + ***************************************************************************/ + +// Qt includes +#include <qapplication.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( QObject *parent, const char *name ) +: QObject( parent, name ) +{ + m_item = NULL; + + m_buffer = QString::null; + + m_working = false; + + m_proc = new KProcess( this, "PreviewProcess" ); + m_proc->setUseShell( true ); + + connect( m_proc, SIGNAL( receivedStdout( KProcess *, char *, int ) ), + this, SLOT( slotReceivedStdout( KProcess *, char *, int ) ) ); + + connect( m_proc, SIGNAL( processExited( KProcess* ) ), + this, SLOT( slotProcessExited( KProcess * ) ) ); + + connect( m_proc, SIGNAL( receivedStderr( KProcess *, char *, int ) ), + this, 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 ( QString::compare( item->share(), "homes" ) == 0 ) + { + QString 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( QTimerEvent * ) +{ + 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. + QString command; + command.append( QString( "smbclient //%1/%2 " ).arg( KProcess::quote( m_item->host() ), KProcess::quote( m_item->share() ) ) ); + command.append( QString( " -d1 -W %1 -D %2 " ).arg( KProcess::quote( m_item->workgroup() ), KProcess::quote( m_item->path() ) ) ); + command.append( " -c \"ls\" " ); + + if ( !m_item->ip().isEmpty() ) + { + command.append( QString( " -I %1 " ).arg( 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( QString( " -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; + + QApplication::setOverrideCursor( waitCursor ); + + m_proc->start( KProcess::NotifyOnExit, KProcess::AllOutput ); +} + + +///////////////////////////////////////////////////////////////////////////// +// SLOT IMPLEMENTATIONS +///////////////////////////////////////////////////////////////////////////// + +void Smb4KPreviewer::slotReceivedStdout( KProcess *, char *buf, int len ) +{ + m_buffer.append( QString::fromLocal8Bit( buf, len ) ); +} + + +void Smb4KPreviewer::slotReceivedStderr( KProcess *, char *buf, int len ) +{ + m_buffer.append( QString::fromLocal8Bit( buf, len ) ); +} + + +void Smb4KPreviewer::slotProcessExited( KProcess * ) +{ + // Disconnect the timer: + if ( m_queue.isEmpty() ) + { + killTimer( m_timer_id ); + } + + m_proc->clearArguments(); + + QStringList list = QStringList::split( "\n", m_buffer, false ); + + m_buffer = QString::null; + + // 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: + + QString 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 ( QString::compare( error_code, "NT_STATUS_ACCESS_DENIED" ) == 0 || + QString::compare( error_code, "NT_STATUS_LOGON_FAILURE" ) == 0 ) + { + int state = Smb4KPasswordHandler::None; + + if ( QString::compare( error_code, "NT_STATUS_ACCESS_DENIED" ) == 0 ) + { + state = Smb4KPasswordHandler::AccessDenied; + } + else if ( QString::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, QString::null, 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, QString::null, m_buffer ); + + m_item->clearContents(); + + emit failed(); + } + else + { + for ( QStringList::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 + { + QString tmp = (*it).stripWhiteSpace().section( " ", 0, -9 ).stripWhiteSpace(); + + QString item = tmp.section( " ", 0, -2 ).stripWhiteSpace(); + + if ( !item.isEmpty() && tmp.section( " ", -1, -1 ).contains( "D" ) != 0 ) + { + // We have a directory here. + if ( item.startsWith( "." ) && + (QString::compare( item.stripWhiteSpace(), "." ) != 0 && + QString::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 ); + + QApplication::restoreOverrideCursor(); + + m_working = false; + + emit state( PREVIEWER_STOP ); +} + +#include "smb4kpreviewer.moc" |