1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 /* 25 * This file pinched from webdavdatasupplier (etc.) 26 * cut & paste + new getData impl. & collate ResultSet code. 27 */ 28 #include <vector> 29 #include <osl/diagnose.h> 30 #include <com/sun/star/ucb/OpenMode.hpp> 31 #include <ucbhelper/contentidentifier.hxx> 32 #include <ucbhelper/providerhelper.hxx> 33 34 #include "gvfs_directory.hxx" 35 36 #include <libgnomevfs/gnome-vfs-utils.h> 37 #include <libgnomevfs/gnome-vfs-directory.h> 38 39 using namespace com::sun::star; 40 using namespace gvfs; 41 42 // DynamicResultSet Implementation. 43 44 DynamicResultSet::DynamicResultSet( 45 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 46 const rtl::Reference< Content >& rxContent, 47 const ucb::OpenCommandArgument2& rCommand, 48 const uno::Reference< ucb::XCommandEnvironment >& rxEnv ) 49 : ResultSetImplHelper( rxSMgr, rCommand ), 50 m_xContent( rxContent ), 51 m_xEnv( rxEnv ) 52 { 53 } 54 void DynamicResultSet::initStatic() 55 { 56 m_xResultSet1 57 = new ::ucbhelper::ResultSet( m_xSMgr, 58 m_aCommand.Properties, 59 new DataSupplier( m_xSMgr, 60 m_xContent, 61 m_aCommand.Mode ), 62 m_xEnv ); 63 } 64 void DynamicResultSet::initDynamic() 65 { 66 initStatic(); 67 m_xResultSet2 = m_xResultSet1; 68 } 69 70 //========================================================================= 71 72 73 // DataSupplier Implementation. 74 75 76 77 struct ResultListEntry 78 { 79 rtl::OUString aId; 80 uno::Reference< ucb::XContentIdentifier > xId; 81 uno::Reference< ucb::XContent > xContent; 82 uno::Reference< sdbc::XRow > xRow; 83 GnomeVFSFileInfo aInfo; 84 85 ResultListEntry( const GnomeVFSFileInfo *fileInfo) 86 { 87 gnome_vfs_file_info_copy (&aInfo, fileInfo); 88 } 89 90 ~ResultListEntry() 91 { 92 gnome_vfs_file_info_clear (&aInfo); 93 } 94 }; 95 96 //========================================================================= 97 // 98 // ResultList. 99 // 100 //========================================================================= 101 102 typedef std::vector< ResultListEntry* > ResultList; 103 104 //========================================================================= 105 // 106 // struct DataSupplier_Impl. 107 // 108 //========================================================================= 109 110 struct gvfs::DataSupplier_Impl 111 { 112 osl::Mutex m_aMutex; 113 ResultList m_aResults; 114 rtl::Reference< Content > m_xContent; 115 uno::Reference< lang::XMultiServiceFactory > m_xSMgr; 116 sal_Int32 m_nOpenMode; 117 sal_Bool m_bCountFinal; 118 119 DataSupplier_Impl( 120 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 121 const rtl::Reference< Content >& rContent, 122 sal_Int32 nOpenMode ) 123 : m_xContent( rContent ), m_xSMgr( rxSMgr ), 124 m_nOpenMode( nOpenMode ), m_bCountFinal( sal_False ) {} 125 ~DataSupplier_Impl() 126 { 127 ResultList::const_iterator it = m_aResults.begin(); 128 ResultList::const_iterator end = m_aResults.end(); 129 130 while ( it != end ) 131 { 132 delete (*it); 133 it++; 134 } 135 } 136 }; 137 138 DataSupplier::DataSupplier( 139 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 140 const rtl::Reference< Content >& rContent, 141 sal_Int32 nOpenMode ) 142 : m_pImpl( new DataSupplier_Impl( rxSMgr, rContent, nOpenMode ) ) 143 { 144 } 145 146 //========================================================================= 147 // virtual 148 DataSupplier::~DataSupplier() 149 { 150 delete m_pImpl; 151 } 152 153 // virtual 154 rtl::OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex ) 155 { 156 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 157 158 if ( nIndex < m_pImpl->m_aResults.size() ) { 159 rtl::OUString aId = m_pImpl->m_aResults[ nIndex ]->aId; 160 if ( aId.getLength() ) // cached 161 return aId; 162 } 163 164 if ( getResult( nIndex ) ) { 165 rtl::OUString aId = m_pImpl->m_xContent->getOUURI(); 166 167 char *escaped_name; 168 escaped_name = gnome_vfs_escape_string( m_pImpl->m_aResults[ nIndex ]->aInfo.name ); 169 170 if ( ( aId.lastIndexOf( '/' ) + 1 ) != aId.getLength() ) 171 aId += rtl::OUString::createFromAscii( "/" ); 172 173 aId += rtl::OUString::createFromAscii( escaped_name ); 174 175 g_free( escaped_name ); 176 177 m_pImpl->m_aResults[ nIndex ]->aId = aId; 178 return aId; 179 } 180 181 return rtl::OUString(); 182 } 183 184 // virtual 185 uno::Reference< ucb::XContentIdentifier > 186 DataSupplier::queryContentIdentifier( sal_uInt32 nIndex ) 187 { 188 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 189 190 if ( nIndex < m_pImpl->m_aResults.size() ) { 191 uno::Reference< ucb::XContentIdentifier > xId 192 = m_pImpl->m_aResults[ nIndex ]->xId; 193 if ( xId.is() ) // Already cached. 194 return xId; 195 } 196 197 rtl::OUString aId = queryContentIdentifierString( nIndex ); 198 if ( aId.getLength() ) { 199 uno::Reference< ucb::XContentIdentifier > xId 200 = new ::ucbhelper::ContentIdentifier( aId ); 201 m_pImpl->m_aResults[ nIndex ]->xId = xId; 202 return xId; 203 } 204 205 return uno::Reference< ucb::XContentIdentifier >(); 206 } 207 208 // virtual 209 uno::Reference< ucb::XContent > 210 DataSupplier::queryContent( sal_uInt32 nIndex ) 211 { 212 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 213 214 if ( nIndex < m_pImpl->m_aResults.size() ) { 215 uno::Reference< ucb::XContent > xContent 216 = m_pImpl->m_aResults[ nIndex ]->xContent; 217 if ( xContent.is() ) // Already cached. 218 return xContent; 219 } 220 221 uno::Reference< ucb::XContentIdentifier > xId 222 = queryContentIdentifier( nIndex ); 223 if ( xId.is() ) { 224 try 225 { 226 // FIXME: 227 // It would be really nice to propagate this information 228 // to the Content, but we can't then register it with the 229 // ContentProvider, and the ucbhelper hinders here. 230 uno::Reference< ucb::XContent > xContent 231 = m_pImpl->m_xContent->getProvider()->queryContent( xId ); 232 m_pImpl->m_aResults[ nIndex ]->xContent = xContent; 233 return xContent; 234 235 } 236 catch ( ucb::IllegalIdentifierException& ) { 237 } 238 } 239 return uno::Reference< ucb::XContent >(); 240 } 241 242 // virtual 243 sal_Bool DataSupplier::getResult( sal_uInt32 nIndex ) 244 { 245 osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 246 247 if ( m_pImpl->m_aResults.size() > nIndex ) // Result already present. 248 return sal_True; 249 250 if ( getData() && m_pImpl->m_aResults.size() > nIndex ) 251 return sal_True; 252 253 return sal_False; 254 } 255 256 // virtual 257 sal_uInt32 DataSupplier::totalCount() 258 { 259 getData(); 260 261 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 262 263 return m_pImpl->m_aResults.size(); 264 } 265 266 // virtual 267 sal_uInt32 DataSupplier::currentCount() 268 { 269 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 270 return m_pImpl->m_aResults.size(); 271 } 272 273 // virtual 274 sal_Bool DataSupplier::isCountFinal() 275 { 276 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 277 return m_pImpl->m_bCountFinal; 278 } 279 280 // virtual 281 uno::Reference< sdbc::XRow > DataSupplier::queryPropertyValues( sal_uInt32 nIndex ) 282 { 283 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 284 285 if ( nIndex < m_pImpl->m_aResults.size() ) { 286 uno::Reference< sdbc::XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow; 287 if ( xRow.is() ) // Already cached. 288 return xRow; 289 } 290 291 if ( getResult( nIndex ) ) { 292 // Inefficient - but we can't create xContent's sensibly 293 // nor can we do the property code sensibly cleanly staticaly. 294 Content *pContent = static_cast< ::gvfs::Content * >(queryContent( nIndex ).get()); 295 296 uno::Reference< sdbc::XRow > xRow = 297 pContent->getPropertyValues( getResultSet()->getProperties(), 298 getResultSet()->getEnvironment() ); 299 300 m_pImpl->m_aResults[ nIndex ]->xRow = xRow; 301 302 return xRow; 303 } 304 305 return uno::Reference< sdbc::XRow >(); 306 } 307 308 // virtual 309 void DataSupplier::releasePropertyValues( sal_uInt32 nIndex ) 310 { 311 osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 312 313 if ( nIndex < m_pImpl->m_aResults.size() ) 314 m_pImpl->m_aResults[ nIndex ]->xRow = uno::Reference< sdbc::XRow >(); 315 } 316 317 // virtual 318 void DataSupplier::close() 319 { 320 } 321 322 // virtual 323 void DataSupplier::validate() 324 throw( ucb::ResultSetException ) 325 { 326 } 327 328 sal_Bool DataSupplier::getData() 329 { 330 osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); 331 332 if ( !m_pImpl->m_bCountFinal ) { 333 GnomeVFSResult result; 334 GnomeVFSDirectoryHandle *dirHandle = NULL; 335 336 { 337 Authentication aAuth( getResultSet()->getEnvironment() ); 338 char *uri = m_pImpl->m_xContent->getURI(); 339 result = gnome_vfs_directory_open 340 ( &dirHandle, uri, GNOME_VFS_FILE_INFO_DEFAULT ); 341 342 if (result != GNOME_VFS_OK) { 343 #ifdef DEBUG 344 g_warning ("Failed open of '%s' with '%s'", 345 uri, gnome_vfs_result_to_string( result )); 346 #endif 347 g_free( uri ); 348 return sal_False; 349 } 350 351 g_free( uri ); 352 } 353 354 GnomeVFSFileInfo* fileInfo = gnome_vfs_file_info_new (); 355 356 while ((result = gnome_vfs_directory_read_next (dirHandle, fileInfo)) == GNOME_VFS_OK) { 357 if( fileInfo->name && fileInfo->name[0] == '.' && 358 ( fileInfo->name[1] == '\0' || 359 ( fileInfo->name[1] == '.' && fileInfo->name[2] == '\0' ) ) ) 360 continue; 361 362 switch ( m_pImpl->m_nOpenMode ) { 363 case ucb::OpenMode::FOLDERS: 364 if ( !(fileInfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) || 365 fileInfo->type != GNOME_VFS_FILE_TYPE_DIRECTORY ) 366 continue; 367 break; 368 369 case ucb::OpenMode::DOCUMENTS: 370 if ( !(fileInfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) || 371 fileInfo->type != GNOME_VFS_FILE_TYPE_REGULAR ) 372 continue; 373 break; 374 375 case ucb::OpenMode::ALL: 376 default: 377 break; 378 } 379 380 m_pImpl->m_aResults.push_back( new ResultListEntry( fileInfo ) ); 381 } 382 383 gnome_vfs_file_info_unref (fileInfo); 384 385 #ifdef DEBUG 386 g_warning ("Got %d directory entries", result); 387 #endif 388 389 m_pImpl->m_bCountFinal = sal_True; 390 391 // Callback possible, because listeners may be informed! 392 aGuard.clear(); 393 getResultSet()->rowCountFinal(); 394 395 if (result != GNOME_VFS_ERROR_EOF) { 396 #ifdef DEBUG 397 g_warning( "Failed read_next '%s'", 398 gnome_vfs_result_to_string( result ) ); 399 #endif 400 return sal_False; 401 } 402 403 result = gnome_vfs_directory_close (dirHandle); 404 if (result != GNOME_VFS_OK) { 405 #ifdef DEBUG 406 g_warning( "Failed close '%s'", 407 gnome_vfs_result_to_string( result ) ); 408 #endif 409 return sal_False; 410 } 411 } 412 413 return sal_True; 414 } 415