Smb4K – Samba (SMB) share advanced browser
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.

362 lines
11KB

  1. /***************************************************************************
  2. smb4kpreviewer - This class queries a remote share for a preview
  3. -------------------
  4. begin : Mo Mai 28 2007
  5. copyright : (C) 2007 by Alexander Reinholdt
  6. email : dustpuppy@users.berlios.de
  7. ***************************************************************************/
  8. /***************************************************************************
  9. * This program is free software; you can redistribute it and/or modify *
  10. * it under the terms of the GNU General Public License as published by *
  11. * the Free Software Foundation; either version 2 of the License, or *
  12. * (at your option) any later version. *
  13. * *
  14. * This program is distributed in the hope that it will be useful, but *
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of *
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
  17. * General Public License for more details. *
  18. * *
  19. * You should have received a copy of the GNU General Public License *
  20. * along with this program; if not, write to the *
  21. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
  22. * MA 02110-1301 USA *
  23. ***************************************************************************/
  24. // TQt includes
  25. #include <tqapplication.h>
  26. // KDE includes
  27. #include <kapplication.h>
  28. #include <kdebug.h>
  29. // application specific includes
  30. #include "smb4kpreviewer.h"
  31. #include "smb4kpreviewitem.h"
  32. #include "smb4kdefs.h"
  33. #include "smb4kglobal.h"
  34. #include "smb4kpasswordhandler.h"
  35. #include "smb4kauthinfo.h"
  36. #include "smb4ksambaoptionshandler.h"
  37. #include "smb4kerror.h"
  38. using namespace Smb4KGlobal;
  39. Smb4KPreviewer::Smb4KPreviewer( TQObject *parent, const char *name )
  40. : TQObject( parent, name )
  41. {
  42. m_item = NULL;
  43. m_buffer = TQString();
  44. m_working = false;
  45. m_proc = new KProcess( this, "PreviewProcess" );
  46. m_proc->setUseShell( true );
  47. connect( m_proc, TQT_SIGNAL( receivedStdout( KProcess *, char *, int ) ),
  48. this, TQT_SLOT( slotReceivedStdout( KProcess *, char *, int ) ) );
  49. connect( m_proc, TQT_SIGNAL( processExited( KProcess* ) ),
  50. this, TQT_SLOT( slotProcessExited( KProcess * ) ) );
  51. connect( m_proc, TQT_SIGNAL( receivedStderr( KProcess *, char *, int ) ),
  52. this, TQT_SLOT( slotReceivedStderr( KProcess *, char *, int ) ) );
  53. }
  54. Smb4KPreviewer::~Smb4KPreviewer()
  55. {
  56. // Do not delete m_item here, because it belongs to an
  57. // outside class.
  58. }
  59. bool Smb4KPreviewer::preview( Smb4KPreviewItem *item )
  60. {
  61. // If there is no item, stop right here.
  62. if ( !item )
  63. {
  64. return false;
  65. }
  66. if ( TQString::compare( item->share(), "homes" ) == 0 )
  67. {
  68. TQString share_name = specifyUser( item->host(), kapp->mainWidget() ? kapp->mainWidget() : 0, "SpecifyUser" );
  69. if ( !share_name.isEmpty() )
  70. {
  71. // The Smb4KPreviewItem::setShare() function will take care
  72. // that no share name is overwritten, that is *not* named
  73. // 'homes'.
  74. item->setShare( share_name );
  75. }
  76. else
  77. {
  78. return false;
  79. }
  80. }
  81. m_timer_id = startTimer( TIMER_INTERVAL );
  82. m_queue.enqueue( item );
  83. return true;
  84. }
  85. void Smb4KPreviewer::abort()
  86. {
  87. m_queue.clear();
  88. if ( m_proc->isRunning() )
  89. {
  90. m_proc->kill();
  91. }
  92. }
  93. void Smb4KPreviewer::timerEvent( TQTimerEvent * )
  94. {
  95. if ( m_working )
  96. {
  97. return;
  98. }
  99. // Declare the previewer working:
  100. emit state( PREVIEWER_START );
  101. m_working = true;
  102. m_item = m_queue.dequeue();
  103. // Assemble the command.
  104. //
  105. // Here are some things to remember:
  106. // (a) Do not convert the path to local 8 bit. It won't work with umlauts or other
  107. // special characters.
  108. // (b) Do not pass the path unquoted, or you'll get a NT_STATUS_OBJECT_NAME_NOT_FOUND
  109. // error message in the case the path is empty.
  110. TQString command;
  111. command.append( TQString( "smbclient //%1/%2 " ).tqarg( KProcess::quote( m_item->host() ), KProcess::quote( m_item->share() ) ) );
  112. command.append( TQString( " -d1 -W %1 -D %2 " ).tqarg( KProcess::quote( m_item->workgroup() ), KProcess::quote( m_item->path() ) ) );
  113. command.append( " -c \"ls\" " );
  114. if ( !m_item->ip().isEmpty() )
  115. {
  116. command.append( TQString( " -I %1 " ).tqarg( m_item->ip() ) );
  117. }
  118. command.append( optionsHandler()->smbclientOptions( "//"+m_item->host()+"/"+m_item->share() ) );
  119. Smb4KAuthInfo *auth = passwordHandler()->readAuth( new Smb4KAuthInfo( m_item->workgroup(), m_item->host(), m_item->share() ) );
  120. if ( !auth->user().isEmpty() )
  121. {
  122. command.append( TQString( " -U %1" ).tqarg( KProcess::quote( auth->user() ) ) );
  123. if ( !auth->password().isEmpty() )
  124. {
  125. m_proc->setEnvironment( "PASSWD", auth->password() );
  126. }
  127. }
  128. else
  129. {
  130. command.append( " -U guest%" );
  131. }
  132. delete auth;
  133. *m_proc << command;
  134. TQApplication::setOverrideCursor( waitCursor );
  135. m_proc->start( KProcess::NotifyOnExit, KProcess::AllOutput );
  136. }
  137. /////////////////////////////////////////////////////////////////////////////
  138. // TQT_SLOT IMPLEMENTATIONS
  139. /////////////////////////////////////////////////////////////////////////////
  140. void Smb4KPreviewer::slotReceivedStdout( KProcess *, char *buf, int len )
  141. {
  142. m_buffer.append( TQString::fromLocal8Bit( buf, len ) );
  143. }
  144. void Smb4KPreviewer::slotReceivedStderr( KProcess *, char *buf, int len )
  145. {
  146. m_buffer.append( TQString::fromLocal8Bit( buf, len ) );
  147. }
  148. void Smb4KPreviewer::slotProcessExited( KProcess * )
  149. {
  150. // Disconnect the timer:
  151. if ( m_queue.isEmpty() )
  152. {
  153. killTimer( m_timer_id );
  154. }
  155. m_proc->clearArguments();
  156. TQStringList list = TQStringList::split( "\n", m_buffer, false );
  157. m_buffer = TQString();
  158. // Check whether an error occurred:
  159. if ( list.grep( "NT_STATUS" ).count() != 0 )
  160. {
  161. // Something went wrong. Let's check if this "only" an
  162. // authentication issue or if we have to error out:
  163. TQString error_code = list.grep( "NT_STATUS" ).first().stripWhiteSpace().section( " ", 0, 0 );
  164. // The error output of smbclient is a little bit inconsistent:
  165. if ( error_code.contains( "NT_STATUS" ) == 0 )
  166. {
  167. error_code = list.grep( "NT_STATUS" ).first().stripWhiteSpace().section( " ", -1, -1 );
  168. }
  169. // Authentication issue?
  170. if ( TQString::compare( error_code, "NT_STATUS_ACCESS_DENIED" ) == 0 ||
  171. TQString::compare( error_code, "NT_STATUS_LOGON_FAILURE" ) == 0 )
  172. {
  173. int state = Smb4KPasswordHandler::None;
  174. if ( TQString::compare( error_code, "NT_STATUS_ACCESS_DENIED" ) == 0 )
  175. {
  176. state = Smb4KPasswordHandler::AccessDenied;
  177. }
  178. else if ( TQString::compare( error_code, "NT_STATUS_LOGON_FAILURE" ) == 0 )
  179. {
  180. state = Smb4KPasswordHandler::LogonFailure;
  181. }
  182. if ( passwordHandler()->askpass( m_item->workgroup(), m_item->host(),
  183. m_item->share(), state,
  184. kapp->mainWidget() ? kapp->mainWidget() : 0,
  185. "AskPass" ) )
  186. {
  187. // Now we have a password. Retry.
  188. // NOTE: Since the item is appended to the queue, there might
  189. // be the case, that another preview is generated before the
  190. // retry is executed. I think, we can live with that.
  191. preview( m_item );
  192. }
  193. else
  194. {
  195. // The user cancelled the askpass dialog. We won't show an
  196. // error dialog here, but will only clear the contents of
  197. // the preview item and emit the failed() signal.
  198. m_item->clearContents();
  199. emit failed();
  200. }
  201. }
  202. else
  203. {
  204. // OK, error out. We cannot recover from it:
  205. Smb4KError::error( ERROR_GETTING_PREVIEW, TQString(), m_buffer );
  206. m_item->clearContents();
  207. emit failed();
  208. }
  209. }
  210. else if ( list.grep( "Connection to" ).count() != 0 ||
  211. (list.grep( "Error returning browse list:" ).count() != 0 &&
  212. list.grep( "NT_STATUS" ).count() == 0) )
  213. {
  214. // These are errors that we cannot work around. Error out.
  215. Smb4KError::error( ERROR_GETTING_PREVIEW, TQString(), m_buffer );
  216. m_item->clearContents();
  217. emit failed();
  218. }
  219. else
  220. {
  221. for ( TQStringList::Iterator it = list.begin(); it != list.end(); ++it )
  222. {
  223. if ( (*it).stripWhiteSpace().startsWith( "Domain" ) ||
  224. (*it).stripWhiteSpace().startsWith( "OS" ) ||
  225. (*it).stripWhiteSpace().startsWith( "Anonymous" ) )
  226. {
  227. continue;
  228. }
  229. else if ( (*it).contains( "blocks of size" ) != 0 )
  230. {
  231. continue;
  232. }
  233. else
  234. {
  235. TQString tmp = (*it).stripWhiteSpace().section( " ", 0, -9 ).stripWhiteSpace();
  236. TQString item = tmp.section( " ", 0, -2 ).stripWhiteSpace();
  237. if ( !item.isEmpty() && tmp.section( " ", -1, -1 ).contains( "D" ) != 0 )
  238. {
  239. // We have a directory here.
  240. if ( item.startsWith( "." ) &&
  241. (TQString::compare( item.stripWhiteSpace(), "." ) != 0 &&
  242. TQString::compare( item.stripWhiteSpace(), ".." ) != 0) )
  243. {
  244. m_item->addContents( ContentsItem( Smb4KPreviewItem::HiddenDirectory, item ) );
  245. }
  246. else
  247. {
  248. m_item->addContents( ContentsItem( Smb4KPreviewItem::Directory, item ) );
  249. }
  250. continue;
  251. }
  252. else if ( item.isEmpty() || tmp.section( " ", -1, -1 ).contains( "D" ) == 0 )
  253. {
  254. // We have a file
  255. if ( item.isEmpty() )
  256. {
  257. if ( tmp.startsWith( "." ) )
  258. {
  259. m_item->addContents( ContentsItem( Smb4KPreviewItem::HiddenFile, tmp ) );
  260. }
  261. else
  262. {
  263. m_item->addContents( ContentsItem( Smb4KPreviewItem::File, tmp ) );
  264. }
  265. }
  266. else
  267. {
  268. if ( item.startsWith( "." ) )
  269. {
  270. m_item->addContents( ContentsItem( Smb4KPreviewItem::HiddenFile, item ) );
  271. }
  272. else
  273. {
  274. m_item->addContents( ContentsItem( Smb4KPreviewItem::File, item ) );
  275. }
  276. }
  277. continue;
  278. }
  279. else
  280. {
  281. continue;
  282. }
  283. }
  284. }
  285. }
  286. emit result( m_item );
  287. TQApplication::restoreOverrideCursor();
  288. m_working = false;
  289. emit state( PREVIEWER_STOP );
  290. }
  291. #include "smb4kpreviewer.moc"