1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_ucb.hxx" 30 #include <string.h> 31 #include <unistd.h> 32 #include <sys/types.h> 33 34 #include "osl/time.h" 35 #include <osl/diagnose.h> 36 37 #include "osl/doublecheckedlocking.h" 38 39 #include <com/sun/star/beans/PropertyValue.hpp> 40 #include <com/sun/star/beans/PropertyAttribute.hpp> 41 #include <com/sun/star/beans/PropertySetInfoChange.hpp> 42 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp> 43 #include <com/sun/star/io/XActiveDataSink.hpp> 44 #include <com/sun/star/io/XOutputStream.hpp> 45 #include <com/sun/star/lang/IllegalAccessException.hpp> 46 #include <com/sun/star/ucb/ContentInfoAttribute.hpp> 47 #include <com/sun/star/ucb/InsertCommandArgument.hpp> 48 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp> 49 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> 50 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp> 51 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp> 52 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp> 53 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp> 54 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp> 55 #include <com/sun/star/ucb/NameClash.hpp> 56 #include <com/sun/star/ucb/NameClashException.hpp> 57 #include <com/sun/star/ucb/OpenCommandArgument2.hpp> 58 #include <com/sun/star/ucb/OpenMode.hpp> 59 #include <com/sun/star/ucb/PostCommandArgument2.hpp> 60 #include <com/sun/star/ucb/TransferInfo.hpp> 61 #include <com/sun/star/ucb/XCommandInfo.hpp> 62 #include <com/sun/star/ucb/XPersistentPropertySet.hpp> 63 #include <com/sun/star/ucb/MissingInputStreamException.hpp> 64 #include <com/sun/star/ucb/MissingPropertiesException.hpp> 65 #include <com/sun/star/ucb/UnsupportedCommandException.hpp> 66 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> 67 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp> 68 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> 69 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> 70 #include <com/sun/star/ucb/NameClashException.hpp> 71 #include <ucbhelper/contentidentifier.hxx> 72 #include <ucbhelper/propertyvalueset.hxx> 73 #include <ucbhelper/interactionrequest.hxx> 74 #include <ucbhelper/cancelcommandexecution.hxx> 75 #include <ucbhelper/simpleauthenticationrequest.hxx> 76 77 const int TRANSFER_BUFFER_SIZE = 65536; 78 79 /* 80 * NB. Name escaping is done only for URIs 81 * the 'Title' property is unescaped on set/get 82 */ 83 #include <libgnomevfs/gnome-vfs-utils.h> 84 #include <libgnomevfs/gnome-vfs-result.h> 85 #include <libgnomevfs/gnome-vfs-standard-callbacks.h> 86 extern "C" { // missing in the header: doh. 87 # include <libgnomevfs/gnome-vfs-module-callback.h> 88 } 89 90 #include "gvfs_content.hxx" 91 #include "gvfs_provider.hxx" 92 #include "gvfs_directory.hxx" 93 #include "gvfs_stream.hxx" 94 95 using namespace gvfs; 96 using namespace com::sun::star; 97 98 #define CLEAR_INFO(info) memset((info), 0, sizeof ((info)[0])) 99 100 101 static char * 102 OUStringToGnome( const rtl::OUString &str ) 103 { 104 rtl::OString aTempStr = rtl::OUStringToOString( str, RTL_TEXTENCODING_UTF8 ); 105 return g_strdup( (const sal_Char *) aTempStr ); 106 } 107 108 static rtl::OUString 109 GnomeToOUString( const char *utf8_str) 110 { 111 if (!utf8_str) 112 return rtl::OUString(); 113 else 114 return rtl::OUString( utf8_str, strlen( utf8_str ), RTL_TEXTENCODING_UTF8 ); 115 } 116 117 118 Content::Content( 119 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 120 ContentProvider* pProvider, 121 const uno::Reference< ucb::XContentIdentifier >& Identifier) 122 throw ( ucb::ContentCreationException ) 123 : ContentImplHelper( rxSMgr, pProvider, Identifier ), 124 m_pProvider( pProvider ), 125 m_bTransient( sal_False ) 126 { 127 CLEAR_INFO (&m_info); 128 #ifdef DEBUG 129 g_warning ("New Content ('%s')", getURI()); 130 #endif 131 } 132 133 Content::Content( 134 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 135 ContentProvider * pProvider, 136 const uno::Reference< ucb::XContentIdentifier >& Identifier, 137 sal_Bool IsFolder) 138 throw ( ucb::ContentCreationException ) 139 : ContentImplHelper( rxSMgr, pProvider, Identifier ), 140 m_pProvider( pProvider ), 141 m_bTransient( sal_True ) 142 { 143 CLEAR_INFO (&m_info); 144 145 #ifdef DEBUG 146 g_warning ("New Transient content ('%s') (%d)", getURI(), IsFolder); 147 #endif 148 // m_info.name = FIXME: set name ? 149 m_info.valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE; 150 m_info.type = IsFolder ? GNOME_VFS_FILE_TYPE_DIRECTORY : 151 GNOME_VFS_FILE_TYPE_REGULAR; 152 } 153 154 // virtual 155 Content::~Content() 156 { 157 gnome_vfs_file_info_clear( &m_info ); 158 } 159 160 // 161 // XInterface methods. 162 // 163 164 void SAL_CALL Content::acquire() 165 throw( ) 166 { 167 ContentImplHelper::acquire(); 168 } 169 void SAL_CALL Content::release() 170 throw( ) 171 { 172 ContentImplHelper::release(); 173 } 174 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) 175 throw ( uno::RuntimeException ) 176 { 177 // Note: isFolder may require network activities! So call it only 178 // if it is really necessary!!! 179 uno::Any aRet = cppu::queryInterface( rType, 180 static_cast< ucb::XContentCreator * >( this ) ); 181 if ( aRet.hasValue() ) 182 return isFolder( uno::Reference< ucb::XCommandEnvironment >() ) 183 ? aRet : uno::Any(); 184 else 185 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType ); 186 } 187 188 // 189 // XTypeProvider methods. 190 // 191 192 XTYPEPROVIDER_COMMON_IMPL( Content ); 193 194 uno::Sequence< uno::Type > SAL_CALL Content::getTypes() 195 throw( uno::RuntimeException ) 196 { 197 static cppu::OTypeCollection *pFolderCollection = NULL; 198 static cppu::OTypeCollection *pFileCollection = NULL; 199 200 if (!pFolderCollection) { 201 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 202 203 if (!pFolderCollection) { 204 static cppu::OTypeCollection aFolderCollection 205 (CPPU_TYPE_REF( lang::XTypeProvider ), 206 CPPU_TYPE_REF( lang::XServiceInfo ), 207 CPPU_TYPE_REF( lang::XComponent ), 208 CPPU_TYPE_REF( ucb::XContent ), 209 CPPU_TYPE_REF( ucb::XCommandProcessor ), 210 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), 211 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), 212 CPPU_TYPE_REF( beans::XPropertyContainer ), 213 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), 214 CPPU_TYPE_REF( container::XChild ), 215 CPPU_TYPE_REF( ucb::XContentCreator ) ); // !! 216 static cppu::OTypeCollection aFileCollection 217 (CPPU_TYPE_REF( lang::XTypeProvider ), 218 CPPU_TYPE_REF( lang::XServiceInfo ), 219 CPPU_TYPE_REF( lang::XComponent ), 220 CPPU_TYPE_REF( ucb::XContent ), 221 CPPU_TYPE_REF( ucb::XCommandProcessor ), 222 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), 223 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), 224 CPPU_TYPE_REF( beans::XPropertyContainer ), 225 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), 226 CPPU_TYPE_REF( container::XChild ) ); 227 228 pFolderCollection = &aFolderCollection; 229 pFileCollection = &aFileCollection; 230 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 231 } 232 } 233 else { 234 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 235 } 236 237 if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) ) 238 return pFolderCollection->getTypes(); 239 else 240 return pFileCollection->getTypes(); 241 } 242 243 // 244 // XServiceInfo methods. 245 // 246 247 rtl::OUString SAL_CALL Content::getImplementationName() 248 throw( uno::RuntimeException ) 249 { 250 return rtl::OUString::createFromAscii("com.sun.star.comp.GnomeVFSContent" ); 251 } 252 253 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames() 254 throw( uno::RuntimeException ) 255 { 256 uno::Sequence< rtl::OUString > aSNS( 1 ); 257 aSNS.getArray()[ 0 ] = rtl::OUString::createFromAscii( 258 "com.sun.star.ucb.GnomeVFSContent" ); 259 return aSNS; 260 } 261 262 // 263 // XContent methods. 264 // 265 266 rtl::OUString SAL_CALL Content::getContentType() 267 throw( uno::RuntimeException ) 268 { 269 if ( isFolder( uno::Reference< ucb::XCommandEnvironment >() ) ) 270 return rtl::OUString::createFromAscii( GVFS_FOLDER_TYPE ); 271 else 272 return rtl::OUString::createFromAscii( GVFS_FILE_TYPE ); 273 } 274 275 // 276 // XCommandProcessor methods. 277 // 278 279 uno::Any Content::getBadArgExcept() 280 { 281 return uno::makeAny( lang::IllegalArgumentException 282 ( rtl::OUString::createFromAscii( "Wrong argument type!" ), 283 static_cast< cppu::OWeakObject * >( this ), 284 -1 ) ); 285 } 286 287 #include <stdio.h> 288 289 uno::Any SAL_CALL Content::execute( 290 const ucb::Command& aCommand, 291 sal_Int32 /*CommandId*/, 292 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 293 throw( uno::Exception, 294 ucb::CommandAbortedException, 295 uno::RuntimeException ) 296 { 297 uno::Any aRet; 298 299 #ifdef DEBUG 300 { 301 uno::Reference< task::XInteractionHandler > xIH; 302 303 if ( xEnv.is() ) 304 xIH = xEnv->getInteractionHandler(); 305 g_warning( "Execute command: '%s' with %s interaction env", 306 OUStringToGnome( aCommand.Name ), 307 xIH.is() ? "" : "NO" ); 308 } 309 #endif 310 311 #define COMMAND_IS(cmd,name) ( (cmd).Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( name ) ) ) 312 313 if ( COMMAND_IS( aCommand, "getPropertyValues" ) ) { 314 uno::Sequence< beans::Property > Properties; 315 316 if ( !( aCommand.Argument >>= Properties ) ) 317 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv ); 318 319 aRet <<= getPropertyValues( Properties, xEnv ); 320 321 } else if ( COMMAND_IS( aCommand, "setPropertyValues" ) ) { 322 uno::Sequence< beans::PropertyValue > aProperties; 323 324 if ( !( aCommand.Argument >>= aProperties ) || 325 !aProperties.getLength() ) 326 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv ); 327 328 aRet <<= setPropertyValues( aProperties, xEnv ); 329 330 } else if ( COMMAND_IS( aCommand, "getPropertySetInfo" ) ) { 331 aRet <<= getPropertySetInfo( xEnv, sal_False ); 332 333 } else if ( COMMAND_IS( aCommand, "getCommandInfo" ) ) { 334 aRet <<= getCommandInfo( xEnv, sal_False ); 335 336 } else if ( COMMAND_IS( aCommand, "open" ) ) { 337 rtl::OUString str = m_xIdentifier->getContentIdentifier(); 338 rtl::OString stra( 339 str.getStr(), 340 str.getLength(), 341 RTL_TEXTENCODING_UTF8); 342 343 ucb::OpenCommandArgument2 aOpenCommand; 344 if ( !( aCommand.Argument >>= aOpenCommand ) ) 345 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv ); 346 347 sal_Bool bOpenFolder = 348 ( ( aOpenCommand.Mode == ucb::OpenMode::ALL ) || 349 ( aOpenCommand.Mode == ucb::OpenMode::FOLDERS ) || 350 ( aOpenCommand.Mode == ucb::OpenMode::DOCUMENTS ) ); 351 352 if ( bOpenFolder && isFolder( xEnv ) ) { 353 uno::Reference< ucb::XDynamicResultSet > xSet 354 = new DynamicResultSet(m_xSMgr, this, aOpenCommand, xEnv ); 355 aRet <<= xSet; 356 357 } else if ( aOpenCommand.Sink.is() ) { 358 359 if ( ( aOpenCommand.Mode 360 == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) || 361 ( aOpenCommand.Mode 362 == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) ) { 363 ucbhelper::cancelCommandExecution 364 ( uno::makeAny ( ucb::UnsupportedOpenModeException 365 ( rtl::OUString(), 366 static_cast< cppu::OWeakObject * >( this ), 367 sal_Int16( aOpenCommand.Mode ) ) ), 368 xEnv ); 369 } 370 if ( !feedSink( aOpenCommand.Sink, xEnv ) ) { 371 // Note: aOpenCommand.Sink may contain an XStream 372 // implementation. Support for this type of 373 // sink is optional... 374 #ifdef DEBUG 375 g_warning ("Failed to load data from '%s'", getURI()); 376 #endif 377 ucbhelper::cancelCommandExecution 378 ( uno::makeAny (ucb::UnsupportedDataSinkException 379 ( rtl::OUString(), 380 static_cast< cppu::OWeakObject * >( this ), 381 aOpenCommand.Sink ) ), 382 xEnv ); 383 } 384 } 385 #ifdef DEBUG 386 else 387 g_warning ("Open falling through ..."); 388 #endif 389 390 } else if ( COMMAND_IS( aCommand, "createNewContent" ) && isFolder( xEnv ) ) { 391 ucb::ContentInfo arg; 392 if ( !( aCommand.Argument >>= arg ) ) 393 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv ); 394 395 aRet <<= createNewContent( arg ); 396 397 } else if ( COMMAND_IS( aCommand, "insert" ) ) { 398 ucb::InsertCommandArgument arg; 399 if ( !( aCommand.Argument >>= arg ) ) 400 ucbhelper::cancelCommandExecution ( getBadArgExcept (), xEnv ); 401 402 insert( arg.Data, arg.ReplaceExisting, xEnv ); 403 404 } else if ( COMMAND_IS( aCommand, "delete" ) ) { 405 406 sal_Bool bDeletePhysical = sal_False; 407 aCommand.Argument >>= bDeletePhysical; 408 409 ::rtl::OString aURI = getOURI(); 410 GnomeVFSResult result = gnome_vfs_unlink ((const sal_Char *) aURI); 411 412 if (result != GNOME_VFS_OK) 413 cancelCommandExecution( result, xEnv, sal_True ); 414 415 destroy( bDeletePhysical ); 416 417 } else if ( COMMAND_IS( aCommand, "transfer" ) && isFolder( xEnv ) ) { 418 ucb::TransferInfo transferArgs; 419 420 if ( !( aCommand.Argument >>= transferArgs ) ) 421 ucbhelper::cancelCommandExecution( getBadArgExcept(), xEnv ); 422 423 transfer( transferArgs, xEnv ); 424 425 } else { // Unsuported 426 #ifdef DEBUG 427 g_warning( "Unsupported command: '%s'", 428 OUStringToGnome( aCommand.Name ) ); 429 #endif 430 ucbhelper::cancelCommandExecution 431 ( uno::makeAny( ucb::UnsupportedCommandException 432 ( rtl::OUString(), 433 static_cast< cppu::OWeakObject * >( this ) ) ), 434 xEnv ); 435 } 436 #undef COMMAND_IS 437 438 return aRet; 439 } 440 441 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) 442 throw( uno::RuntimeException ) 443 { 444 // FIXME: we should use the GnomeVFSCancellation APIs here ... 445 } 446 447 // 448 // XContentCreator methods. 449 // 450 451 uno::Sequence< ucb::ContentInfo > Content::queryCreatableContentsInfo( 452 const uno::Reference< ucb::XCommandEnvironment >& xEnv) 453 throw( uno::RuntimeException ) 454 { 455 if ( isFolder( xEnv ) ) 456 { 457 uno::Sequence< ucb::ContentInfo > seq(2); 458 459 // Minimum set of props we really need 460 uno::Sequence< beans::Property > props( 1 ); 461 props[0] = beans::Property( 462 rtl::OUString::createFromAscii( "Title" ), 463 -1, 464 getCppuType( static_cast< rtl::OUString* >( 0 ) ), 465 beans::PropertyAttribute::MAYBEVOID | beans::PropertyAttribute::BOUND ); 466 467 // file 468 seq[0].Type = rtl::OUString::createFromAscii( GVFS_FILE_TYPE ); 469 seq[0].Attributes = ( ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM | 470 ucb::ContentInfoAttribute::KIND_DOCUMENT ); 471 seq[0].Properties = props; 472 473 // folder 474 seq[1].Type = rtl::OUString::createFromAscii( GVFS_FOLDER_TYPE ); 475 seq[1].Attributes = ucb::ContentInfoAttribute::KIND_FOLDER; 476 seq[1].Properties = props; 477 478 return seq; 479 } 480 else 481 { 482 return uno::Sequence< ucb::ContentInfo >(); 483 } 484 } 485 486 uno::Sequence< ucb::ContentInfo > SAL_CALL Content::queryCreatableContentsInfo() 487 throw( uno::RuntimeException ) 488 { 489 return queryCreatableContentsInfo( uno::Reference< ucb::XCommandEnvironment >() ); 490 } 491 492 uno::Reference< ucb::XContent > SAL_CALL 493 Content::createNewContent( const ucb::ContentInfo& Info ) 494 throw( uno::RuntimeException ) 495 { 496 bool create_document; 497 const char *name; 498 499 if ( Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( GVFS_FILE_TYPE ) ) ) 500 create_document = true; 501 else if ( Info.Type.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( GVFS_FOLDER_TYPE ) ) ) 502 create_document = false; 503 else { 504 #ifdef DEBUG 505 g_warning( "Failed to create new content '%s'", 506 OUStringToGnome( Info.Type ) ); 507 #endif 508 return uno::Reference< ucb::XContent >(); 509 } 510 511 #ifdef DEBUG 512 g_warning( "createNewContent (%d)", (int) create_document ); 513 #endif 514 515 rtl::OUString aURL = getOUURI(); 516 517 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() ) 518 aURL += rtl::OUString::createFromAscii( "/" ); 519 520 name = create_document ? "[New_Content]" : "[New_Collection]"; 521 // This looks problematic to me cf. webdav 522 aURL += rtl::OUString::createFromAscii( name ); 523 524 uno::Reference< ucb::XContentIdentifier > xId 525 ( new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) ); 526 527 try { 528 return new ::gvfs::Content( m_xSMgr, m_pProvider, xId, !create_document ); 529 } catch ( ucb::ContentCreationException & ) { 530 return uno::Reference< ucb::XContent >(); 531 } 532 } 533 534 rtl::OUString Content::getParentURL() 535 { 536 rtl::OUString aParentURL; 537 // <scheme>:// -> "" 538 // <scheme>://foo -> "" 539 // <scheme>://foo/ -> "" 540 // <scheme>://foo/bar -> <scheme>://foo/ 541 // <scheme>://foo/bar/ -> <scheme>://foo/ 542 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/ 543 544 rtl::OUString aURL = getOUURI(); 545 546 sal_Int32 nPos = aURL.lastIndexOf( '/' ); 547 if ( nPos == ( aURL.getLength() - 1 ) ) { 548 // Trailing slash found. Skip. 549 nPos = aURL.lastIndexOf( '/', nPos ); 550 } 551 552 sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos ); 553 if ( nPos1 != -1 ) 554 nPos1 = aURL.lastIndexOf( '/', nPos1 ); 555 556 if ( nPos1 != -1 ) 557 aParentURL = rtl::OUString( aURL.copy( 0, nPos + 1 ) ); 558 559 #ifdef DEBUG 560 g_warning ("getParentURL '%s' -> '%s'", 561 getURI(), (const sal_Char *) rtl::OUStringToOString 562 ( aParentURL, RTL_TEXTENCODING_UTF8 ) ); 563 #endif 564 565 return aParentURL; 566 } 567 568 static util::DateTime 569 getDateFromUnix (time_t t) 570 { 571 TimeValue tv; 572 tv.Nanosec = 0; 573 tv.Seconds = t; 574 oslDateTime dt; 575 576 if ( osl_getDateTimeFromTimeValue( &tv, &dt ) ) 577 return util::DateTime( 0, dt.Seconds, dt.Minutes, dt.Hours, 578 dt.Day, dt.Month, dt.Year); 579 else 580 return util::DateTime(); 581 } 582 583 uno::Reference< sdbc::XRow > Content::getPropertyValues( 584 const uno::Sequence< beans::Property >& rProperties, 585 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 586 { 587 int nProps; 588 GnomeVFSResult result; 589 uno::Sequence< beans::Property > allProperties; 590 591 if( ( result = getInfo( xEnv ) ) != GNOME_VFS_OK ) 592 cancelCommandExecution( result, xEnv, sal_False ); 593 594 const beans::Property* pProps; 595 596 if( rProperties.getLength() ) { 597 nProps = rProperties.getLength(); 598 pProps = rProperties.getConstArray(); 599 } else { 600 allProperties = getPropertySetInfo( xEnv )->getProperties(); 601 nProps = allProperties.getLength(); 602 pProps = allProperties.getConstArray(); 603 } 604 605 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow 606 = new ::ucbhelper::PropertyValueSet( m_xSMgr ); 607 608 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 609 for( sal_Int32 n = 0; n < nProps; ++n ) { 610 const beans::Property& rProp = pProps[ n ]; 611 612 if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) { 613 if (m_info.name && m_info.name[0] == '/') 614 g_warning ("Odd NFS title on item '%s' == '%s'", 615 getURI(), m_info.name); 616 xRow->appendString( rProp, GnomeToOUString( m_info.name ) ); 617 } 618 619 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) 620 xRow->appendString( rProp, getContentType () ); 621 622 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) { 623 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) 624 xRow->appendBoolean( rProp, ( m_info.type == GNOME_VFS_FILE_TYPE_REGULAR || 625 m_info.type == GNOME_VFS_FILE_TYPE_UNKNOWN ) ); 626 else 627 xRow->appendVoid( rProp ); 628 } 629 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) { 630 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) 631 xRow->appendBoolean( rProp, ( m_info.type == GNOME_VFS_FILE_TYPE_DIRECTORY ) ); 632 else 633 xRow->appendVoid( rProp ); 634 } 635 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsReadOnly" ) ) ) { 636 637 GnomeVFSFileInfo* fileInfo = gnome_vfs_file_info_new (); 638 639 ::rtl::OString aURI = getOURI(); 640 gnome_vfs_get_file_info 641 ( (const sal_Char *)aURI, fileInfo, 642 GNOME_VFS_FILE_INFO_GET_ACCESS_RIGHTS ); 643 644 if (fileInfo->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_ACCESS) { 645 bool read_only = true; 646 647 if (fileInfo->permissions & GNOME_VFS_PERM_ACCESS_WRITABLE) 648 read_only = false; 649 650 xRow->appendBoolean( rProp, read_only ); 651 } else 652 xRow->appendVoid( rProp ); 653 gnome_vfs_file_info_unref (fileInfo); 654 } 655 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ) { 656 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) 657 xRow->appendLong( rProp, m_info.size ); 658 else 659 xRow->appendVoid( rProp ); 660 } 661 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsHidden" ) ) ) 662 xRow->appendBoolean( rProp, ( m_info.name && m_info.name[0] == '.' ) ); 663 664 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsVolume" ) ) || 665 rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsCompactDisk" ) ) ) 666 xRow->appendBoolean( rProp, sal_False ); 667 668 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) ) { 669 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_CTIME) 670 xRow->appendTimestamp( rProp, getDateFromUnix( m_info.ctime ) ); 671 else 672 xRow->appendVoid( rProp ); 673 } 674 675 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) { 676 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_MTIME) 677 xRow->appendTimestamp( rProp, getDateFromUnix( m_info.mtime ) ); 678 else 679 xRow->appendVoid( rProp ); 680 } 681 682 else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) { 683 // We do this by sniffing in gnome-vfs; rather expensively. 684 #ifdef DEBUG 685 g_warning ("FIXME: Requested mime-type - an expensive op. indeed!"); 686 #endif 687 xRow->appendVoid( rProp ); 688 } else if (rProp.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) 689 xRow->appendObject( rProp, uno::makeAny( queryCreatableContentsInfo( xEnv ) ) ); 690 691 else { 692 xRow->appendVoid( rProp ); 693 } 694 } 695 #ifdef DEBUG 696 g_warning ("getPropertyValues on '%s' %d properties returned (of %d)", 697 getURI(), (int)xRow->getLength(), (int)nProps); 698 #endif 699 700 return uno::Reference< sdbc::XRow >( xRow.get() ); 701 } 702 703 static lang::IllegalAccessException 704 getReadOnlyException( Content *ctnt ) 705 { 706 return lang::IllegalAccessException 707 ( rtl::OUString::createFromAscii( "Property is read-only!" ), 708 static_cast< cppu::OWeakObject * >( ctnt ) ); 709 } 710 711 rtl::OUString 712 Content::makeNewURL( const char */*newName*/ ) 713 { 714 rtl::OUString aNewURL = getParentURL(); 715 if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) ) 716 aNewURL += rtl::OUString::createFromAscii( "/" ); 717 718 char *name = gnome_vfs_escape_string( m_info.name ); 719 aNewURL += GnomeToOUString( name ); 720 g_free( name ); 721 722 return aNewURL; 723 } 724 725 // This is slightly complicated by needing to support either 'move' or 'setname' 726 GnomeVFSResult 727 Content::doSetFileInfo( const GnomeVFSFileInfo *newInfo, 728 GnomeVFSSetFileInfoMask setMask, 729 const uno::Reference< ucb::XCommandEnvironment >& /*xEnv*/ ) 730 { 731 GnomeVFSResult result = GNOME_VFS_OK; 732 733 g_assert (!m_bTransient); 734 735 ::rtl::OString aURI = getOURI(); 736 737 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 738 739 // The simple approach: 740 if( setMask != GNOME_VFS_SET_FILE_INFO_NONE ) 741 result = gnome_vfs_set_file_info // missed a const in the API there 742 ( (const sal_Char *) aURI, (GnomeVFSFileInfo *)newInfo, setMask ); 743 744 if ( result == GNOME_VFS_ERROR_NOT_SUPPORTED && 745 ( setMask & GNOME_VFS_SET_FILE_INFO_NAME ) ) { 746 // Try a move instead 747 #ifdef DEBUG 748 g_warning( "SetFileInfo not supported on '%s'", getURI() ); 749 #endif 750 751 char *newURI = OUStringToGnome( makeNewURL( newInfo->name ) ); 752 753 result = gnome_vfs_move ((const sal_Char *)aURI, newURI, FALSE); 754 755 g_free (newURI); 756 } 757 758 return result; 759 } 760 761 762 uno::Sequence< uno::Any > Content::setPropertyValues( 763 const uno::Sequence< beans::PropertyValue >& rValues, 764 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 765 { 766 rtl::OUString aNewTitle; 767 GnomeVFSFileInfo newInfo; 768 int setMask = GNOME_VFS_SET_FILE_INFO_NONE; 769 770 getInfo( xEnv ); 771 772 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 773 774 gnome_vfs_file_info_copy( &newInfo, &m_info ); 775 776 Authentication aAuth( xEnv ); 777 778 int nChanged = 0, nTitlePos = 0; 779 uno::Sequence< uno::Any > aRet( rValues.getLength() ); 780 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() ); 781 782 beans::PropertyChangeEvent aEvent; 783 aEvent.Source = static_cast< cppu::OWeakObject * >( this ); 784 aEvent.Further = sal_False; 785 aEvent.PropertyHandle = -1; 786 // aEvent.PropertyName = fill in later ... 787 // aEvent.OldValue = 788 // aEvent.NewValue = 789 790 int nCount = rValues.getLength(); 791 const beans::PropertyValue* pValues = rValues.getConstArray(); 792 793 for ( sal_Int32 n = 0; n < nCount; ++n ) { 794 const beans::PropertyValue& rValue = pValues[ n ]; 795 796 #ifdef DEBUG 797 g_warning( "Set prop '%s'", OUStringToGnome( rValue.Name ) ); 798 #endif 799 if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) || 800 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) || 801 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) || 802 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) || 803 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) || 804 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) 805 aRet[ n ] <<= getReadOnlyException( this ); 806 807 else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) { 808 if ( rValue.Value >>= aNewTitle ) { 809 if ( aNewTitle.getLength() <= 0 ) 810 aRet[ n ] <<= lang::IllegalArgumentException 811 ( rtl::OUString::createFromAscii( "Empty title not allowed!" ), 812 static_cast< cppu::OWeakObject * >( this ), -1 ); 813 else { 814 char *newName = OUStringToGnome( aNewTitle ); 815 816 if( !newName || !m_info.name || strcmp( newName, m_info.name ) ) { 817 #ifdef DEBUG 818 g_warning ("Set new name to '%s'", newName); 819 #endif 820 821 aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" ); 822 aEvent.OldValue = uno::makeAny( GnomeToOUString( newInfo.name ) ); 823 aEvent.NewValue = uno::makeAny( aNewTitle ); 824 aChanges.getArray()[ nChanged ] = aEvent; 825 nTitlePos = nChanged++; 826 827 newInfo.name = newName; 828 setMask |= GNOME_VFS_SET_FILE_INFO_NAME; 829 } else // same name 830 g_free (newName); 831 } 832 } else 833 aRet[ n ] <<= beans::IllegalTypeException 834 ( rtl::OUString::createFromAscii( "Property value has wrong type!" ), 835 static_cast< cppu::OWeakObject * >( this ) ); 836 837 } else if ( rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) || 838 rValue.Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) { 839 // FIXME: should be able to set the timestamps 840 aRet[ n ] <<= getReadOnlyException( this ); 841 } else { 842 #ifdef DEBUG 843 g_warning( "Unhandled property '%s'", OUStringToGnome( rValue.Name ) ); 844 #endif 845 aRet[ n ] <<= getReadOnlyException( this ); 846 } 847 } 848 849 GnomeVFSResult result = GNOME_VFS_OK; 850 851 if ( !m_bTransient && 852 ( result = doSetFileInfo( &newInfo, 853 (GnomeVFSSetFileInfoMask) setMask, 854 xEnv ) ) != GNOME_VFS_OK ) { 855 for (int i = 0; i < nChanged; i++) 856 aRet[ i ] <<= mapVFSException( result, sal_True ); 857 858 } 859 860 if ( result == GNOME_VFS_OK) { 861 gnome_vfs_file_info_copy( &m_info, &newInfo ); 862 863 if ( setMask & GNOME_VFS_SET_FILE_INFO_NAME ) { 864 uno::Reference< ucb::XContentIdentifier > xNewId 865 = new ::ucbhelper::ContentIdentifier( 866 m_xSMgr, makeNewURL( newInfo.name ) ); 867 868 aGuard.clear(); 869 if (!exchangeIdentity( xNewId ) ) 870 aRet[ nTitlePos ] <<= uno::Exception 871 ( rtl::OUString::createFromAscii( "Exchange failed!" ), 872 static_cast< cppu::OWeakObject * >( this ) ); 873 } 874 } 875 876 gnome_vfs_file_info_clear( &newInfo ); 877 878 if ( nChanged > 0 ) { 879 aGuard.clear(); 880 aChanges.realloc( nChanged ); 881 notifyPropertiesChange( aChanges ); 882 } 883 884 return aRet; 885 } 886 887 void Content::queryChildren( ContentRefList& rChildren ) 888 { 889 // Obtain a list with a snapshot of all currently instanciated contents 890 // from provider and extract the contents which are direct children 891 // of this content. 892 893 ::ucbhelper::ContentRefList aAllContents; 894 m_xProvider->queryExistingContents( aAllContents ); 895 896 rtl::OUString aURL = getOUURI(); 897 sal_Int32 nURLPos = aURL.lastIndexOf( '/' ); 898 899 if ( nURLPos != ( aURL.getLength() - 1 ) ) 900 aURL += rtl::OUString::createFromAscii( "/" ); 901 902 sal_Int32 nLen = aURL.getLength(); 903 904 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); 905 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); 906 907 while ( it != end ) { 908 ::ucbhelper::ContentImplHelperRef xChild = (*it); 909 rtl::OUString aChildURL 910 = xChild->getIdentifier()->getContentIdentifier(); 911 912 // Is aURL a prefix of aChildURL? 913 if ( ( aChildURL.getLength() > nLen ) && 914 ( aChildURL.compareTo( aURL, nLen ) == 0 ) ) { 915 sal_Int32 nPos = nLen; 916 nPos = aChildURL.indexOf( '/', nPos ); 917 918 if ( ( nPos == -1 ) || 919 ( nPos == ( aChildURL.getLength() - 1 ) ) ) { 920 // No further slashes / only a final slash. It's a child! 921 rChildren.push_back( ::gvfs::Content::ContentRef 922 (static_cast< ::gvfs::Content * >(xChild.get() ) ) ); 923 } 924 } 925 ++it; 926 } 927 } 928 929 void Content::insert( 930 const uno::Reference< io::XInputStream > &xInputStream, 931 sal_Bool bReplaceExisting, 932 const uno::Reference< ucb::XCommandEnvironment > &xEnv ) 933 throw( uno::Exception ) 934 { 935 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 936 937 #ifdef DEBUG 938 g_warning( "Insert '%s' (%d) (0x%x:%d)", getURI(), bReplaceExisting, 939 m_info.valid_fields, m_info.type ); 940 #endif 941 942 GnomeVFSResult result = getInfo( xEnv ); 943 // a racy design indeed. 944 if( !bReplaceExisting && !m_bTransient && 945 result != GNOME_VFS_ERROR_NOT_FOUND) { 946 #ifdef DEBUG 947 g_warning ("Nasty error inserting to '%s' ('%s')", 948 getURI(), gnome_vfs_result_to_string( result )); 949 #endif 950 cancelCommandExecution( GNOME_VFS_ERROR_FILE_EXISTS, xEnv, sal_True ); 951 } 952 953 if ( m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE && 954 m_info.type == GNOME_VFS_FILE_TYPE_DIRECTORY ) { 955 ::rtl::OString aURI = getOURI(); 956 int perm; 957 958 perm = ( GNOME_VFS_PERM_USER_ALL | 959 GNOME_VFS_PERM_GROUP_READ | 960 GNOME_VFS_PERM_OTHER_READ ); 961 962 #ifdef DEBUG 963 g_warning ("Make directory"); 964 #endif 965 result = gnome_vfs_make_directory( (const sal_Char *) aURI, perm ); 966 967 if( result != GNOME_VFS_OK ) 968 cancelCommandExecution( result, xEnv, sal_True ); 969 970 return; 971 } 972 973 if ( !xInputStream.is() ) { 974 // FIXME: slightly unclear whether to accept this and create an empty file 975 ucbhelper::cancelCommandExecution 976 ( uno::makeAny 977 ( ucb::MissingInputStreamException 978 ( rtl::OUString(), 979 static_cast< cppu::OWeakObject * >( this ) ) ), 980 xEnv ); 981 } 982 983 GnomeVFSHandle *handle = NULL; 984 ::rtl::OString aURI = getOURI(); 985 986 result = GNOME_VFS_OK; 987 if ( bReplaceExisting ) { 988 Authentication aAuth( xEnv ); 989 result = gnome_vfs_open( &handle, (const sal_Char *)aURI, 990 GNOME_VFS_OPEN_WRITE ); 991 } 992 993 if ( result != GNOME_VFS_OK ) { 994 int perm; 995 Authentication aAuth( xEnv ); 996 997 perm = ( ( GNOME_VFS_PERM_USER_WRITE | GNOME_VFS_PERM_USER_READ ) | 998 ( GNOME_VFS_PERM_GROUP_WRITE | GNOME_VFS_PERM_GROUP_READ ) ); 999 1000 result = gnome_vfs_create 1001 ( &handle, (const sal_Char *)aURI, GNOME_VFS_OPEN_WRITE, TRUE, perm ); 1002 } 1003 1004 if( result != GNOME_VFS_OK ) 1005 cancelCommandExecution( result, xEnv, sal_True ); 1006 1007 if ( !xInputStream.is() ) { 1008 result = gnome_vfs_close( handle ); 1009 if (result != GNOME_VFS_OK) 1010 cancelCommandExecution( result, xEnv, sal_True ); 1011 1012 } else { // copy it over 1013 uno::Reference < io::XOutputStream > xOutput = 1014 new gvfs::Stream( handle, &m_info ); 1015 1016 copyData( xInputStream, xOutput ); 1017 } 1018 1019 if (m_bTransient) { 1020 m_bTransient = sal_False; 1021 aGuard.clear(); 1022 inserted(); 1023 } 1024 } 1025 1026 void Content::transfer(const ucb::TransferInfo & /*rArgs*/, 1027 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1028 throw( uno::Exception ) 1029 { 1030 // FIXME: see gnome-vfs-xfer.h - but we need to be able to easily 1031 // detect which are gnome-vfs owned URI types ... 1032 ucbhelper::cancelCommandExecution 1033 ( uno::makeAny 1034 ( ucb::InteractiveBadTransferURLException 1035 ( rtl::OUString::createFromAscii( "Unsupported URL scheme!" ), 1036 static_cast< cppu::OWeakObject * >( this ) ) ), 1037 xEnv ); 1038 } 1039 1040 void Content::destroy( sal_Bool bDeletePhysical ) 1041 throw( uno::Exception ) 1042 { 1043 // @@@ take care about bDeletePhysical -> trashcan support 1044 rtl::OUString aURL = getOUURI(); 1045 1046 uno::Reference< ucb::XContent > xThis = this; 1047 1048 deleted(); 1049 1050 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1051 1052 // Process instanciated children... 1053 ::gvfs::Content::ContentRefList aChildren; 1054 queryChildren( aChildren ); 1055 1056 ContentRefList::const_iterator it = aChildren.begin(); 1057 ContentRefList::const_iterator end = aChildren.end(); 1058 1059 while ( it != end ) { 1060 (*it)->destroy( bDeletePhysical ); 1061 ++it; 1062 } 1063 } 1064 1065 // Used by the 'setPropertyValues' method for 1066 // propagating the renaming of a Content. 1067 sal_Bool Content::exchangeIdentity( 1068 const uno::Reference< ucb::XContentIdentifier >& xNewId ) 1069 { 1070 if ( !xNewId.is() ) 1071 return sal_False; 1072 1073 uno::Reference< ucb::XContent > xThis = this; 1074 1075 #ifdef DEBUG 1076 g_warning( "exchangeIdentity from '%s' to '%s'", 1077 getURI(), OUStringToGnome( xNewId->getContentIdentifier() ) ); 1078 #endif 1079 1080 if ( m_bTransient ) { 1081 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1082 /* FIXME: can we not screw up an identically named 1083 * Content pointing to ourself here ? */ 1084 m_xIdentifier = xNewId; 1085 return sal_False; 1086 } 1087 1088 rtl::OUString aOldURL = getOUURI(); 1089 1090 // Exchange own identitity. 1091 if ( exchange( xNewId ) ) { 1092 1093 // Process instanciated children... 1094 ContentRefList aChildren; 1095 queryChildren( aChildren ); 1096 1097 ContentRefList::const_iterator it = aChildren.begin(); 1098 ContentRefList::const_iterator end = aChildren.end(); 1099 1100 while ( it != end ) { 1101 ContentRef xChild = (*it); 1102 1103 // Create new content identifier for the child... 1104 uno::Reference< ucb::XContentIdentifier > 1105 xOldChildId = xChild->getIdentifier(); 1106 rtl::OUString aOldChildURL 1107 = xOldChildId->getContentIdentifier(); 1108 rtl::OUString aNewChildURL 1109 = aOldChildURL.replaceAt( 1110 0, 1111 aOldURL.getLength(), 1112 xNewId->getContentIdentifier() ); 1113 uno::Reference< ucb::XContentIdentifier > 1114 xNewChildId 1115 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aNewChildURL ); 1116 1117 if ( !xChild->exchangeIdentity( xNewChildId ) ) 1118 return sal_False; 1119 1120 ++it; 1121 } 1122 return sal_True; 1123 } 1124 1125 return sal_False; 1126 } 1127 1128 GnomeVFSResult 1129 Content::getInfo( const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1130 { 1131 GnomeVFSResult result; 1132 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1133 1134 if (m_bTransient) 1135 result = GNOME_VFS_OK; 1136 1137 else if ( !m_info.valid_fields ) { 1138 ::rtl::OString aURI = getOURI(); 1139 Authentication aAuth( xEnv ); 1140 result = gnome_vfs_get_file_info 1141 ( (const sal_Char *)aURI, &m_info, GNOME_VFS_FILE_INFO_DEFAULT ); 1142 if (result != GNOME_VFS_OK) 1143 gnome_vfs_file_info_clear( &m_info ); 1144 } else 1145 result = GNOME_VFS_OK; 1146 #ifdef DEBUG 1147 g_warning( "getInfo on '%s' returns '%s' (%d) (0x%x)", 1148 getURI(), gnome_vfs_result_to_string( result ), 1149 result, m_info.valid_fields ); 1150 #endif 1151 return result; 1152 } 1153 1154 sal_Bool 1155 Content::isFolder(const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1156 { 1157 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1158 getInfo( xEnv ); 1159 return (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE && 1160 m_info.type == GNOME_VFS_FILE_TYPE_DIRECTORY); 1161 } 1162 1163 uno::Any Content::mapVFSException( const GnomeVFSResult result, sal_Bool bWrite ) 1164 { 1165 uno::Any aException; 1166 const char *gvfs_message; 1167 rtl::OUString message; 1168 uno::Sequence< uno::Any > aArgs( 1 ); 1169 1170 #ifdef DEBUG 1171 g_warning ("Map VFS exception '%s' (%d)", 1172 gnome_vfs_result_to_string( result ), result ); 1173 #endif 1174 1175 if ((gvfs_message = gnome_vfs_result_to_string (result))) 1176 message = GnomeToOUString( gvfs_message ); 1177 1178 switch (result) { 1179 case GNOME_VFS_OK: 1180 g_warning("VFS_OK mapped to exception."); 1181 break; 1182 case GNOME_VFS_ERROR_EOF: 1183 g_warning ("VFS_EOF not handled somewhere."); 1184 break; 1185 case GNOME_VFS_ERROR_NOT_FOUND: 1186 aArgs[ 0 ] <<= m_xIdentifier->getContentIdentifier(); 1187 aException <<= 1188 ucb::InteractiveAugmentedIOException 1189 ( rtl::OUString::createFromAscii( "Not found!" ), 1190 static_cast< cppu::OWeakObject * >( this ), 1191 task::InteractionClassification_ERROR, 1192 ucb::IOErrorCode_NOT_EXISTING, 1193 aArgs ); 1194 break; 1195 case GNOME_VFS_ERROR_BAD_PARAMETERS: 1196 aException <<= 1197 lang::IllegalArgumentException 1198 ( rtl::OUString(), 1199 static_cast< cppu::OWeakObject * >( this ), 1200 -1 ); 1201 break; 1202 case GNOME_VFS_ERROR_GENERIC: 1203 case GNOME_VFS_ERROR_INTERNAL: 1204 case GNOME_VFS_ERROR_NOT_SUPPORTED: 1205 #ifdef DEBUG 1206 g_warning ("Internal - un-mapped error"); 1207 #endif 1208 aException <<= io::IOException(); 1209 break; 1210 case GNOME_VFS_ERROR_IO: 1211 if ( bWrite ) 1212 aException <<= 1213 ucb::InteractiveNetworkWriteException 1214 ( rtl::OUString(), 1215 static_cast< cppu::OWeakObject * >( this ), 1216 task::InteractionClassification_ERROR, 1217 message ); 1218 else 1219 aException <<= 1220 ucb::InteractiveNetworkReadException 1221 ( rtl::OUString(), 1222 static_cast< cppu::OWeakObject * >( this ), 1223 task::InteractionClassification_ERROR, 1224 message ); 1225 break; 1226 case GNOME_VFS_ERROR_HOST_NOT_FOUND: 1227 case GNOME_VFS_ERROR_INVALID_HOST_NAME: 1228 aException <<= 1229 ucb::InteractiveNetworkResolveNameException 1230 ( rtl::OUString(), 1231 static_cast< cppu::OWeakObject * >( this ), 1232 task::InteractionClassification_ERROR, 1233 message ); 1234 break; 1235 case GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE: 1236 case GNOME_VFS_ERROR_SERVICE_OBSOLETE: 1237 case GNOME_VFS_ERROR_PROTOCOL_ERROR: 1238 case GNOME_VFS_ERROR_NO_MASTER_BROWSER: 1239 aException <<= 1240 ucb::InteractiveNetworkConnectException 1241 ( rtl::OUString(), 1242 static_cast< cppu::OWeakObject * >( this ), 1243 task::InteractionClassification_ERROR, 1244 message ); 1245 break; 1246 1247 case GNOME_VFS_ERROR_FILE_EXISTS: 1248 aException <<= ucb::NameClashException 1249 ( rtl::OUString(), 1250 static_cast< cppu::OWeakObject * >( this ), 1251 task::InteractionClassification_ERROR, 1252 message ); 1253 break; 1254 1255 case GNOME_VFS_ERROR_INVALID_OPEN_MODE: 1256 aException <<= ucb::UnsupportedOpenModeException(); 1257 break; 1258 1259 case GNOME_VFS_ERROR_CORRUPTED_DATA: 1260 case GNOME_VFS_ERROR_WRONG_FORMAT: 1261 case GNOME_VFS_ERROR_BAD_FILE: 1262 case GNOME_VFS_ERROR_TOO_BIG: 1263 case GNOME_VFS_ERROR_NO_SPACE: 1264 case GNOME_VFS_ERROR_READ_ONLY: 1265 case GNOME_VFS_ERROR_INVALID_URI: 1266 case GNOME_VFS_ERROR_NOT_OPEN: 1267 case GNOME_VFS_ERROR_ACCESS_DENIED: 1268 case GNOME_VFS_ERROR_TOO_MANY_OPEN_FILES: 1269 case GNOME_VFS_ERROR_NOT_A_DIRECTORY: 1270 case GNOME_VFS_ERROR_IN_PROGRESS: 1271 case GNOME_VFS_ERROR_INTERRUPTED: 1272 case GNOME_VFS_ERROR_LOOP: 1273 case GNOME_VFS_ERROR_NOT_PERMITTED: 1274 case GNOME_VFS_ERROR_IS_DIRECTORY: 1275 case GNOME_VFS_ERROR_NO_MEMORY: 1276 case GNOME_VFS_ERROR_HOST_HAS_NO_ADDRESS: 1277 case GNOME_VFS_ERROR_LOGIN_FAILED: 1278 case GNOME_VFS_ERROR_CANCELLED: 1279 case GNOME_VFS_ERROR_DIRECTORY_BUSY: 1280 case GNOME_VFS_ERROR_DIRECTORY_NOT_EMPTY: 1281 case GNOME_VFS_ERROR_TOO_MANY_LINKS: 1282 case GNOME_VFS_ERROR_READ_ONLY_FILE_SYSTEM: 1283 case GNOME_VFS_ERROR_NOT_SAME_FILE_SYSTEM: 1284 case GNOME_VFS_ERROR_NAME_TOO_LONG: 1285 #ifdef DEBUG 1286 g_warning( "FIXME: Un-mapped VFS exception '%s' (%d)", 1287 gnome_vfs_result_to_string( result ), result ); 1288 #endif 1289 default: 1290 aException <<= ucb::InteractiveNetworkGeneralException 1291 ( rtl::OUString(), 1292 static_cast< cppu::OWeakObject * >( this ), 1293 task::InteractionClassification_ERROR ); 1294 break; 1295 } 1296 1297 return aException; 1298 } 1299 1300 void Content::cancelCommandExecution( 1301 GnomeVFSResult result, 1302 const uno::Reference< ucb::XCommandEnvironment > & xEnv, 1303 sal_Bool bWrite /* = sal_False */ ) 1304 throw ( uno::Exception ) 1305 { 1306 ucbhelper::cancelCommandExecution( mapVFSException( result, bWrite ), xEnv ); 1307 // Unreachable 1308 } 1309 1310 uno::Sequence< beans::Property > Content::getProperties( 1311 const uno::Reference< ucb::XCommandEnvironment > & /*xEnv*/ ) 1312 { 1313 static const beans::Property aGenericProperties[] = { 1314 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ContentType" ) ), 1315 -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1316 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1317 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ), 1318 -1, getCppuBooleanType(), 1319 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1320 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ), 1321 -1, getCppuBooleanType(), 1322 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1323 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), 1324 -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1325 beans::PropertyAttribute::BOUND ), 1326 // Optional ... 1327 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateCreated" ) ), 1328 -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ), 1329 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1330 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DateModified" ) ), 1331 -1, getCppuType( static_cast< const util::DateTime * >( 0 ) ), 1332 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1333 // FIXME: Too expensive for now (?) 1334 // beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), 1335 // -1, getCppuType( static_cast< const rtl::OUString * >( 0 ) ), 1336 // beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1337 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ), 1338 -1, getCppuType( static_cast< const sal_Int64 * >( 0 ) ), 1339 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1340 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ), 1341 -1, getCppuBooleanType(), 1342 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1343 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsVolume" ) ), 1344 -1, getCppuBooleanType(), 1345 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1346 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsCompactDisk" ) ), 1347 -1, getCppuBooleanType(), 1348 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1349 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsHidden" ) ), 1350 -1, getCppuBooleanType(), 1351 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ), 1352 beans::Property( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ), 1353 -1, getCppuType( static_cast< const uno::Sequence< ucb::ContentInfo > * >( 0 ) ), 1354 beans::PropertyAttribute::BOUND | beans::PropertyAttribute::READONLY ) 1355 }; 1356 1357 const int nProps = sizeof (aGenericProperties) / sizeof (aGenericProperties[0]); 1358 1359 return uno::Sequence< beans::Property > ( aGenericProperties, nProps ); 1360 1361 } 1362 1363 uno::Sequence< ucb::CommandInfo > Content::getCommands( 1364 const uno::Reference< ucb::XCommandEnvironment > & xEnv ) 1365 { 1366 static ucb::CommandInfo aCommandInfoTable[] = { 1367 // Required commands 1368 ucb::CommandInfo 1369 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getCommandInfo" ) ), 1370 -1, getCppuVoidType() ), 1371 ucb::CommandInfo 1372 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertySetInfo" ) ), 1373 -1, getCppuVoidType() ), 1374 ucb::CommandInfo 1375 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getPropertyValues" ) ), 1376 -1, getCppuType( static_cast<uno::Sequence< beans::Property > * >( 0 ) ) ), 1377 ucb::CommandInfo 1378 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "setPropertyValues" ) ), 1379 -1, getCppuType( static_cast<uno::Sequence< beans::PropertyValue > * >( 0 ) ) ), 1380 1381 // Optional standard commands 1382 ucb::CommandInfo 1383 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete" ) ), 1384 -1, getCppuBooleanType() ), 1385 ucb::CommandInfo 1386 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "insert" ) ), 1387 -1, getCppuType( static_cast<ucb::InsertCommandArgument * >( 0 ) ) ), 1388 ucb::CommandInfo 1389 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "open" ) ), 1390 -1, getCppuType( static_cast<ucb::OpenCommandArgument2 * >( 0 ) ) ), 1391 1392 // Folder Only, omitted if not a folder 1393 ucb::CommandInfo 1394 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ), 1395 -1, getCppuType( static_cast<ucb::TransferInfo * >( 0 ) ) ), 1396 ucb::CommandInfo 1397 ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "createNewContent" ) ), 1398 -1, getCppuType( static_cast<ucb::ContentInfo * >( 0 ) ) ) 1399 }; 1400 1401 const int nProps 1402 = sizeof( aCommandInfoTable ) / sizeof( aCommandInfoTable[ 0 ] ); 1403 return uno::Sequence< ucb::CommandInfo >( 1404 aCommandInfoTable, isFolder( xEnv ) ? nProps : nProps - 2 ); 1405 } 1406 1407 rtl::OUString 1408 Content::getOUURI () 1409 { 1410 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1411 return m_xIdentifier->getContentIdentifier(); 1412 } 1413 1414 rtl::OString 1415 Content::getOURI () 1416 { 1417 return rtl::OUStringToOString( getOUURI(), RTL_TEXTENCODING_UTF8 ); 1418 } 1419 1420 char * 1421 Content::getURI () 1422 { 1423 return OUStringToGnome( getOUURI() ); 1424 } 1425 1426 void 1427 Content::copyData( uno::Reference< io::XInputStream > xIn, 1428 uno::Reference< io::XOutputStream > xOut ) 1429 { 1430 uno::Sequence< sal_Int8 > theData( TRANSFER_BUFFER_SIZE ); 1431 1432 g_return_if_fail( xIn.is() && xOut.is() ); 1433 1434 while ( xIn->readBytes( theData, TRANSFER_BUFFER_SIZE ) > 0 ) 1435 xOut->writeBytes( theData ); 1436 1437 xOut->closeOutput(); 1438 } 1439 1440 // Inherits an authentication context 1441 uno::Reference< io::XInputStream > 1442 Content::createTempStream( 1443 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1444 throw( uno::Exception ) 1445 { 1446 GnomeVFSResult result; 1447 GnomeVFSHandle *handle = NULL; 1448 ::rtl::OString aURI = getOURI(); 1449 1450 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1451 // Something badly wrong happened - can't seek => stream to a temporary file 1452 const rtl::OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); 1453 uno::Reference < io::XOutputStream > xTempOut = 1454 uno::Reference < io::XOutputStream > 1455 ( m_xSMgr->createInstance( sServiceName ), uno::UNO_QUERY ); 1456 1457 if ( !xTempOut.is() ) 1458 cancelCommandExecution( GNOME_VFS_ERROR_IO, xEnv ); 1459 1460 result = gnome_vfs_open 1461 ( &handle, (const sal_Char *)aURI, GNOME_VFS_OPEN_READ ); 1462 if (result != GNOME_VFS_OK) 1463 cancelCommandExecution( result, xEnv ); 1464 1465 uno::Reference < io::XInputStream > pStream = new ::gvfs::Stream( handle, &m_info ); 1466 copyData( pStream, xTempOut ); 1467 1468 return uno::Reference < io::XInputStream > ( xTempOut, uno::UNO_QUERY ); 1469 } 1470 1471 uno::Reference< io::XInputStream > 1472 Content::createInputStream( 1473 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1474 throw( uno::Exception ) 1475 { 1476 GnomeVFSHandle *handle = NULL; 1477 GnomeVFSResult result; 1478 uno::Reference<io::XInputStream > xIn; 1479 1480 Authentication aAuth( xEnv ); 1481 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1482 1483 getInfo( xEnv ); 1484 ::rtl::OString aURI = getOURI(); 1485 1486 if ( !(m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) ) 1487 return createTempStream( xEnv ); 1488 1489 result = gnome_vfs_open 1490 ( &handle, (const sal_Char *)aURI, 1491 (GnomeVFSOpenMode) (GNOME_VFS_OPEN_READ | GNOME_VFS_OPEN_RANDOM ) ); 1492 1493 if (result == GNOME_VFS_ERROR_INVALID_OPEN_MODE || 1494 result == GNOME_VFS_ERROR_NOT_SUPPORTED) 1495 return createTempStream( xEnv ); 1496 1497 if (result != GNOME_VFS_OK) 1498 cancelCommandExecution( result, xEnv ); 1499 1500 // Try a seek just to make sure it's Random access: some lie. 1501 result = gnome_vfs_seek( handle, GNOME_VFS_SEEK_START, 0); 1502 if (result == GNOME_VFS_ERROR_NOT_SUPPORTED) { 1503 gnome_vfs_close( handle ); 1504 return createTempStream( xEnv ); 1505 } 1506 1507 if (result != GNOME_VFS_OK) 1508 cancelCommandExecution( result, xEnv ); 1509 1510 if (handle != NULL) 1511 xIn = new ::gvfs::Stream( handle, &m_info ); 1512 1513 return xIn; 1514 } 1515 1516 sal_Bool 1517 Content::feedSink( uno::Reference< uno::XInterface > aSink, 1518 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1519 { 1520 if ( !aSink.is() ) 1521 return sal_False; 1522 1523 uno::Reference< io::XOutputStream > xOut 1524 = uno::Reference< io::XOutputStream >(aSink, uno::UNO_QUERY ); 1525 uno::Reference< io::XActiveDataSink > xDataSink 1526 = uno::Reference< io::XActiveDataSink >(aSink, uno::UNO_QUERY ); 1527 1528 if ( !xOut.is() && !xDataSink.is() ) 1529 return sal_False; 1530 1531 uno::Reference< io::XInputStream > xIn = createInputStream( xEnv ); 1532 if ( !xIn.is() ) 1533 return sal_False; 1534 1535 if ( xOut.is() ) 1536 copyData( xIn, xOut ); 1537 1538 if ( xDataSink.is() ) 1539 xDataSink->setInputStream( xIn ); 1540 1541 return sal_True; 1542 } 1543 1544 extern "C" { 1545 1546 #ifndef GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION 1547 # error "We require Gnome VFS 2.6.x to compile (will run fine with < 2.6)" 1548 #endif 1549 1550 static void 1551 vfs_authentication_callback (gconstpointer in_void, 1552 gsize in_size, 1553 gpointer out_void, 1554 gsize out_size, 1555 gpointer callback_data) 1556 { 1557 task::XInteractionHandler *xIH; 1558 1559 #ifdef DEBUG 1560 g_warning ("Full authentication callback (%p) ...", callback_data); 1561 #endif 1562 1563 if( !( xIH = (task::XInteractionHandler *) callback_data ) ) 1564 return; 1565 1566 const GnomeVFSModuleCallbackFullAuthenticationIn *in = 1567 (const GnomeVFSModuleCallbackFullAuthenticationIn *) in_void; 1568 GnomeVFSModuleCallbackFullAuthenticationOut *out = 1569 (GnomeVFSModuleCallbackFullAuthenticationOut *) out_void; 1570 1571 g_return_if_fail (in != NULL && out != NULL); 1572 g_return_if_fail (sizeof (GnomeVFSModuleCallbackFullAuthenticationIn) == in_size && 1573 sizeof (GnomeVFSModuleCallbackFullAuthenticationOut) == out_size); 1574 1575 #ifdef DEBUG 1576 # define NNIL(x) (x?x:"<Null>") 1577 g_warning (" InComing data 0x%x uri '%s' prot '%s' server '%s' object '%s' " 1578 "port %d auth_t '%s' user '%s' domain '%s' " 1579 "def user '%s', def domain '%s'", 1580 (int) in->flags, NNIL(in->uri), NNIL(in->protocol), 1581 NNIL(in->server), NNIL(in->object), 1582 (int) in->port, NNIL(in->authtype), NNIL(in->username), NNIL(in->domain), 1583 NNIL(in->default_user), NNIL(in->default_domain)); 1584 # undef NNIL 1585 #endif 1586 1587 ucbhelper::SimpleAuthenticationRequest::EntityType 1588 eDomain, eUserName, ePassword; 1589 ::rtl::OUString aHostName, aDomain, aUserName, aPassword; 1590 1591 aHostName = GnomeToOUString( in->server ); 1592 1593 if (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN) 1594 { 1595 aDomain = GnomeToOUString( in->domain ); 1596 eDomain = ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY; 1597 if (!aDomain.getLength()) 1598 aDomain = GnomeToOUString( in->default_domain ); 1599 } 1600 else // no underlying capability to display realm otherwise 1601 eDomain = ucbhelper::SimpleAuthenticationRequest::ENTITY_NA; 1602 1603 aUserName = GnomeToOUString( in->username ); 1604 if (!aUserName.getLength()) 1605 aUserName = GnomeToOUString( in->default_user ); 1606 eUserName = (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME) ? 1607 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY : 1608 (aUserName.getLength() ? 1609 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED : 1610 ucbhelper::SimpleAuthenticationRequest::ENTITY_NA); 1611 1612 // No suggested password. 1613 ePassword = (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD) ? 1614 ucbhelper::SimpleAuthenticationRequest::ENTITY_MODIFY : 1615 ucbhelper::SimpleAuthenticationRequest::ENTITY_FIXED; 1616 1617 // Really, really bad things happen if we don't provide 1618 // the same user/password as was entered last time if 1619 // we failed to authenticate - infinite looping / flickering 1620 // madness etc. [ nice infrastructure ! ] 1621 static rtl::OUString aLastUserName, aLastPassword; 1622 if (in->flags & GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED) 1623 { 1624 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 1625 aUserName = aLastUserName; 1626 aPassword = aLastPassword; 1627 } 1628 1629 rtl::Reference< ucbhelper::SimpleAuthenticationRequest > xRequest 1630 = new ucbhelper::SimpleAuthenticationRequest (GnomeToOUString(in->uri), 1631 aHostName, eDomain, aDomain, 1632 eUserName, aUserName, 1633 ePassword, aPassword); 1634 1635 xIH->handle( xRequest.get() ); 1636 1637 rtl::Reference< ucbhelper::InteractionContinuation > xSelection 1638 = xRequest->getSelection(); 1639 1640 if ( xSelection.is() ) { 1641 // Handler handled the request. 1642 uno::Reference< task::XInteractionAbort > xAbort(xSelection.get(), uno::UNO_QUERY ); 1643 if ( !xAbort.is() ) { 1644 const rtl::Reference< 1645 ucbhelper::InteractionSupplyAuthentication > & xSupp 1646 = xRequest->getAuthenticationSupplier(); 1647 1648 aUserName = xSupp->getUserName(); 1649 aDomain = xSupp->getRealm(); 1650 aPassword = xSupp->getPassword(); 1651 1652 { 1653 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 1654 aLastUserName = aUserName; 1655 aLastPassword = aPassword; 1656 } 1657 1658 out->username = OUStringToGnome( aUserName ); 1659 out->domain = OUStringToGnome( aDomain ); 1660 out->password = OUStringToGnome( aPassword ); 1661 out->save_password = xSupp->getRememberPasswordMode(); 1662 1663 #ifdef DEBUG 1664 g_warning ("Got valid user/domain/password '%s' '%s' '%s', %s password", 1665 out->username, out->domain, out->password, 1666 out->save_password ? "save" : "don't save"); 1667 #endif 1668 } 1669 else 1670 out->abort_auth = TRUE; 1671 } 1672 else 1673 out->abort_auth = TRUE; 1674 } 1675 1676 static void 1677 vfs_authentication_old_callback (gconstpointer in_void, 1678 gsize in_size, 1679 gpointer out_void, 1680 gsize out_size, 1681 gpointer callback_data) 1682 { 1683 #ifdef DEBUG 1684 g_warning ("Old authentication callback (%p) [ UNTESTED ] ...", callback_data); 1685 #endif 1686 const GnomeVFSModuleCallbackAuthenticationIn *in = 1687 (const GnomeVFSModuleCallbackAuthenticationIn *) in_void; 1688 GnomeVFSModuleCallbackAuthenticationOut *out = 1689 (GnomeVFSModuleCallbackAuthenticationOut *) out_void; 1690 1691 g_return_if_fail (in != NULL && out != NULL); 1692 g_return_if_fail (sizeof (GnomeVFSModuleCallbackAuthenticationIn) == in_size && 1693 sizeof (GnomeVFSModuleCallbackAuthenticationOut) == out_size); 1694 1695 GnomeVFSModuleCallbackFullAuthenticationIn mapped_in = { 1696 (GnomeVFSModuleCallbackFullAuthenticationFlags) 1697 (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_PASSWORD | 1698 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_USERNAME | 1699 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_NEED_DOMAIN), 1700 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1701 GnomeVFSModuleCallbackFullAuthenticationOut mapped_out = { 0, 0, 0, 0, 0, 0, 0, 0 }; 1702 1703 // Map the old style input auth. data to the new style structure. 1704 if (in->previous_attempt_failed) 1705 mapped_in.flags = (GnomeVFSModuleCallbackFullAuthenticationFlags) 1706 (mapped_in.flags | 1707 GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION_PREVIOUS_ATTEMPT_FAILED); 1708 1709 GnomeVFSURI *pURI = NULL; 1710 // Urk - parse all this from the URL ... 1711 mapped_in.uri = in->uri; 1712 if (in->uri) 1713 { 1714 pURI = gnome_vfs_uri_new( in->uri ); 1715 mapped_in.protocol = (char *) gnome_vfs_uri_get_scheme (pURI); 1716 mapped_in.server = (char *) gnome_vfs_uri_get_host_name (pURI); 1717 mapped_in.port = gnome_vfs_uri_get_host_port (pURI); 1718 mapped_in.username = (char *) gnome_vfs_uri_get_user_name (pURI); 1719 } 1720 mapped_in.domain = in->realm; 1721 mapped_in.default_user = mapped_in.username; 1722 mapped_in.default_domain = mapped_in.domain; 1723 1724 vfs_authentication_callback ((gconstpointer) &mapped_in, 1725 sizeof (mapped_in), 1726 (gpointer) &mapped_out, 1727 sizeof (mapped_out), 1728 callback_data); 1729 1730 if (pURI) 1731 gnome_vfs_uri_unref (pURI); 1732 1733 // Map the new style auth. out data to the old style out structure. 1734 out->username = mapped_out.username; 1735 out->password = mapped_out.password; 1736 g_free (mapped_out.domain); 1737 g_free (mapped_out.keyring); 1738 } 1739 1740 1741 static void 1742 auth_destroy (gpointer data) 1743 { 1744 task::XInteractionHandler *xIH; 1745 if( ( xIH = ( task::XInteractionHandler * )data ) ) 1746 xIH->release(); 1747 } 1748 1749 // This sucks, but gnome-vfs doesn't much like 1750 // repeated set / unsets - so we have to compensate. 1751 GPrivate *auth_queue = NULL; 1752 1753 void auth_queue_destroy( gpointer data ) 1754 { 1755 GList *l; 1756 GQueue *vq = (GQueue *) data; 1757 1758 for (l = vq->head; l; l = l->next) 1759 auth_destroy (l->data); 1760 g_queue_free (vq); 1761 } 1762 } 1763 1764 static void 1765 refresh_auth( GQueue *vq ) 1766 { 1767 GList *l; 1768 1769 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION ); 1770 gnome_vfs_module_callback_pop( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION ); 1771 1772 for (l = vq->head; l; l = l->next) { 1773 if (l->data) { 1774 gnome_vfs_module_callback_push 1775 ( GNOME_VFS_MODULE_CALLBACK_AUTHENTICATION, 1776 vfs_authentication_old_callback, l->data, NULL ); 1777 gnome_vfs_module_callback_push 1778 ( GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION, 1779 vfs_authentication_callback, l->data, NULL ); 1780 break; 1781 } 1782 } 1783 } 1784 1785 gvfs::Authentication::Authentication( 1786 const uno::Reference< ucb::XCommandEnvironment > & xEnv ) 1787 { 1788 GQueue *vq; 1789 uno::Reference< task::XInteractionHandler > xIH; 1790 1791 if ( xEnv.is() ) 1792 xIH = xEnv->getInteractionHandler(); 1793 1794 if ( xIH.is() ) 1795 xIH->acquire(); 1796 1797 if( !(vq = (GQueue *)g_private_get( auth_queue ) ) ) { 1798 vq = g_queue_new(); 1799 g_private_set( auth_queue, vq ); 1800 } 1801 1802 g_queue_push_head( vq, (gpointer) xIH.get() ); 1803 refresh_auth( vq ); 1804 } 1805 1806 gvfs::Authentication::~Authentication() 1807 { 1808 GQueue *vq; 1809 gpointer data; 1810 1811 vq = (GQueue *)g_private_get( auth_queue ); 1812 1813 data = g_queue_pop_head( vq ); 1814 auth_destroy (data); 1815 1816 refresh_auth( vq ); 1817 } 1818