/*************************************************************************** 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 // KDE includes #include #include // 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 *tqparent, const char *name ) : TQObject( tqparent, 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"