summaryrefslogtreecommitdiffstats
path: root/smb4k/core/smb4kpreviewer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'smb4k/core/smb4kpreviewer.cpp')
-rw-r--r--smb4k/core/smb4kpreviewer.cpp361
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"