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 31 /************************************************************************** 32 TODO 33 ************************************************************************** 34 35 *************************************************************************/ 36 37 #include <osl/diagnose.h> 38 #include "osl/doublecheckedlocking.h" 39 #include <rtl/uri.hxx> 40 #include <rtl/ustrbuf.hxx> 41 #include <ucbhelper/contentidentifier.hxx> 42 #include <ucbhelper/propertyvalueset.hxx> 43 #include <ucbhelper/simpleinteractionrequest.hxx> 44 #include <ucbhelper/cancelcommandexecution.hxx> 45 46 #include <com/sun/star/beans/PropertyAttribute.hpp> 47 #include <com/sun/star/beans/PropertySetInfoChange.hpp> 48 #include <com/sun/star/beans/PropertySetInfoChangeEvent.hpp> 49 #include <com/sun/star/beans/PropertyValue.hpp> 50 #include <com/sun/star/io/XActiveDataSink.hpp> 51 #include <com/sun/star/io/XOutputStream.hpp> 52 #include <com/sun/star/lang/IllegalAccessException.hpp> 53 #include <com/sun/star/task/PasswordContainerInteractionHandler.hpp> 54 #include <com/sun/star/ucb/CommandEnvironment.hpp> 55 #include <com/sun/star/ucb/CommandFailedException.hpp> 56 #include <com/sun/star/ucb/ContentInfoAttribute.hpp> 57 #include <com/sun/star/ucb/InsertCommandArgument.hpp> 58 #include <com/sun/star/ucb/InteractiveBadTransferURLException.hpp> 59 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> 60 #include "com/sun/star/ucb/InteractiveLockingLockedException.hpp" 61 #include "com/sun/star/ucb/InteractiveLockingLockExpiredException.hpp" 62 #include "com/sun/star/ucb/InteractiveLockingNotLockedException.hpp" 63 #include <com/sun/star/ucb/InteractiveNetworkConnectException.hpp> 64 #include <com/sun/star/ucb/InteractiveNetworkGeneralException.hpp> 65 #include <com/sun/star/ucb/InteractiveNetworkReadException.hpp> 66 #include <com/sun/star/ucb/InteractiveNetworkResolveNameException.hpp> 67 #include <com/sun/star/ucb/InteractiveNetworkWriteException.hpp> 68 #include <com/sun/star/ucb/MissingInputStreamException.hpp> 69 #include <com/sun/star/ucb/MissingPropertiesException.hpp> 70 #include <com/sun/star/ucb/NameClash.hpp> 71 #include <com/sun/star/ucb/NameClashException.hpp> 72 #include <com/sun/star/ucb/OpenCommandArgument2.hpp> 73 #include <com/sun/star/ucb/OpenMode.hpp> 74 #include <com/sun/star/ucb/PostCommandArgument2.hpp> 75 #include <com/sun/star/ucb/TransferInfo.hpp> 76 #include <com/sun/star/ucb/UnsupportedCommandException.hpp> 77 #include <com/sun/star/ucb/UnsupportedDataSinkException.hpp> 78 #include <com/sun/star/ucb/UnsupportedNameClashException.hpp> 79 #include <com/sun/star/ucb/UnsupportedOpenModeException.hpp> 80 #include <com/sun/star/ucb/XCommandInfo.hpp> 81 #include <com/sun/star/ucb/XPersistentPropertySet.hpp> 82 #include <com/sun/star/uno/XComponentContext.hpp> 83 84 #include "webdavcontent.hxx" 85 #include "webdavprovider.hxx" 86 #include "webdavresultset.hxx" 87 #include "ContentProperties.hxx" 88 #include "NeonUri.hxx" 89 #include "UCBDeadPropertyValue.hxx" 90 91 using namespace com::sun::star; 92 using namespace webdav_ucp; 93 94 //========================================================================= 95 //========================================================================= 96 // 97 // Content Implementation. 98 // 99 //========================================================================= 100 //========================================================================= 101 102 //========================================================================= 103 // ctr for content on an existing webdav resource 104 Content::Content( 105 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 106 ContentProvider* pProvider, 107 const uno::Reference< ucb::XContentIdentifier >& Identifier, 108 rtl::Reference< DAVSessionFactory > const & rSessionFactory ) 109 throw ( ucb::ContentCreationException ) 110 : ContentImplHelper( rxSMgr, pProvider, Identifier ), 111 m_eResourceType( UNKNOWN ), 112 m_pProvider( pProvider ), 113 m_bTransient( false ), 114 m_bCollection( false ), 115 m_bDidGetOrHead( false ) 116 { 117 try 118 { 119 m_xResAccess.reset( new DAVResourceAccess( 120 rxSMgr, 121 rSessionFactory, 122 Identifier->getContentIdentifier() ) ); 123 124 NeonUri aURI( Identifier->getContentIdentifier() ); 125 m_aEscapedTitle = aURI.GetPathBaseName(); 126 } 127 catch ( DAVException const & ) 128 { 129 throw ucb::ContentCreationException(); 130 } 131 } 132 133 //========================================================================= 134 // ctr for content on an non-existing webdav resource 135 Content::Content( 136 const uno::Reference< lang::XMultiServiceFactory >& rxSMgr, 137 ContentProvider* pProvider, 138 const uno::Reference< ucb::XContentIdentifier >& Identifier, 139 rtl::Reference< DAVSessionFactory > const & rSessionFactory, 140 sal_Bool isCollection ) 141 throw ( ucb::ContentCreationException ) 142 : ContentImplHelper( rxSMgr, pProvider, Identifier ), 143 m_eResourceType( UNKNOWN ), 144 m_pProvider( pProvider ), 145 m_bTransient( true ), 146 m_bCollection( isCollection ), 147 m_bDidGetOrHead( false ) 148 { 149 try 150 { 151 m_xResAccess.reset( new DAVResourceAccess( 152 rxSMgr, rSessionFactory, Identifier->getContentIdentifier() ) ); 153 } 154 catch ( DAVException const & ) 155 { 156 throw ucb::ContentCreationException(); 157 } 158 159 // Do not set m_aEscapedTitle here! Content::insert relays on this!!! 160 } 161 162 //========================================================================= 163 // virtual 164 Content::~Content() 165 { 166 } 167 168 //========================================================================= 169 // 170 // XInterface methods. 171 // 172 //========================================================================= 173 174 // virtual 175 void SAL_CALL Content::acquire() 176 throw( ) 177 { 178 ContentImplHelper::acquire(); 179 } 180 181 //========================================================================= 182 // virtual 183 void SAL_CALL Content::release() 184 throw( ) 185 { 186 ContentImplHelper::release(); 187 } 188 189 //========================================================================= 190 // virtual 191 uno::Any SAL_CALL Content::queryInterface( const uno::Type & rType ) 192 throw ( uno::RuntimeException ) 193 { 194 // Note: isFolder may require network activities! So call it only 195 // if it is really necessary!!! 196 uno::Any aRet = cppu::queryInterface( 197 rType, 198 static_cast< ucb::XContentCreator * >( this ) ); 199 if ( aRet.hasValue() ) 200 { 201 try 202 { 203 uno::Reference< beans::XPropertySet > const xProps( 204 m_xSMgr, uno::UNO_QUERY_THROW ); 205 uno::Reference< uno::XComponentContext > xCtx; 206 xCtx.set( xProps->getPropertyValue( 207 rtl::OUString( 208 RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ), 209 uno::UNO_QUERY_THROW ); 210 211 uno::Reference< task::XInteractionHandler > xIH( 212 task::PasswordContainerInteractionHandler::create( xCtx ) ); 213 214 // Supply a command env to isFolder() that contains an interaction 215 // handler that uses the password container service to obtain 216 // credentials without displaying a password gui. 217 218 uno::Reference< ucb::XCommandEnvironment > xCmdEnv( 219 ucb::CommandEnvironment::create( 220 xCtx, 221 xIH, 222 uno::Reference< ucb::XProgressHandler >() ) ); 223 224 return isFolder( xCmdEnv ) ? aRet : uno::Any(); 225 } 226 catch ( uno::RuntimeException const & ) 227 { 228 throw; 229 } 230 catch ( uno::Exception const & ) 231 { 232 return uno::Any(); 233 } 234 } 235 return aRet.hasValue() ? aRet : ContentImplHelper::queryInterface( rType ); 236 } 237 238 //========================================================================= 239 // 240 // XTypeProvider methods. 241 // 242 //========================================================================= 243 244 XTYPEPROVIDER_COMMON_IMPL( Content ); 245 246 //========================================================================= 247 // virtual 248 uno::Sequence< uno::Type > SAL_CALL Content::getTypes() 249 throw( uno::RuntimeException ) 250 { 251 sal_Bool bFolder = sal_False; 252 try 253 { 254 bFolder 255 = isFolder( uno::Reference< ucb::XCommandEnvironment >() ); 256 } 257 catch ( uno::RuntimeException const & ) 258 { 259 throw; 260 } 261 catch ( uno::Exception const & ) 262 { 263 } 264 265 cppu::OTypeCollection * pCollection = 0; 266 267 if ( bFolder ) 268 { 269 static cppu::OTypeCollection* pFolderTypes = 0; 270 271 pCollection = pFolderTypes; 272 if ( !pCollection ) 273 { 274 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 275 276 pCollection = pFolderTypes; 277 if ( !pCollection ) 278 { 279 static cppu::OTypeCollection aCollection( 280 CPPU_TYPE_REF( lang::XTypeProvider ), 281 CPPU_TYPE_REF( lang::XServiceInfo ), 282 CPPU_TYPE_REF( lang::XComponent ), 283 CPPU_TYPE_REF( ucb::XContent ), 284 CPPU_TYPE_REF( ucb::XCommandProcessor ), 285 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), 286 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), 287 CPPU_TYPE_REF( beans::XPropertyContainer ), 288 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), 289 CPPU_TYPE_REF( container::XChild ), 290 CPPU_TYPE_REF( ucb::XContentCreator ) ); // !! 291 pCollection = &aCollection; 292 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 293 pFolderTypes = pCollection; 294 } 295 } 296 else { 297 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 298 } 299 } 300 else 301 { 302 static cppu::OTypeCollection* pDocumentTypes = 0; 303 304 pCollection = pDocumentTypes; 305 if ( !pCollection ) 306 { 307 osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() ); 308 309 pCollection = pDocumentTypes; 310 if ( !pCollection ) 311 { 312 static cppu::OTypeCollection aCollection( 313 CPPU_TYPE_REF( lang::XTypeProvider ), 314 CPPU_TYPE_REF( lang::XServiceInfo ), 315 CPPU_TYPE_REF( lang::XComponent ), 316 CPPU_TYPE_REF( ucb::XContent ), 317 CPPU_TYPE_REF( ucb::XCommandProcessor ), 318 CPPU_TYPE_REF( beans::XPropertiesChangeNotifier ), 319 CPPU_TYPE_REF( ucb::XCommandInfoChangeNotifier ), 320 CPPU_TYPE_REF( beans::XPropertyContainer ), 321 CPPU_TYPE_REF( beans::XPropertySetInfoChangeNotifier ), 322 CPPU_TYPE_REF( container::XChild ) ); 323 pCollection = &aCollection; 324 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 325 pDocumentTypes = pCollection; 326 } 327 } 328 else { 329 OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); 330 } 331 } 332 333 return (*pCollection).getTypes(); 334 } 335 336 //========================================================================= 337 // 338 // XServiceInfo methods. 339 // 340 //========================================================================= 341 342 // virtual 343 rtl::OUString SAL_CALL Content::getImplementationName() 344 throw( uno::RuntimeException ) 345 { 346 return rtl::OUString::createFromAscii( 347 "com.sun.star.comp.ucb.WebDAVContent" ); 348 } 349 350 //========================================================================= 351 // virtual 352 uno::Sequence< rtl::OUString > SAL_CALL Content::getSupportedServiceNames() 353 throw( uno::RuntimeException ) 354 { 355 uno::Sequence< rtl::OUString > aSNS( 1 ); 356 aSNS.getArray()[ 0 ] 357 = rtl::OUString::createFromAscii( WEBDAV_CONTENT_SERVICE_NAME ); 358 return aSNS; 359 } 360 361 //========================================================================= 362 // 363 // XContent methods. 364 // 365 //========================================================================= 366 367 // virtual 368 rtl::OUString SAL_CALL Content::getContentType() 369 throw( uno::RuntimeException ) 370 { 371 sal_Bool bFolder = sal_False; 372 try 373 { 374 bFolder 375 = isFolder( uno::Reference< ucb::XCommandEnvironment >() ); 376 } 377 catch ( uno::RuntimeException const & ) 378 { 379 throw; 380 } 381 catch ( uno::Exception const & ) 382 { 383 } 384 385 if ( bFolder ) 386 return rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE ); 387 388 return rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE ); 389 } 390 391 //========================================================================= 392 // 393 // XCommandProcessor methods. 394 // 395 //========================================================================= 396 397 // virtual 398 uno::Any SAL_CALL Content::execute( 399 const ucb::Command& aCommand, 400 sal_Int32 /*CommandId*/, 401 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 402 throw( uno::Exception, 403 ucb::CommandAbortedException, 404 uno::RuntimeException ) 405 { 406 OSL_TRACE( ">>>>> Content::execute: start: command: %s, env: %s", 407 rtl::OUStringToOString( aCommand.Name, 408 RTL_TEXTENCODING_UTF8 ).getStr(), 409 Environment.is() ? "present" : "missing" ); 410 411 uno::Any aRet; 412 413 if ( aCommand.Name.equalsAsciiL( 414 RTL_CONSTASCII_STRINGPARAM( "getPropertyValues" ) ) ) 415 { 416 ////////////////////////////////////////////////////////////////// 417 // getPropertyValues 418 ////////////////////////////////////////////////////////////////// 419 420 uno::Sequence< beans::Property > Properties; 421 if ( !( aCommand.Argument >>= Properties ) ) 422 { 423 ucbhelper::cancelCommandExecution( 424 uno::makeAny( lang::IllegalArgumentException( 425 rtl::OUString::createFromAscii( 426 "Wrong argument type!" ), 427 static_cast< cppu::OWeakObject * >( this ), 428 -1 ) ), 429 Environment ); 430 // Unreachable 431 } 432 433 aRet <<= getPropertyValues( Properties, Environment ); 434 } 435 else if ( aCommand.Name.equalsAsciiL( 436 RTL_CONSTASCII_STRINGPARAM( "setPropertyValues" ) ) ) 437 { 438 ////////////////////////////////////////////////////////////////// 439 // setPropertyValues 440 ////////////////////////////////////////////////////////////////// 441 442 uno::Sequence< beans::PropertyValue > aProperties; 443 if ( !( aCommand.Argument >>= aProperties ) ) 444 { 445 ucbhelper::cancelCommandExecution( 446 uno::makeAny( lang::IllegalArgumentException( 447 rtl::OUString::createFromAscii( 448 "Wrong argument type!" ), 449 static_cast< cppu::OWeakObject * >( this ), 450 -1 ) ), 451 Environment ); 452 // Unreachable 453 } 454 455 if ( !aProperties.getLength() ) 456 { 457 ucbhelper::cancelCommandExecution( 458 uno::makeAny( lang::IllegalArgumentException( 459 rtl::OUString::createFromAscii( 460 "No properties!" ), 461 static_cast< cppu::OWeakObject * >( this ), 462 -1 ) ), 463 Environment ); 464 // Unreachable 465 } 466 467 aRet <<= setPropertyValues( aProperties, Environment ); 468 } 469 else if ( aCommand.Name.equalsAsciiL( 470 RTL_CONSTASCII_STRINGPARAM( "getPropertySetInfo" ) ) ) 471 { 472 ////////////////////////////////////////////////////////////////// 473 // getPropertySetInfo 474 ////////////////////////////////////////////////////////////////// 475 476 // Note: Implemented by base class. 477 aRet <<= getPropertySetInfo( Environment, 478 sal_False /* don't cache data */ ); 479 } 480 else if ( aCommand.Name.equalsAsciiL( 481 RTL_CONSTASCII_STRINGPARAM( "getCommandInfo" ) ) ) 482 { 483 ////////////////////////////////////////////////////////////////// 484 // getCommandInfo 485 ////////////////////////////////////////////////////////////////// 486 487 // Note: Implemented by base class. 488 aRet <<= getCommandInfo( Environment, sal_False ); 489 } 490 else if ( aCommand.Name.equalsAsciiL( 491 RTL_CONSTASCII_STRINGPARAM( "open" ) ) ) 492 { 493 ////////////////////////////////////////////////////////////////// 494 // open 495 ////////////////////////////////////////////////////////////////// 496 497 ucb::OpenCommandArgument2 aOpenCommand; 498 if ( !( aCommand.Argument >>= aOpenCommand ) ) 499 { 500 ucbhelper::cancelCommandExecution( 501 uno::makeAny( lang::IllegalArgumentException( 502 rtl::OUString::createFromAscii( 503 "Wrong argument type!" ), 504 static_cast< cppu::OWeakObject * >( this ), 505 -1 ) ), 506 Environment ); 507 // Unreachable 508 } 509 510 aRet = open( aOpenCommand, Environment ); 511 } 512 else if ( aCommand.Name.equalsAsciiL( 513 RTL_CONSTASCII_STRINGPARAM( "insert" ) ) ) 514 { 515 ////////////////////////////////////////////////////////////////// 516 // insert 517 ////////////////////////////////////////////////////////////////// 518 519 ucb::InsertCommandArgument arg; 520 if ( !( aCommand.Argument >>= arg ) ) 521 { 522 ucbhelper::cancelCommandExecution( 523 uno::makeAny( lang::IllegalArgumentException( 524 rtl::OUString::createFromAscii( 525 "Wrong argument type!" ), 526 static_cast< cppu::OWeakObject * >( this ), 527 -1 ) ), 528 Environment ); 529 // Unreachable 530 } 531 532 insert( arg.Data, arg.ReplaceExisting, Environment ); 533 } 534 else if ( aCommand.Name.equalsAsciiL( 535 RTL_CONSTASCII_STRINGPARAM( "delete" ) ) ) 536 { 537 ////////////////////////////////////////////////////////////////// 538 // delete 539 ////////////////////////////////////////////////////////////////// 540 541 sal_Bool bDeletePhysical = sal_False; 542 aCommand.Argument >>= bDeletePhysical; 543 544 // KSO: Ignore parameter and destroy the content, if you don't support 545 // putting objects into trashcan. ( Since we do not have a trash can 546 // service yet (src603), you actually have no other choice. ) 547 // if ( bDeletePhysical ) 548 // { 549 try 550 { 551 std::auto_ptr< DAVResourceAccess > xResAccess; 552 { 553 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 554 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 555 } 556 xResAccess->DESTROY( Environment ); 557 { 558 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 559 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 560 } 561 } 562 catch ( DAVException const & e ) 563 { 564 cancelCommandExecution( e, Environment, sal_True ); 565 // Unreachable 566 } 567 // } 568 569 // Propagate destruction. 570 destroy( bDeletePhysical ); 571 572 // Remove own and all children's Additional Core Properties. 573 removeAdditionalPropertySet( sal_True ); 574 } 575 else if ( aCommand.Name.equalsAsciiL( 576 RTL_CONSTASCII_STRINGPARAM( "transfer" ) ) 577 && isFolder( Environment ) ) 578 { 579 ////////////////////////////////////////////////////////////////// 580 // transfer 581 // ( Not available at documents ) 582 ////////////////////////////////////////////////////////////////// 583 584 ucb::TransferInfo transferArgs; 585 if ( !( aCommand.Argument >>= transferArgs ) ) 586 { 587 ucbhelper::cancelCommandExecution( 588 uno::makeAny( lang::IllegalArgumentException( 589 rtl::OUString::createFromAscii( 590 "Wrong argument type!" ), 591 static_cast< cppu::OWeakObject * >( this ), 592 -1 ) ), 593 Environment ); 594 // Unreachable 595 } 596 597 transfer( transferArgs, Environment ); 598 } 599 else if ( aCommand.Name.equalsAsciiL( 600 RTL_CONSTASCII_STRINGPARAM( "post" ) ) ) 601 { 602 ////////////////////////////////////////////////////////////////// 603 // post 604 ////////////////////////////////////////////////////////////////// 605 606 ucb::PostCommandArgument2 aArg; 607 if ( !( aCommand.Argument >>= aArg ) ) 608 { 609 ucbhelper::cancelCommandExecution( 610 uno::makeAny( lang::IllegalArgumentException( 611 rtl::OUString::createFromAscii( 612 "Wrong argument type!" ), 613 static_cast< cppu::OWeakObject * >( this ), 614 -1 ) ), 615 Environment ); 616 // Unreachable 617 } 618 619 post( aArg, Environment ); 620 } 621 else if ( aCommand.Name.equalsAsciiL( 622 RTL_CONSTASCII_STRINGPARAM( "lock" ) ) && 623 supportsExclusiveWriteLock( Environment ) ) 624 { 625 ////////////////////////////////////////////////////////////////// 626 // lock 627 ////////////////////////////////////////////////////////////////// 628 629 lock( Environment ); 630 } 631 else if ( aCommand.Name.equalsAsciiL( 632 RTL_CONSTASCII_STRINGPARAM( "unlock" ) ) && 633 supportsExclusiveWriteLock( Environment ) ) 634 { 635 ////////////////////////////////////////////////////////////////// 636 // unlock 637 ////////////////////////////////////////////////////////////////// 638 639 unlock( Environment ); 640 } 641 else if ( aCommand.Name.equalsAsciiL( 642 RTL_CONSTASCII_STRINGPARAM( "createNewContent" ) ) && 643 isFolder( Environment ) ) 644 { 645 ////////////////////////////////////////////////////////////////// 646 // createNewContent 647 ////////////////////////////////////////////////////////////////// 648 649 ucb::ContentInfo aArg; 650 if ( !( aCommand.Argument >>= aArg ) ) 651 { 652 ucbhelper::cancelCommandExecution( 653 uno::makeAny( lang::IllegalArgumentException( 654 rtl::OUString::createFromAscii( 655 "Wrong argument type!" ), 656 static_cast< cppu::OWeakObject * >( this ), 657 -1 ) ), 658 Environment ); 659 // Unreachable 660 } 661 662 aRet = uno::makeAny( createNewContent( aArg ) ); 663 } 664 else 665 { 666 ////////////////////////////////////////////////////////////////// 667 // Unsupported command 668 ////////////////////////////////////////////////////////////////// 669 670 ucbhelper::cancelCommandExecution( 671 uno::makeAny( ucb::UnsupportedCommandException( 672 aCommand.Name, 673 static_cast< cppu::OWeakObject * >( this ) ) ), 674 Environment ); 675 // Unreachable 676 } 677 678 OSL_TRACE( "<<<<< Content::execute: end: command: %s", 679 rtl::OUStringToOString( aCommand.Name, 680 RTL_TEXTENCODING_UTF8 ).getStr() ); 681 682 return aRet; 683 } 684 685 //========================================================================= 686 // virtual 687 void SAL_CALL Content::abort( sal_Int32 /*CommandId*/ ) 688 throw( uno::RuntimeException ) 689 { 690 try 691 { 692 std::auto_ptr< DAVResourceAccess > xResAccess; 693 { 694 osl::MutexGuard aGuard( m_aMutex ); 695 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 696 } 697 xResAccess->abort(); 698 { 699 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 700 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 701 } 702 } 703 catch ( DAVException const & ) 704 { 705 // abort failed! 706 } 707 } 708 709 //========================================================================= 710 // 711 // XPropertyContainer methods. 712 // 713 //========================================================================= 714 715 // virtual 716 void SAL_CALL Content::addProperty( const rtl::OUString& Name, 717 sal_Int16 Attributes, 718 const uno::Any& DefaultValue ) 719 throw( beans::PropertyExistException, 720 beans::IllegalTypeException, 721 lang::IllegalArgumentException, 722 uno::RuntimeException ) 723 { 724 // if ( m_bTransient ) 725 // @@@ ??? 726 727 if ( !Name.getLength() ) 728 throw lang::IllegalArgumentException(); 729 730 // Check property type. 731 if ( !UCBDeadPropertyValue::supportsType( DefaultValue.getValueType() ) ) 732 { 733 OSL_ENSURE( sal_False, 734 "Content::addProperty - Unsupported property type!" ); 735 throw beans::IllegalTypeException(); 736 } 737 738 ////////////////////////////////////////////////////////////////////// 739 // Make sure a property with the requested name does not already 740 // exist in dynamic and static(!) properties. 741 ////////////////////////////////////////////////////////////////////// 742 743 // @@@ Need real command environment here, but where to get it from? 744 // XPropertyContainer interface should be replaced by 745 // XCommandProcessor commands! 746 uno::Reference< ucb::XCommandEnvironment > xEnv; 747 748 // Note: This requires network access! 749 if ( getPropertySetInfo( xEnv, sal_False /* don't cache data */ ) 750 ->hasPropertyByName( Name ) ) 751 { 752 // Property does already exist. 753 throw beans::PropertyExistException(); 754 } 755 756 ////////////////////////////////////////////////////////////////////// 757 // Add a new dynamic property. 758 ////////////////////////////////////////////////////////////////////// 759 760 ProppatchValue aValue( PROPSET, Name, DefaultValue ); 761 762 std::vector< ProppatchValue > aProppatchValues; 763 aProppatchValues.push_back( aValue ); 764 765 try 766 { 767 // Set property value at server. 768 std::auto_ptr< DAVResourceAccess > xResAccess; 769 { 770 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 771 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 772 } 773 xResAccess->PROPPATCH( aProppatchValues, xEnv ); 774 { 775 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 776 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 777 } 778 779 // Notify propertyset info change listeners. 780 beans::PropertySetInfoChangeEvent evt( 781 static_cast< cppu::OWeakObject * >( this ), 782 Name, 783 -1, // No handle available 784 beans::PropertySetInfoChange::PROPERTY_INSERTED ); 785 notifyPropertySetInfoChange( evt ); 786 } 787 catch ( DAVException const & e ) 788 { 789 if ( e.getStatus() == SC_FORBIDDEN ) 790 { 791 // Support for setting arbitrary dead properties is optional! 792 793 // Store property locally. 794 ContentImplHelper::addProperty( 795 Name, Attributes, DefaultValue ); 796 } 797 else 798 { 799 if ( shouldAccessNetworkAfterException( e ) ) 800 { 801 try 802 { 803 const ResourceType & rType = getResourceType( xEnv ); 804 switch ( rType ) 805 { 806 case UNKNOWN: 807 case DAV: 808 throw lang::IllegalArgumentException(); 809 810 case FTP: 811 case NON_DAV: 812 // Store property locally. 813 ContentImplHelper::addProperty( Name, 814 Attributes, 815 DefaultValue ); 816 break; 817 818 default: 819 OSL_ENSURE( sal_False, 820 "Content::addProperty - " 821 "Unsupported resource type!" ); 822 break; 823 } 824 } 825 catch ( uno::Exception const & ) 826 { 827 OSL_ENSURE( sal_False, 828 "Content::addProperty - " 829 "Unable to determine resource type!" ); 830 } 831 } 832 else 833 { 834 OSL_ENSURE( sal_False, 835 "Content::addProperty - " 836 "Unable to determine resource type!" ); 837 } 838 } 839 } 840 } 841 842 //========================================================================= 843 // virtual 844 void SAL_CALL Content::removeProperty( const rtl::OUString& Name ) 845 throw( beans::UnknownPropertyException, 846 beans::NotRemoveableException, 847 uno::RuntimeException ) 848 { 849 // @@@ Need real command environment here, but where to get it from? 850 // XPropertyContainer interface should be replaced by 851 // XCommandProcessor commands! 852 uno::Reference< ucb::XCommandEnvironment > xEnv; 853 854 #if 0 855 // @@@ REMOVEABLE z.Z. nicht richtig an der PropSetInfo gesetzt!!! 856 try 857 { 858 beans::Property aProp 859 = getPropertySetInfo( xEnv, sal_False /* don't cache data */ ) 860 ->getPropertyByName( Name ); 861 862 if ( !( aProp.Attributes & beans::PropertyAttribute::REMOVEABLE ) ) 863 { 864 // Not removeable! 865 throw beans::NotRemoveableException(); 866 } 867 } 868 catch ( beans::UnknownPropertyException const & ) 869 { 870 //OSL_ENSURE( sal_False, "removeProperty - Unknown property!" ); 871 throw; 872 } 873 #endif 874 875 ////////////////////////////////////////////////////////////////////// 876 // Try to remove property from server. 877 ////////////////////////////////////////////////////////////////////// 878 879 try 880 { 881 std::vector< ProppatchValue > aProppatchValues; 882 ProppatchValue aValue( PROPREMOVE, Name, uno::Any() ); 883 aProppatchValues.push_back( aValue ); 884 885 // Remove property value from server. 886 std::auto_ptr< DAVResourceAccess > xResAccess; 887 { 888 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 889 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 890 } 891 xResAccess->PROPPATCH( aProppatchValues, xEnv ); 892 { 893 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 894 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 895 } 896 897 // Notify propertyset info change listeners. 898 beans::PropertySetInfoChangeEvent evt( 899 static_cast< cppu::OWeakObject * >( this ), 900 Name, 901 -1, // No handle available 902 beans::PropertySetInfoChange::PROPERTY_REMOVED ); 903 notifyPropertySetInfoChange( evt ); 904 } 905 catch ( DAVException const & e ) 906 { 907 if ( e.getStatus() == SC_FORBIDDEN ) 908 { 909 // Support for setting arbitrary dead properties is optional! 910 911 // Try to remove property from local store. 912 ContentImplHelper::removeProperty( Name ); 913 } 914 else 915 { 916 if ( shouldAccessNetworkAfterException( e ) ) 917 { 918 try 919 { 920 const ResourceType & rType = getResourceType( xEnv ); 921 switch ( rType ) 922 { 923 case UNKNOWN: 924 case DAV: 925 throw beans::UnknownPropertyException(); 926 927 case FTP: 928 case NON_DAV: 929 // Try to remove property from local store. 930 ContentImplHelper::removeProperty( Name ); 931 break; 932 933 default: 934 OSL_ENSURE( sal_False, 935 "Content::removeProperty - " 936 "Unsupported resource type!" ); 937 break; 938 } 939 } 940 catch ( uno::Exception const & ) 941 { 942 OSL_ENSURE( sal_False, 943 "Content::removeProperty - " 944 "Unable to determine resource type!" ); 945 } 946 } 947 else 948 { 949 OSL_ENSURE( sal_False, 950 "Content::removeProperty - " 951 "Unable to determine resource type!" ); 952 // throw beans::UnknownPropertyException(); 953 } 954 } 955 } 956 } 957 958 //========================================================================= 959 // 960 // XContentCreator methods. 961 // 962 //========================================================================= 963 964 // virtual 965 uno::Sequence< ucb::ContentInfo > SAL_CALL 966 Content::queryCreatableContentsInfo() 967 throw( uno::RuntimeException ) 968 { 969 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 970 971 uno::Sequence< ucb::ContentInfo > aSeq( 2 ); 972 973 // document. 974 aSeq.getArray()[ 0 ].Type 975 = rtl::OUString::createFromAscii( WEBDAV_CONTENT_TYPE ); 976 aSeq.getArray()[ 0 ].Attributes 977 = ucb::ContentInfoAttribute::INSERT_WITH_INPUTSTREAM 978 | ucb::ContentInfoAttribute::KIND_DOCUMENT; 979 980 beans::Property aProp; 981 m_pProvider->getProperty( 982 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), aProp ); 983 984 uno::Sequence< beans::Property > aDocProps( 1 ); 985 aDocProps.getArray()[ 0 ] = aProp; 986 aSeq.getArray()[ 0 ].Properties = aDocProps; 987 988 // folder. 989 aSeq.getArray()[ 1 ].Type 990 = rtl::OUString::createFromAscii( WEBDAV_COLLECTION_TYPE ); 991 aSeq.getArray()[ 1 ].Attributes 992 = ucb::ContentInfoAttribute::KIND_FOLDER; 993 994 uno::Sequence< beans::Property > aFolderProps( 1 ); 995 aFolderProps.getArray()[ 0 ] = aProp; 996 aSeq.getArray()[ 1 ].Properties = aFolderProps; 997 return aSeq; 998 } 999 1000 //========================================================================= 1001 // virtual 1002 uno::Reference< ucb::XContent > SAL_CALL 1003 Content::createNewContent( const ucb::ContentInfo& Info ) 1004 throw( uno::RuntimeException ) 1005 { 1006 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1007 1008 if ( !Info.Type.getLength() ) 1009 return uno::Reference< ucb::XContent >(); 1010 1011 if ( ( !Info.Type.equalsAsciiL( 1012 RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) ) 1013 && 1014 ( !Info.Type.equalsAsciiL( 1015 RTL_CONSTASCII_STRINGPARAM( WEBDAV_CONTENT_TYPE ) ) ) ) 1016 return uno::Reference< ucb::XContent >(); 1017 1018 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 1019 1020 OSL_ENSURE( aURL.getLength() > 0, 1021 "WebdavContent::createNewContent - empty identifier!" ); 1022 1023 if ( ( aURL.lastIndexOf( '/' ) + 1 ) != aURL.getLength() ) 1024 aURL += rtl::OUString::createFromAscii( "/" ); 1025 1026 sal_Bool isCollection; 1027 if ( Info.Type.equalsAsciiL( 1028 RTL_CONSTASCII_STRINGPARAM( WEBDAV_COLLECTION_TYPE ) ) ) 1029 { 1030 aURL += rtl::OUString::createFromAscii( "New_Collection" ); 1031 isCollection = sal_True; 1032 } 1033 else 1034 { 1035 aURL += rtl::OUString::createFromAscii( "New_Content" ); 1036 isCollection = sal_False; 1037 } 1038 1039 uno::Reference< ucb::XContentIdentifier > xId( 1040 new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ) ); 1041 1042 // create the local content 1043 try 1044 { 1045 return new ::webdav_ucp::Content( m_xSMgr, 1046 m_pProvider, 1047 xId, 1048 m_xResAccess->getSessionFactory(), 1049 isCollection ); 1050 } 1051 catch ( ucb::ContentCreationException & ) 1052 { 1053 return uno::Reference< ucb::XContent >(); 1054 } 1055 } 1056 1057 //========================================================================= 1058 // virtual 1059 rtl::OUString Content::getParentURL() 1060 { 1061 // <scheme>:// -> "" 1062 // <scheme>://foo -> "" 1063 // <scheme>://foo/ -> "" 1064 // <scheme>://foo/bar -> <scheme>://foo/ 1065 // <scheme>://foo/bar/ -> <scheme>://foo/ 1066 // <scheme>://foo/bar/abc -> <scheme>://foo/bar/ 1067 1068 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 1069 1070 sal_Int32 nPos = aURL.lastIndexOf( '/' ); 1071 if ( nPos == ( aURL.getLength() - 1 ) ) 1072 { 1073 // Trailing slash found. Skip. 1074 nPos = aURL.lastIndexOf( '/', nPos ); 1075 } 1076 1077 sal_Int32 nPos1 = aURL.lastIndexOf( '/', nPos ); 1078 if ( nPos1 != -1 ) 1079 nPos1 = aURL.lastIndexOf( '/', nPos1 ); 1080 1081 if ( nPos1 == -1 ) 1082 return rtl::OUString(); 1083 1084 return rtl::OUString( aURL.copy( 0, nPos + 1 ) ); 1085 } 1086 1087 //========================================================================= 1088 // 1089 // Non-interface methods. 1090 // 1091 //========================================================================= 1092 1093 // static 1094 uno::Reference< sdbc::XRow > Content::getPropertyValues( 1095 const uno::Reference< lang::XMultiServiceFactory >& rSMgr, 1096 const uno::Sequence< beans::Property >& rProperties, 1097 const ContentProperties& rData, 1098 const rtl::Reference< ::ucbhelper::ContentProviderImplHelper >& rProvider, 1099 const rtl::OUString& rContentId ) 1100 { 1101 // Note: Empty sequence means "get values of all supported properties". 1102 1103 rtl::Reference< ::ucbhelper::PropertyValueSet > xRow 1104 = new ::ucbhelper::PropertyValueSet( rSMgr ); 1105 1106 sal_Int32 nCount = rProperties.getLength(); 1107 if ( nCount ) 1108 { 1109 uno::Reference< beans::XPropertySet > xAdditionalPropSet; 1110 sal_Bool bTriedToGetAdditonalPropSet = sal_False; 1111 1112 const beans::Property* pProps = rProperties.getConstArray(); 1113 for ( sal_Int32 n = 0; n < nCount; ++n ) 1114 { 1115 const beans::Property& rProp = pProps[ n ]; 1116 1117 // Process standard UCB, DAV and HTTP properties. 1118 const uno::Any & rValue = rData.getValue( rProp.Name ); 1119 if ( rValue.hasValue() ) 1120 { 1121 xRow->appendObject( rProp, rValue ); 1122 } 1123 else 1124 { 1125 // Process local Additional Properties. 1126 if ( !bTriedToGetAdditonalPropSet && !xAdditionalPropSet.is() ) 1127 { 1128 xAdditionalPropSet 1129 = uno::Reference< beans::XPropertySet >( 1130 rProvider->getAdditionalPropertySet( rContentId, 1131 sal_False ), 1132 uno::UNO_QUERY ); 1133 bTriedToGetAdditonalPropSet = sal_True; 1134 } 1135 1136 if ( !xAdditionalPropSet.is() || 1137 !xRow->appendPropertySetValue( 1138 xAdditionalPropSet, rProp ) ) 1139 { 1140 // Append empty entry. 1141 xRow->appendVoid( rProp ); 1142 } 1143 } 1144 } 1145 } 1146 else 1147 { 1148 // Append all standard UCB, DAV and HTTP properties. 1149 1150 const std::auto_ptr< PropertyValueMap > & xProps = rData.getProperties(); 1151 1152 PropertyValueMap::const_iterator it = xProps->begin(); 1153 PropertyValueMap::const_iterator end = xProps->end(); 1154 1155 ContentProvider * pProvider 1156 = static_cast< ContentProvider * >( rProvider.get() ); 1157 beans::Property aProp; 1158 1159 while ( it != end ) 1160 { 1161 if ( pProvider->getProperty( (*it).first, aProp ) ) 1162 xRow->appendObject( aProp, (*it).second.value() ); 1163 1164 ++it; 1165 } 1166 1167 // Append all local Additional Properties. 1168 uno::Reference< beans::XPropertySet > xSet( 1169 rProvider->getAdditionalPropertySet( rContentId, sal_False ), 1170 uno::UNO_QUERY ); 1171 xRow->appendPropertySet( xSet ); 1172 } 1173 1174 return uno::Reference< sdbc::XRow >( xRow.get() ); 1175 } 1176 1177 //========================================================================= 1178 uno::Reference< sdbc::XRow > Content::getPropertyValues( 1179 const uno::Sequence< beans::Property >& rProperties, 1180 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1181 throw ( uno::Exception ) 1182 { 1183 std::auto_ptr< ContentProperties > xProps; 1184 std::auto_ptr< ContentProperties > xCachedProps; 1185 std::auto_ptr< DAVResourceAccess > xResAccess; 1186 rtl::OUString aUnescapedTitle; 1187 bool bHasAll = false; 1188 uno::Reference< lang::XMultiServiceFactory > xSMgr; 1189 uno::Reference< ucb::XContentIdentifier > xIdentifier; 1190 rtl::Reference< ::ucbhelper::ContentProviderImplHelper > xProvider; 1191 1192 { 1193 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1194 1195 aUnescapedTitle = NeonUri::unescape( m_aEscapedTitle ); 1196 xSMgr.set( m_xSMgr ); 1197 xIdentifier.set( m_xIdentifier ); 1198 xProvider.set( m_xProvider.get() ); 1199 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 1200 1201 // First, ask cache... 1202 if ( m_xCachedProps.get() ) 1203 { 1204 xCachedProps.reset( new ContentProperties( *m_xCachedProps.get() ) ); 1205 1206 std::vector< rtl::OUString > aMissingProps; 1207 if ( xCachedProps->containsAllNames( rProperties, aMissingProps ) ) 1208 { 1209 // All properties are already in cache! No server access needed. 1210 bHasAll = true; 1211 } 1212 1213 // use the cached ContentProperties instance 1214 xProps.reset( new ContentProperties( *xCachedProps.get() ) ); 1215 } 1216 } 1217 1218 if ( !m_bTransient && !bHasAll ) 1219 { 1220 ///////////////////////////////////////////////////////////////////// 1221 // Obtain values from server... 1222 ///////////////////////////////////////////////////////////////////// 1223 1224 // First, identify whether resource is DAV or not 1225 const ResourceType & rType = getResourceType( xEnv, xResAccess ); 1226 1227 bool bNetworkAccessAllowed = true; 1228 1229 if ( DAV == rType ) 1230 { 1231 // cache lookup... getResourceType may fill the props cache via 1232 // PROPFIND! 1233 if ( m_xCachedProps.get() ) 1234 { 1235 xCachedProps.reset( 1236 new ContentProperties( *m_xCachedProps.get() ) ); 1237 1238 std::vector< rtl::OUString > aMissingProps; 1239 if ( xCachedProps->containsAllNames( 1240 rProperties, aMissingProps ) ) 1241 { 1242 // All properties are already in cache! No server access 1243 // needed. 1244 bHasAll = true; 1245 } 1246 1247 // use the cached ContentProperties instance 1248 xProps.reset( new ContentProperties( *xCachedProps.get() ) ); 1249 } 1250 1251 if ( !bHasAll ) 1252 { 1253 // Only DAV resources support PROPFIND 1254 std::vector< rtl::OUString > aPropNames; 1255 1256 uno::Sequence< beans::Property > aProperties( 1257 rProperties.getLength() ); 1258 1259 if ( m_aFailedPropNames.size() > 0 ) 1260 { 1261 sal_Int32 nProps = 0; 1262 sal_Int32 nCount = rProperties.getLength(); 1263 for ( sal_Int32 n = 0; n < nCount; ++n ) 1264 { 1265 const rtl::OUString & rName = rProperties[ n ].Name; 1266 1267 std::vector< rtl::OUString >::const_iterator it 1268 = m_aFailedPropNames.begin(); 1269 std::vector< rtl::OUString >::const_iterator end 1270 = m_aFailedPropNames.end(); 1271 1272 while ( it != end ) 1273 { 1274 if ( *it == rName ) 1275 break; 1276 1277 ++it; 1278 } 1279 1280 if ( it == end ) 1281 { 1282 aProperties[ nProps ] = rProperties[ n ]; 1283 nProps++; 1284 } 1285 } 1286 1287 aProperties.realloc( nProps ); 1288 } 1289 else 1290 { 1291 aProperties = rProperties; 1292 } 1293 1294 if ( aProperties.getLength() > 0 ) 1295 ContentProperties::UCBNamesToDAVNames( 1296 aProperties, aPropNames ); 1297 1298 if ( aPropNames.size() > 0 ) 1299 { 1300 std::vector< DAVResource > resources; 1301 try 1302 { 1303 xResAccess->PROPFIND( 1304 DAVZERO, aPropNames, resources, xEnv ); 1305 1306 if ( 1 == resources.size() ) 1307 { 1308 if ( xProps.get()) 1309 xProps->addProperties( 1310 aPropNames, 1311 ContentProperties( resources[ 0 ] )); 1312 else 1313 xProps.reset( 1314 new ContentProperties( resources[ 0 ] ) ); 1315 } 1316 } 1317 catch ( DAVException const & e ) 1318 { 1319 bNetworkAccessAllowed 1320 = shouldAccessNetworkAfterException( e ); 1321 1322 if ( !bNetworkAccessAllowed ) 1323 { 1324 cancelCommandExecution( e, xEnv ); 1325 // unreachable 1326 } 1327 } 1328 } 1329 } 1330 } 1331 1332 if ( bNetworkAccessAllowed ) 1333 { 1334 // All properties obtained already? 1335 std::vector< rtl::OUString > aMissingProps; 1336 if ( !( xProps.get() 1337 && xProps->containsAllNames( 1338 rProperties, aMissingProps ) ) 1339 && !m_bDidGetOrHead ) 1340 { 1341 // Possibly the missing props can be obtained using a HEAD 1342 // request. 1343 1344 std::vector< rtl::OUString > aHeaderNames; 1345 ContentProperties::UCBNamesToHTTPNames( 1346 rProperties, 1347 aHeaderNames, 1348 true /* bIncludeUnmatched */ ); 1349 1350 if ( aHeaderNames.size() > 0 ) 1351 { 1352 try 1353 { 1354 DAVResource resource; 1355 xResAccess->HEAD( aHeaderNames, resource, xEnv ); 1356 m_bDidGetOrHead = true; 1357 1358 if ( xProps.get() ) 1359 xProps->addProperties( 1360 aMissingProps, 1361 ContentProperties( resource ) ); 1362 else 1363 xProps.reset ( new ContentProperties( resource ) ); 1364 1365 if ( m_eResourceType == NON_DAV ) 1366 xProps->addProperties( aMissingProps, 1367 ContentProperties( 1368 aUnescapedTitle, 1369 false ) ); 1370 } 1371 catch ( DAVException const & e ) 1372 { 1373 bNetworkAccessAllowed 1374 = shouldAccessNetworkAfterException( e ); 1375 1376 if ( !bNetworkAccessAllowed ) 1377 { 1378 cancelCommandExecution( e, xEnv ); 1379 // unreachable 1380 } 1381 } 1382 } 1383 } 1384 } 1385 1386 // might trigger HTTP redirect. 1387 // Therefore, title must be updated here. 1388 NeonUri aUri( xResAccess->getURL() ); 1389 aUnescapedTitle = aUri.GetPathBaseNameUnescaped(); 1390 1391 if ( rType == UNKNOWN ) 1392 { 1393 xProps.reset( new ContentProperties( aUnescapedTitle ) ); 1394 } 1395 1396 // For DAV resources we only know the Title, for non-DAV 1397 // resources we additionally know that it is a document. 1398 1399 if ( rType == DAV ) 1400 { 1401 //xProps.reset( 1402 // new ContentProperties( aUnescapedTitle ) ); 1403 xProps->addProperty( 1404 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), 1405 uno::makeAny( aUnescapedTitle ), 1406 true ); 1407 } 1408 else 1409 { 1410 if ( !xProps.get() ) 1411 xProps.reset( new ContentProperties( aUnescapedTitle, false ) ); 1412 else 1413 xProps->addProperty( 1414 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) ), 1415 uno::makeAny( aUnescapedTitle ), 1416 true ); 1417 1418 xProps->addProperty( 1419 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ), 1420 uno::makeAny( false ), 1421 true ); 1422 xProps->addProperty( 1423 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsDocument" ) ), 1424 uno::makeAny( true ), 1425 true ); 1426 } 1427 } 1428 else 1429 { 1430 // No server access for just created (not yet committed) objects. 1431 // Only a minimal set of properties supported at this stage. 1432 if (m_bTransient) 1433 xProps.reset( new ContentProperties( aUnescapedTitle, 1434 m_bCollection ) ); 1435 } 1436 1437 sal_Int32 nCount = rProperties.getLength(); 1438 for ( sal_Int32 n = 0; n < nCount; ++n ) 1439 { 1440 const rtl::OUString rName = rProperties[ n ].Name; 1441 if ( rName.equalsAsciiL( 1442 RTL_CONSTASCII_STRINGPARAM( "BaseURI" ) ) ) 1443 { 1444 // Add BaseURI property, if requested. 1445 xProps->addProperty( 1446 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BaseURI" ) ), 1447 uno::makeAny( getBaseURI( xResAccess ) ), 1448 true ); 1449 } 1450 else if ( rName.equalsAsciiL( 1451 RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) 1452 { 1453 // Add CreatableContentsInfo property, if requested. 1454 sal_Bool bFolder = sal_False; 1455 xProps->getValue( 1456 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) ) ) 1457 >>= bFolder; 1458 xProps->addProperty( 1459 rtl::OUString( 1460 RTL_CONSTASCII_USTRINGPARAM( "CreatableContentsInfo" ) ), 1461 uno::makeAny( bFolder 1462 ? queryCreatableContentsInfo() 1463 : uno::Sequence< ucb::ContentInfo >() ), 1464 true ); 1465 } 1466 } 1467 1468 uno::Reference< sdbc::XRow > xResultRow 1469 = getPropertyValues( xSMgr, 1470 rProperties, 1471 *xProps, 1472 xProvider, 1473 xIdentifier->getContentIdentifier() ); 1474 1475 { 1476 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1477 1478 if ( !m_xCachedProps.get() ) 1479 m_xCachedProps.reset( new CachableContentProperties( *xProps.get() ) ); 1480 else 1481 m_xCachedProps->addProperties( *xProps.get() ); 1482 1483 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 1484 m_aEscapedTitle = NeonUri::escapeSegment( aUnescapedTitle ); 1485 } 1486 1487 return xResultRow; 1488 } 1489 1490 //========================================================================= 1491 uno::Sequence< uno::Any > Content::setPropertyValues( 1492 const uno::Sequence< beans::PropertyValue >& rValues, 1493 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 1494 throw ( uno::Exception ) 1495 { 1496 uno::Reference< lang::XMultiServiceFactory > xSMgr; 1497 uno::Reference< ucb::XContentIdentifier > xIdentifier; 1498 rtl::Reference< ContentProvider > xProvider; 1499 sal_Bool bTransient; 1500 std::auto_ptr< DAVResourceAccess > xResAccess; 1501 1502 { 1503 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1504 1505 xProvider.set( m_pProvider ); 1506 xIdentifier.set( m_xIdentifier ); 1507 bTransient = m_bTransient; 1508 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 1509 xSMgr.set( m_xSMgr ); 1510 } 1511 1512 uno::Sequence< uno::Any > aRet( rValues.getLength() ); 1513 uno::Sequence< beans::PropertyChangeEvent > aChanges( rValues.getLength() ); 1514 sal_Int32 nChanged = 0; 1515 1516 beans::PropertyChangeEvent aEvent; 1517 aEvent.Source = static_cast< cppu::OWeakObject * >( this ); 1518 aEvent.Further = sal_False; 1519 // aEvent.PropertyName = 1520 aEvent.PropertyHandle = -1; 1521 // aEvent.OldValue = 1522 // aEvent.NewValue = 1523 1524 std::vector< ProppatchValue > aProppatchValues; 1525 std::vector< sal_Int32 > aProppatchPropsPositions; 1526 1527 uno::Reference< ucb::XPersistentPropertySet > xAdditionalPropSet; 1528 sal_Bool bTriedToGetAdditonalPropSet = sal_False; 1529 1530 sal_Bool bExchange = sal_False; 1531 rtl::OUString aNewTitle; 1532 rtl::OUString aOldTitle; 1533 sal_Int32 nTitlePos = -1; 1534 1535 uno::Reference< beans::XPropertySetInfo > xInfo; 1536 1537 const beans::PropertyValue* pValues = rValues.getConstArray(); 1538 sal_Int32 nCount = rValues.getLength(); 1539 for ( sal_Int32 n = 0; n < nCount; ++n ) 1540 { 1541 const beans::PropertyValue& rValue = pValues[ n ]; 1542 const rtl::OUString & rName = rValue.Name; 1543 1544 beans::Property aTmpProp; 1545 xProvider->getProperty( rName, aTmpProp ); 1546 1547 if ( aTmpProp.Attributes & beans::PropertyAttribute::READONLY ) 1548 { 1549 // Read-only property! 1550 aRet[ n ] <<= lang::IllegalAccessException( 1551 rtl::OUString::createFromAscii( 1552 "Property is read-only!" ), 1553 static_cast< cppu::OWeakObject * >( this ) ); 1554 continue; 1555 } 1556 1557 ////////////////////////////////////////////////////////////////// 1558 // Mandatory props. 1559 ////////////////////////////////////////////////////////////////// 1560 1561 if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ContentType" ) ) ) 1562 { 1563 // Read-only property! 1564 aRet[ n ] <<= lang::IllegalAccessException( 1565 rtl::OUString::createFromAscii( 1566 "Property is read-only!" ), 1567 static_cast< cppu::OWeakObject * >( this ) ); 1568 } 1569 else if ( rName.equalsAsciiL( 1570 RTL_CONSTASCII_STRINGPARAM( "IsDocument" ) ) ) 1571 { 1572 // Read-only property! 1573 aRet[ n ] <<= lang::IllegalAccessException( 1574 rtl::OUString::createFromAscii( 1575 "Property is read-only!" ), 1576 static_cast< cppu::OWeakObject * >( this ) ); 1577 } 1578 else if ( rName.equalsAsciiL( 1579 RTL_CONSTASCII_STRINGPARAM( "IsFolder" ) ) ) 1580 { 1581 // Read-only property! 1582 aRet[ n ] <<= lang::IllegalAccessException( 1583 rtl::OUString::createFromAscii( 1584 "Property is read-only!" ), 1585 static_cast< cppu::OWeakObject * >( this ) ); 1586 } 1587 else if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Title" ) ) ) 1588 { 1589 rtl::OUString aNewValue; 1590 if ( rValue.Value >>= aNewValue ) 1591 { 1592 // No empty titles! 1593 if ( aNewValue.getLength() > 0 ) 1594 { 1595 try 1596 { 1597 NeonUri aURI( xIdentifier->getContentIdentifier() ); 1598 aOldTitle = aURI.GetPathBaseNameUnescaped(); 1599 1600 if ( aNewValue != aOldTitle ) 1601 { 1602 // modified title -> modified URL -> exchange ! 1603 if ( !bTransient ) 1604 bExchange = sal_True; 1605 1606 // new value will be set later... 1607 aNewTitle = aNewValue; 1608 1609 // remember position within sequence of values (for 1610 // error handling). 1611 nTitlePos = n; 1612 } 1613 } 1614 catch ( DAVException const & ) 1615 { 1616 aRet[ n ] <<= lang::IllegalArgumentException( 1617 rtl::OUString::createFromAscii( 1618 "Invalid content identifier!" ), 1619 static_cast< cppu::OWeakObject * >( this ), 1620 -1 ); 1621 } 1622 } 1623 else 1624 { 1625 aRet[ n ] <<= lang::IllegalArgumentException( 1626 rtl::OUString::createFromAscii( 1627 "Empty title not allowed!" ), 1628 static_cast< cppu::OWeakObject * >( this ), 1629 -1 ); 1630 } 1631 } 1632 else 1633 { 1634 aRet[ n ] <<= beans::IllegalTypeException( 1635 rtl::OUString::createFromAscii( 1636 "Property value has wrong type!" ), 1637 static_cast< cppu::OWeakObject * >( this ) ); 1638 } 1639 } 1640 else 1641 { 1642 ////////////////////////////////////////////////////////////// 1643 // Optional props. 1644 ////////////////////////////////////////////////////////////// 1645 1646 if ( !xInfo.is() ) 1647 xInfo = getPropertySetInfo( xEnv, 1648 sal_False /* don't cache data */ ); 1649 1650 if ( !xInfo->hasPropertyByName( rName ) ) 1651 { 1652 // Check, whether property exists. Skip otherwise. 1653 // PROPPATCH::set would add the property automatically, which 1654 // is not allowed for "setPropertyValues" command! 1655 aRet[ n ] <<= beans::UnknownPropertyException( 1656 rtl::OUString::createFromAscii( 1657 "Property is unknown!" ), 1658 static_cast< cppu::OWeakObject * >( this ) ); 1659 continue; 1660 } 1661 1662 if ( rName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Size" ) ) ) 1663 { 1664 // Read-only property! 1665 aRet[ n ] <<= lang::IllegalAccessException( 1666 rtl::OUString::createFromAscii( 1667 "Property is read-only!" ), 1668 static_cast< cppu::OWeakObject * >( this ) ); 1669 } 1670 else if ( rName.equalsAsciiL( 1671 RTL_CONSTASCII_STRINGPARAM( "DateCreated" ) ) ) 1672 { 1673 // Read-only property! 1674 aRet[ n ] <<= lang::IllegalAccessException( 1675 rtl::OUString::createFromAscii( 1676 "Property is read-only!" ), 1677 static_cast< cppu::OWeakObject * >( this ) ); 1678 } 1679 else if ( rName.equalsAsciiL( 1680 RTL_CONSTASCII_STRINGPARAM( "DateModified" ) ) ) 1681 { 1682 // Read-only property! 1683 aRet[ n ] <<= lang::IllegalAccessException( 1684 rtl::OUString::createFromAscii( 1685 "Property is read-only!" ), 1686 static_cast< cppu::OWeakObject * >( this ) ); 1687 } 1688 else if ( rName.equalsAsciiL( 1689 RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) 1690 { 1691 // Read-only property! 1692 // (but could be writable, if 'getcontenttype' would be) 1693 aRet[ n ] <<= lang::IllegalAccessException( 1694 rtl::OUString::createFromAscii( 1695 "Property is read-only!" ), 1696 static_cast< cppu::OWeakObject * >( this ) ); 1697 } 1698 if ( rName.equalsAsciiL( 1699 RTL_CONSTASCII_STRINGPARAM( "CreatableContentsInfo" ) ) ) 1700 { 1701 // Read-only property! 1702 aRet[ n ] <<= lang::IllegalAccessException( 1703 rtl::OUString::createFromAscii( 1704 "Property is read-only!" ), 1705 static_cast< cppu::OWeakObject * >( this ) ); 1706 } 1707 else 1708 { 1709 if ( getResourceType( xEnv, xResAccess ) == DAV ) 1710 { 1711 // Property value will be set on server. 1712 ProppatchValue aValue( PROPSET, rName, rValue.Value ); 1713 aProppatchValues.push_back( aValue ); 1714 1715 // remember position within sequence of values (for 1716 // error handling). 1717 aProppatchPropsPositions.push_back( n ); 1718 } 1719 else 1720 { 1721 // Property value will be stored in local property store. 1722 if ( !bTriedToGetAdditonalPropSet && 1723 !xAdditionalPropSet.is() ) 1724 { 1725 xAdditionalPropSet 1726 = getAdditionalPropertySet( sal_False ); 1727 bTriedToGetAdditonalPropSet = sal_True; 1728 } 1729 1730 if ( xAdditionalPropSet.is() ) 1731 { 1732 try 1733 { 1734 uno::Any aOldValue 1735 = xAdditionalPropSet->getPropertyValue( rName ); 1736 if ( aOldValue != rValue.Value ) 1737 { 1738 xAdditionalPropSet->setPropertyValue( 1739 rName, rValue.Value ); 1740 1741 aEvent.PropertyName = rName; 1742 aEvent.OldValue = aOldValue; 1743 aEvent.NewValue = rValue.Value; 1744 1745 aChanges.getArray()[ nChanged ] = aEvent; 1746 nChanged++; 1747 } 1748 } 1749 catch ( beans::UnknownPropertyException const & e ) 1750 { 1751 aRet[ n ] <<= e; 1752 } 1753 catch ( lang::WrappedTargetException const & e ) 1754 { 1755 aRet[ n ] <<= e; 1756 } 1757 catch ( beans::PropertyVetoException const & e ) 1758 { 1759 aRet[ n ] <<= e; 1760 } 1761 catch ( lang::IllegalArgumentException const & e ) 1762 { 1763 aRet[ n ] <<= e; 1764 } 1765 } 1766 else 1767 { 1768 aRet[ n ] <<= uno::Exception( 1769 rtl::OUString::createFromAscii( 1770 "No property set for storing the value!" ), 1771 static_cast< cppu::OWeakObject * >( this ) ); 1772 } 1773 } 1774 } 1775 } 1776 } // for 1777 1778 if ( !bTransient && aProppatchValues.size() ) 1779 { 1780 try 1781 { 1782 // Set property values at server. 1783 xResAccess->PROPPATCH( aProppatchValues, xEnv ); 1784 1785 std::vector< ProppatchValue >::const_iterator it 1786 = aProppatchValues.begin(); 1787 std::vector< ProppatchValue >::const_iterator end 1788 = aProppatchValues.end(); 1789 1790 while ( it != end ) 1791 { 1792 aEvent.PropertyName = (*it).name; 1793 aEvent.OldValue = uno::Any(); // @@@ to expensive to obtain! 1794 aEvent.NewValue = (*it).value; 1795 1796 aChanges.getArray()[ nChanged ] = aEvent; 1797 nChanged++; 1798 1799 ++it; 1800 } 1801 } 1802 catch ( DAVException const & e ) 1803 { 1804 // OSL_ENSURE( sal_False, 1805 // "Content::setPropertyValues - PROPPATCH failed!" ); 1806 1807 #if 1 1808 cancelCommandExecution( e, xEnv ); 1809 // unreachable 1810 #else 1811 // Note: PROPPATCH either sets ALL property values OR NOTHING. 1812 1813 std::vector< sal_Int32 >::const_iterator it 1814 = aProppatchPropsPositions.begin(); 1815 std::vector< sal_Int32 >::const_iterator end 1816 = aProppatchPropsPositions.end(); 1817 1818 while ( it != end ) 1819 { 1820 // Set error. 1821 aRet[ (*it) ] <<= MapDAVException( e, sal_True ); 1822 ++it; 1823 } 1824 #endif 1825 } 1826 } 1827 1828 if ( bExchange ) 1829 { 1830 // Assemble new content identifier... 1831 1832 rtl::OUString aNewURL = getParentURL(); 1833 if ( aNewURL.lastIndexOf( '/' ) != ( aNewURL.getLength() - 1 ) ) 1834 aNewURL += rtl::OUString::createFromAscii( "/" ); 1835 1836 aNewURL += NeonUri::escapeSegment( aNewTitle ); 1837 1838 uno::Reference< ucb::XContentIdentifier > xNewId 1839 = new ::ucbhelper::ContentIdentifier( xSMgr, aNewURL ); 1840 uno::Reference< ucb::XContentIdentifier > xOldId = xIdentifier; 1841 1842 try 1843 { 1844 NeonUri sourceURI( xOldId->getContentIdentifier() ); 1845 NeonUri targetURI( xNewId->getContentIdentifier() ); 1846 targetURI.SetScheme( sourceURI.GetScheme() ); 1847 1848 xResAccess->MOVE( 1849 sourceURI.GetPath(), targetURI.GetURI(), sal_False, xEnv ); 1850 // @@@ Should check for resources that could not be moved 1851 // (due to source access or target overwrite) and send 1852 // this information through the interaction handler. 1853 1854 // @@@ Existing content should be checked to see if it needs 1855 // to be deleted at the source 1856 1857 // @@@ Existing content should be checked to see if it has 1858 // been overwritten at the target 1859 1860 if ( exchangeIdentity( xNewId ) ) 1861 { 1862 xResAccess->setURL( aNewURL ); 1863 1864 // DAV resources store all additional props on server! 1865 // // Adapt Additional Core Properties. 1866 // renameAdditionalPropertySet( xOldId->getContentIdentifier(), 1867 // xNewId->getContentIdentifier(), 1868 // sal_True ); 1869 } 1870 else 1871 { 1872 // Do not set new title! 1873 aNewTitle = rtl::OUString(); 1874 1875 // Set error . 1876 aRet[ nTitlePos ] <<= uno::Exception( 1877 rtl::OUString::createFromAscii( "Exchange failed!" ), 1878 static_cast< cppu::OWeakObject * >( this ) ); 1879 } 1880 } 1881 catch ( DAVException const & e ) 1882 { 1883 // Do not set new title! 1884 aNewTitle = rtl::OUString(); 1885 1886 // Set error . 1887 aRet[ nTitlePos ] <<= MapDAVException( e, sal_True ); 1888 } 1889 } 1890 1891 if ( aNewTitle.getLength() ) 1892 { 1893 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1894 1895 aEvent.PropertyName = rtl::OUString::createFromAscii( "Title" ); 1896 aEvent.OldValue = uno::makeAny( aOldTitle ); 1897 aEvent.NewValue = uno::makeAny( aNewTitle ); 1898 1899 m_aEscapedTitle = NeonUri::escapeSegment( aNewTitle ); 1900 1901 aChanges.getArray()[ nChanged ] = aEvent; 1902 nChanged++; 1903 } 1904 1905 if ( nChanged > 0 ) 1906 { 1907 aChanges.realloc( nChanged ); 1908 notifyPropertiesChange( aChanges ); 1909 } 1910 1911 { 1912 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 1913 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 1914 } 1915 1916 return aRet; 1917 } 1918 1919 //========================================================================= 1920 uno::Any Content::open( 1921 const ucb::OpenCommandArgument2 & rArg, 1922 const uno::Reference< ucb::XCommandEnvironment > & xEnv ) 1923 throw( uno::Exception ) 1924 { 1925 uno::Any aRet; 1926 1927 sal_Bool bOpenFolder = ( ( rArg.Mode == ucb::OpenMode::ALL ) || 1928 ( rArg.Mode == ucb::OpenMode::FOLDERS ) || 1929 ( rArg.Mode == ucb::OpenMode::DOCUMENTS ) ); 1930 if ( bOpenFolder ) 1931 { 1932 if ( isFolder( xEnv ) ) 1933 { 1934 // Open collection. 1935 1936 uno::Reference< ucb::XDynamicResultSet > xSet 1937 = new DynamicResultSet( m_xSMgr, this, rArg, xEnv ); 1938 aRet <<= xSet; 1939 } 1940 else 1941 { 1942 // Error: Not a folder! 1943 1944 rtl::OUStringBuffer aMsg; 1945 if ( getResourceType( xEnv ) == FTP ) 1946 { 1947 // #114653# 1948 aMsg.appendAscii( "FTP over HTTP proxy: resource cannot " 1949 "be opened as folder! Wrong Open Mode!" ); 1950 } 1951 else 1952 { 1953 aMsg.appendAscii( "Non-folder resource cannot be " 1954 "opened as folder! Wrong Open Mode!" ); 1955 } 1956 1957 ucbhelper::cancelCommandExecution( 1958 uno::makeAny( 1959 lang::IllegalArgumentException( 1960 aMsg.makeStringAndClear(), 1961 static_cast< cppu::OWeakObject * >( this ), 1962 -1 ) ), 1963 xEnv ); 1964 // Unreachable 1965 } 1966 } 1967 1968 if ( rArg.Sink.is() ) 1969 { 1970 // Open document. 1971 1972 if ( ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_NONE ) || 1973 ( rArg.Mode == ucb::OpenMode::DOCUMENT_SHARE_DENY_WRITE ) ) 1974 { 1975 // Currently(?) unsupported. 1976 ucbhelper::cancelCommandExecution( 1977 uno::makeAny( 1978 ucb::UnsupportedOpenModeException( 1979 rtl::OUString(), 1980 static_cast< cppu::OWeakObject * >( this ), 1981 sal_Int16( rArg.Mode ) ) ), 1982 xEnv ); 1983 // Unreachable 1984 } 1985 1986 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 1987 uno::Reference< io::XOutputStream > xOut 1988 = uno::Reference< io::XOutputStream >( rArg.Sink, uno::UNO_QUERY ); 1989 if ( xOut.is() ) 1990 { 1991 // PUSH: write data 1992 try 1993 { 1994 std::auto_ptr< DAVResourceAccess > xResAccess; 1995 1996 { 1997 osl::MutexGuard aGuard( m_aMutex ); 1998 1999 xResAccess.reset( 2000 new DAVResourceAccess( *m_xResAccess.get() ) ); 2001 } 2002 2003 DAVResource aResource; 2004 std::vector< rtl::OUString > aHeaders; 2005 2006 xResAccess->GET( xOut, aHeaders, aResource, xEnv ); 2007 m_bDidGetOrHead = true; 2008 2009 { 2010 osl::MutexGuard aGuard( m_aMutex ); 2011 2012 // cache headers. 2013 if ( !m_xCachedProps.get()) 2014 m_xCachedProps.reset( 2015 new CachableContentProperties( aResource ) ); 2016 else 2017 m_xCachedProps->addProperties( aResource ); 2018 2019 m_xResAccess.reset( 2020 new DAVResourceAccess( *xResAccess.get() ) ); 2021 } 2022 } 2023 catch ( DAVException const & e ) 2024 { 2025 cancelCommandExecution( e, xEnv ); 2026 // Unreachable 2027 } 2028 } 2029 else 2030 { 2031 uno::Reference< io::XActiveDataSink > xDataSink 2032 = uno::Reference< io::XActiveDataSink >( rArg.Sink, 2033 uno::UNO_QUERY ); 2034 if ( xDataSink.is() ) 2035 { 2036 // PULL: wait for client read 2037 try 2038 { 2039 std::auto_ptr< DAVResourceAccess > xResAccess; 2040 { 2041 osl::MutexGuard aGuard( m_aMutex ); 2042 2043 xResAccess.reset( 2044 new DAVResourceAccess( *m_xResAccess.get() ) ); 2045 } 2046 2047 // fill inputsream sync; return if all data present 2048 DAVResource aResource; 2049 std::vector< rtl::OUString > aHeaders; 2050 2051 uno::Reference< io::XInputStream > xIn 2052 = xResAccess->GET( aHeaders, aResource, xEnv ); 2053 m_bDidGetOrHead = true; 2054 2055 { 2056 osl::MutexGuard aGuard( m_aMutex ); 2057 2058 // cache headers. 2059 if ( !m_xCachedProps.get()) 2060 m_xCachedProps.reset( 2061 new CachableContentProperties( aResource ) ); 2062 else 2063 m_xCachedProps->addProperties( 2064 aResource.properties ); 2065 2066 m_xResAccess.reset( 2067 new DAVResourceAccess( *xResAccess.get() ) ); 2068 } 2069 2070 xDataSink->setInputStream( xIn ); 2071 } 2072 catch ( DAVException const & e ) 2073 { 2074 cancelCommandExecution( e, xEnv ); 2075 // Unreachable 2076 } 2077 } 2078 else 2079 { 2080 // Note: aOpenCommand.Sink may contain an XStream 2081 // implementation. Support for this type of 2082 // sink is optional... 2083 ucbhelper::cancelCommandExecution( 2084 uno::makeAny( 2085 ucb::UnsupportedDataSinkException( 2086 rtl::OUString(), 2087 static_cast< cppu::OWeakObject * >( this ), 2088 rArg.Sink ) ), 2089 xEnv ); 2090 // Unreachable 2091 } 2092 } 2093 } 2094 2095 return aRet; 2096 } 2097 2098 //========================================================================= 2099 void Content::post( 2100 const ucb::PostCommandArgument2 & rArg, 2101 const uno::Reference< ucb::XCommandEnvironment > & xEnv ) 2102 throw( uno::Exception ) 2103 { 2104 uno::Reference< io::XActiveDataSink > xSink( rArg.Sink, uno::UNO_QUERY ); 2105 if ( xSink.is() ) 2106 { 2107 try 2108 { 2109 std::auto_ptr< DAVResourceAccess > xResAccess; 2110 { 2111 osl::MutexGuard aGuard( m_aMutex ); 2112 xResAccess.reset( 2113 new DAVResourceAccess( *m_xResAccess.get() ) ); 2114 } 2115 2116 uno::Reference< io::XInputStream > xResult 2117 = xResAccess->POST( rArg.MediaType, 2118 rArg.Referer, 2119 rArg.Source, 2120 xEnv ); 2121 2122 { 2123 osl::MutexGuard aGuard( m_aMutex ); 2124 m_xResAccess.reset( 2125 new DAVResourceAccess( *xResAccess.get() ) ); 2126 } 2127 2128 xSink->setInputStream( xResult ); 2129 } 2130 catch ( DAVException const & e ) 2131 { 2132 cancelCommandExecution( e, xEnv, sal_True ); 2133 // Unreachable 2134 } 2135 } 2136 else 2137 { 2138 uno::Reference< io::XOutputStream > xResult( rArg.Sink, uno::UNO_QUERY ); 2139 if ( xResult.is() ) 2140 { 2141 try 2142 { 2143 std::auto_ptr< DAVResourceAccess > xResAccess; 2144 { 2145 osl::MutexGuard aGuard( m_aMutex ); 2146 xResAccess.reset( 2147 new DAVResourceAccess( *m_xResAccess.get() ) ); 2148 } 2149 2150 xResAccess->POST( rArg.MediaType, 2151 rArg.Referer, 2152 rArg.Source, 2153 xResult, 2154 xEnv ); 2155 2156 { 2157 osl::MutexGuard aGuard( m_aMutex ); 2158 m_xResAccess.reset( 2159 new DAVResourceAccess( *xResAccess.get() ) ); 2160 } 2161 } 2162 catch ( DAVException const & e ) 2163 { 2164 cancelCommandExecution( e, xEnv, sal_True ); 2165 // Unreachable 2166 } 2167 } 2168 else 2169 { 2170 ucbhelper::cancelCommandExecution( 2171 uno::makeAny( 2172 ucb::UnsupportedDataSinkException( 2173 rtl::OUString(), 2174 static_cast< cppu::OWeakObject * >( this ), 2175 rArg.Sink ) ), 2176 xEnv ); 2177 // Unreachable 2178 } 2179 } 2180 } 2181 2182 //========================================================================= 2183 void Content::queryChildren( ContentRefList& rChildren ) 2184 { 2185 // Obtain a list with a snapshot of all currently instanciated contents 2186 // from provider and extract the contents which are direct children 2187 // of this content. 2188 2189 ::ucbhelper::ContentRefList aAllContents; 2190 m_xProvider->queryExistingContents( aAllContents ); 2191 2192 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 2193 sal_Int32 nURLPos = aURL.lastIndexOf( '/' ); 2194 2195 if ( nURLPos != ( aURL.getLength() - 1 ) ) 2196 { 2197 // No trailing slash found. Append. 2198 aURL += rtl::OUString::createFromAscii( "/" ); 2199 } 2200 2201 sal_Int32 nLen = aURL.getLength(); 2202 2203 ::ucbhelper::ContentRefList::const_iterator it = aAllContents.begin(); 2204 ::ucbhelper::ContentRefList::const_iterator end = aAllContents.end(); 2205 2206 while ( it != end ) 2207 { 2208 ::ucbhelper::ContentImplHelperRef xChild = (*it); 2209 rtl::OUString aChildURL 2210 = xChild->getIdentifier()->getContentIdentifier(); 2211 2212 // Is aURL a prefix of aChildURL? 2213 if ( ( aChildURL.getLength() > nLen ) && 2214 ( aChildURL.compareTo( aURL, nLen ) == 0 ) ) 2215 { 2216 sal_Int32 nPos = nLen; 2217 nPos = aChildURL.indexOf( '/', nPos ); 2218 2219 if ( ( nPos == -1 ) || 2220 ( nPos == ( aChildURL.getLength() - 1 ) ) ) 2221 { 2222 // No further slashes / only a final slash. It's a child! 2223 rChildren.push_back( 2224 ::webdav_ucp::Content::ContentRef( 2225 static_cast< ::webdav_ucp::Content * >( 2226 xChild.get() ) ) ); 2227 } 2228 } 2229 ++it; 2230 } 2231 } 2232 2233 //========================================================================= 2234 void Content::insert( 2235 const uno::Reference< io::XInputStream > & xInputStream, 2236 sal_Bool bReplaceExisting, 2237 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 2238 throw( uno::Exception ) 2239 { 2240 sal_Bool bTransient, bCollection; 2241 rtl::OUString aEscapedTitle; 2242 std::auto_ptr< DAVResourceAccess > xResAccess; 2243 2244 { 2245 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2246 2247 bTransient = m_bTransient; 2248 bCollection = m_bCollection; 2249 aEscapedTitle = m_aEscapedTitle; 2250 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 2251 } 2252 2253 // Check, if all required properties are present. 2254 2255 if ( aEscapedTitle.getLength() == 0 ) 2256 { 2257 OSL_ENSURE( sal_False, "Content::insert - Title missing!" ); 2258 2259 uno::Sequence< rtl::OUString > aProps( 1 ); 2260 aProps[ 0 ] = rtl::OUString::createFromAscii( "Title" ); 2261 ucbhelper::cancelCommandExecution( 2262 uno::makeAny( ucb::MissingPropertiesException( 2263 rtl::OUString(), 2264 static_cast< cppu::OWeakObject * >( this ), 2265 aProps ) ), 2266 Environment ); 2267 // Unreachable 2268 } 2269 2270 if ( !bReplaceExisting ) 2271 { 2272 /* [RFC 2616] - HTTP 2273 2274 The PUT method requests that the enclosed entity be stored under the 2275 supplied Request-URI. If the Request-URI refers to an already 2276 existing resource, the enclosed entity SHOULD be considered as a 2277 modified version of the one residing on the origin server. 2278 */ 2279 2280 /* [RFC 2518] - WebDAV 2281 2282 MKCOL creates a new collection resource at the location specified by 2283 the Request-URI. If the resource identified by the Request-URI is 2284 non-null then the MKCOL MUST fail. 2285 */ 2286 2287 // ==> Complain on PUT, continue on MKCOL. 2288 if ( !bTransient || ( bTransient && !bCollection ) ) 2289 { 2290 ucb::UnsupportedNameClashException aEx( 2291 rtl::OUString::createFromAscii( 2292 "Unable to write without overwrite!" ), 2293 static_cast< cppu::OWeakObject * >( this ), 2294 ucb::NameClash::ERROR ); 2295 2296 uno::Reference< task::XInteractionHandler > xIH; 2297 2298 if ( Environment.is() ) 2299 xIH = Environment->getInteractionHandler(); 2300 2301 if ( xIH.is() ) 2302 { 2303 uno::Any aExAsAny( uno::makeAny( aEx ) ); 2304 2305 rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest 2306 = new ucbhelper::SimpleInteractionRequest( 2307 aExAsAny, 2308 ucbhelper::CONTINUATION_APPROVE 2309 | ucbhelper::CONTINUATION_DISAPPROVE ); 2310 xIH->handle( xRequest.get() ); 2311 2312 const sal_Int32 nResp = xRequest->getResponse(); 2313 2314 switch ( nResp ) 2315 { 2316 case ucbhelper::CONTINUATION_UNKNOWN: 2317 // Not handled; throw. 2318 throw aEx; 2319 // break; 2320 2321 case ucbhelper::CONTINUATION_APPROVE: 2322 // Continue -> Overwrite. 2323 bReplaceExisting = sal_True; 2324 break; 2325 2326 case ucbhelper::CONTINUATION_DISAPPROVE: 2327 // Abort. 2328 throw ucb::CommandFailedException( 2329 rtl::OUString(), 2330 uno::Reference< uno::XInterface >(), 2331 aExAsAny ); 2332 // break; 2333 2334 default: 2335 OSL_ENSURE( sal_False, 2336 "Content::insert - " 2337 "Unknown interaction selection!" ); 2338 throw ucb::CommandFailedException( 2339 rtl::OUString::createFromAscii( 2340 "Unknown interaction selection!" ), 2341 uno::Reference< uno::XInterface >(), 2342 aExAsAny ); 2343 // break; 2344 } 2345 } 2346 else 2347 { 2348 // No IH; throw. 2349 throw aEx; 2350 } 2351 } 2352 } 2353 2354 if ( bTransient ) 2355 { 2356 // Assemble new content identifier... 2357 rtl::OUString aURL = getParentURL(); 2358 if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) ) 2359 aURL += rtl::OUString::createFromAscii( "/" ); 2360 2361 aURL += aEscapedTitle; 2362 2363 try 2364 { 2365 xResAccess->setURL( aURL ); 2366 2367 if ( bCollection ) 2368 xResAccess->MKCOL( Environment ); 2369 else 2370 xResAccess->PUT( xInputStream, Environment ); 2371 } 2372 catch ( DAVException const & except ) 2373 { 2374 if ( bCollection ) 2375 { 2376 if ( except.getStatus() == SC_METHOD_NOT_ALLOWED ) 2377 { 2378 // [RFC 2518] - WebDAV 2379 // 405 (Method Not Allowed) - MKCOL can only be 2380 // executed on a deleted/non-existent resource. 2381 2382 if ( bReplaceExisting ) 2383 { 2384 // Destroy old resource. 2385 try 2386 { 2387 xResAccess->DESTROY( Environment ); 2388 } 2389 catch ( DAVException const & e ) 2390 { 2391 cancelCommandExecution( e, Environment, sal_True ); 2392 // Unreachable 2393 } 2394 2395 // Insert (recursion!). 2396 insert( xInputStream, bReplaceExisting, Environment ); 2397 2398 { 2399 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2400 m_xResAccess.reset( 2401 new DAVResourceAccess( *xResAccess.get() ) ); 2402 } 2403 2404 // Success! 2405 return; 2406 } 2407 else 2408 { 2409 rtl::OUString aTitle; 2410 try 2411 { 2412 NeonUri aURI( aURL ); 2413 aTitle = aURI.GetPathBaseNameUnescaped(); 2414 } 2415 catch ( DAVException const & ) 2416 { 2417 } 2418 2419 ucbhelper::cancelCommandExecution( 2420 uno::makeAny( 2421 ucb::NameClashException( 2422 rtl::OUString(), 2423 static_cast< cppu::OWeakObject * >( this ), 2424 task::InteractionClassification_ERROR, 2425 aTitle ) ), 2426 Environment ); 2427 // Unreachable 2428 } 2429 } 2430 } 2431 2432 cancelCommandExecution( except, Environment, sal_True ); 2433 // Unreachable 2434 } 2435 2436 { 2437 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2438 m_xIdentifier 2439 = new ::ucbhelper::ContentIdentifier( m_xSMgr, aURL ); 2440 } 2441 2442 inserted(); 2443 2444 { 2445 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2446 m_bTransient = sal_False; 2447 } 2448 } 2449 else 2450 { 2451 if ( !xInputStream.is() ) 2452 { 2453 ucbhelper::cancelCommandExecution( 2454 uno::makeAny( 2455 ucb::MissingInputStreamException( 2456 rtl::OUString(), 2457 static_cast< cppu::OWeakObject * >( this ) ) ), 2458 Environment ); 2459 // Unreachable 2460 } 2461 2462 try 2463 { 2464 xResAccess->PUT( xInputStream, Environment ); 2465 } 2466 catch ( DAVException const & e ) 2467 { 2468 cancelCommandExecution( e, Environment, sal_True ); 2469 // Unreachable 2470 } 2471 } 2472 2473 { 2474 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2475 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 2476 } 2477 } 2478 2479 //========================================================================= 2480 void Content::transfer( 2481 const ucb::TransferInfo & rArgs, 2482 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 2483 throw( uno::Exception ) 2484 { 2485 uno::Reference< lang::XMultiServiceFactory > xSMgr; 2486 uno::Reference< ucb::XContentIdentifier > xIdentifier; 2487 uno::Reference< ucb::XContentProvider > xProvider; 2488 std::auto_ptr< DAVResourceAccess > xResAccess; 2489 2490 { 2491 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2492 2493 xSMgr.set( m_xSMgr ); 2494 xIdentifier.set( m_xIdentifier ); 2495 xProvider.set( m_xProvider.get() ); 2496 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 2497 } 2498 2499 rtl::OUString aTargetURI; 2500 try 2501 { 2502 NeonUri sourceURI( rArgs.SourceURL ); 2503 NeonUri targetURI( xIdentifier->getContentIdentifier() ); 2504 aTargetURI = targetURI.GetPathBaseNameUnescaped(); 2505 2506 // Check source's and target's URL scheme 2507 // 2508 const rtl::OUString aScheme = sourceURI.GetScheme().toAsciiLowerCase(); 2509 if ( aScheme.equalsAsciiL( 2510 RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) ) 2511 { 2512 sourceURI.SetScheme( 2513 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); 2514 } 2515 else if ( aScheme.equalsAsciiL( 2516 RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) ) 2517 { 2518 sourceURI.SetScheme( 2519 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); 2520 } 2521 else if ( aScheme.equalsAsciiL( 2522 RTL_CONSTASCII_STRINGPARAM( DAVS_URL_SCHEME ) ) ) 2523 { 2524 sourceURI.SetScheme( 2525 rtl::OUString::createFromAscii( HTTPS_URL_SCHEME ) ); 2526 } 2527 else 2528 { 2529 if ( !aScheme.equalsAsciiL( 2530 RTL_CONSTASCII_STRINGPARAM( HTTP_URL_SCHEME ) ) && 2531 !aScheme.equalsAsciiL( 2532 RTL_CONSTASCII_STRINGPARAM( HTTPS_URL_SCHEME ) ) ) 2533 { 2534 ucbhelper::cancelCommandExecution( 2535 uno::makeAny( 2536 ucb::InteractiveBadTransferURLException( 2537 rtl::OUString::createFromAscii( 2538 "Unsupported URL scheme!" ), 2539 static_cast< cppu::OWeakObject * >( this ) ) ), 2540 Environment ); 2541 // Unreachable 2542 } 2543 } 2544 2545 if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL( 2546 RTL_CONSTASCII_STRINGPARAM( WEBDAV_URL_SCHEME ) ) ) 2547 targetURI.SetScheme( 2548 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); 2549 else if ( targetURI.GetScheme().toAsciiLowerCase().equalsAsciiL( 2550 RTL_CONSTASCII_STRINGPARAM( DAV_URL_SCHEME ) ) ) 2551 targetURI.SetScheme( 2552 rtl::OUString::createFromAscii( HTTP_URL_SCHEME ) ); 2553 2554 // @@@ This implementation of 'transfer' only works 2555 // if the source and target are located at same host. 2556 // (Neon does not support cross-server copy/move) 2557 2558 // Check for same host 2559 // 2560 if ( sourceURI.GetHost().getLength() && 2561 ( sourceURI.GetHost() != targetURI.GetHost() ) ) 2562 { 2563 ucbhelper::cancelCommandExecution( 2564 uno::makeAny( ucb::InteractiveBadTransferURLException( 2565 rtl::OUString::createFromAscii( 2566 "Different hosts!" ), 2567 static_cast< cppu::OWeakObject * >( this ) ) ), 2568 Environment ); 2569 // Unreachable 2570 } 2571 2572 rtl::OUString aTitle = rArgs.NewTitle; 2573 2574 if ( !aTitle.getLength() ) 2575 aTitle = sourceURI.GetPathBaseNameUnescaped(); 2576 2577 if ( aTitle.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "/" ) ) ) 2578 { 2579 // kso: ??? 2580 aTitle = rtl::OUString(); 2581 } 2582 2583 targetURI.AppendPath( aTitle ); 2584 2585 rtl::OUString aTargetURL = xIdentifier->getContentIdentifier(); 2586 if ( ( aTargetURL.lastIndexOf( '/' ) + 1 ) 2587 != aTargetURL.getLength() ) 2588 aTargetURL += rtl::OUString::createFromAscii( "/" ); 2589 2590 aTargetURL += aTitle; 2591 2592 uno::Reference< ucb::XContentIdentifier > xTargetId 2593 = new ::ucbhelper::ContentIdentifier( xSMgr, aTargetURL ); 2594 2595 DAVResourceAccess aSourceAccess( xSMgr, 2596 xResAccess->getSessionFactory(), 2597 sourceURI.GetURI() ); 2598 2599 if ( rArgs.MoveData == sal_True ) 2600 { 2601 uno::Reference< ucb::XContentIdentifier > xId 2602 = new ::ucbhelper::ContentIdentifier( xSMgr, rArgs.SourceURL ); 2603 2604 // Note: The static cast is okay here, because its sure that 2605 // xProvider is always the WebDAVContentProvider. 2606 rtl::Reference< Content > xSource 2607 = static_cast< Content * >( 2608 xProvider->queryContent( xId ).get() ); 2609 2610 // [RFC 2518] - WebDAV 2611 // If a resource exists at the destination and the Overwrite 2612 // header is "T" then prior to performing the move the server 2613 // MUST perform a DELETE with "Depth: infinity" on the 2614 // destination resource. If the Overwrite header is set to 2615 // "F" then the operation will fail. 2616 2617 aSourceAccess.MOVE( sourceURI.GetPath(), 2618 targetURI.GetURI(), 2619 rArgs.NameClash 2620 == ucb::NameClash::OVERWRITE, 2621 Environment ); 2622 2623 if ( xSource.is() ) 2624 { 2625 // Propagate destruction to listeners. 2626 xSource->destroy( sal_True ); 2627 } 2628 2629 // DAV resources store all additional props on server! 2630 // // Rename own and all children's Additional Core Properties. 2631 // renameAdditionalPropertySet( xId->getContentIdentifier(), 2632 // xTargetId->getContentIdentifier(), 2633 // sal_True ); 2634 } 2635 else 2636 { 2637 // [RFC 2518] - WebDAV 2638 // If a resource exists at the destination and the Overwrite 2639 // header is "T" then prior to performing the copy the server 2640 // MUST perform a DELETE with "Depth: infinity" on the 2641 // destination resource. If the Overwrite header is set to 2642 // "F" then the operation will fail. 2643 2644 aSourceAccess.COPY( sourceURI.GetPath(), 2645 targetURI.GetURI(), 2646 rArgs.NameClash 2647 == ucb::NameClash::OVERWRITE, 2648 Environment ); 2649 2650 // DAV resources store all additional props on server! 2651 // // Copy own and all children's Additional Core Properties. 2652 // copyAdditionalPropertySet( xId->getContentIdentifier(), 2653 // xTargetId->getContentIdentifier(), 2654 // sal_True ); 2655 } 2656 2657 // Note: The static cast is okay here, because its sure that 2658 // xProvider is always the WebDAVContentProvider. 2659 rtl::Reference< Content > xTarget 2660 = static_cast< Content * >( 2661 xProvider->queryContent( xTargetId ).get() ); 2662 2663 // Announce transfered content in its new folder. 2664 xTarget->inserted(); 2665 } 2666 catch ( ucb::IllegalIdentifierException const & ) 2667 { 2668 // queryContent 2669 } 2670 catch ( DAVException const & e ) 2671 { 2672 // [RFC 2518] - WebDAV 2673 // 412 (Precondition Failed) - The server was unable to maintain 2674 // the liveness of the properties listed in the propertybehavior 2675 // XML element or the Overwrite header is "F" and the state of 2676 // the destination resource is non-null. 2677 2678 if ( e.getStatus() == SC_PRECONDITION_FAILED ) 2679 { 2680 switch ( rArgs.NameClash ) 2681 { 2682 case ucb::NameClash::ERROR: 2683 { 2684 ucbhelper::cancelCommandExecution( 2685 uno::makeAny( 2686 ucb::NameClashException( 2687 rtl::OUString(), 2688 static_cast< cppu::OWeakObject * >( this ), 2689 task::InteractionClassification_ERROR, 2690 aTargetURI ) ), 2691 Environment ); 2692 // Unreachable 2693 } 2694 2695 case ucb::NameClash::OVERWRITE: 2696 break; 2697 2698 case ucb::NameClash::KEEP: // deprecated 2699 case ucb::NameClash::RENAME: 2700 case ucb::NameClash::ASK: 2701 default: 2702 { 2703 ucbhelper::cancelCommandExecution( 2704 uno::makeAny( 2705 ucb::UnsupportedNameClashException( 2706 rtl::OUString(), 2707 static_cast< cppu::OWeakObject * >( this ), 2708 rArgs.NameClash ) ), 2709 Environment ); 2710 // Unreachable 2711 } 2712 } 2713 } 2714 2715 cancelCommandExecution( e, Environment, sal_True ); 2716 // Unreachable 2717 } 2718 2719 { 2720 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2721 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 2722 } 2723 } 2724 2725 //========================================================================= 2726 void Content::destroy( sal_Bool bDeletePhysical ) 2727 throw( uno::Exception ) 2728 { 2729 // @@@ take care about bDeletePhysical -> trashcan support 2730 rtl::OUString aURL = m_xIdentifier->getContentIdentifier(); 2731 2732 uno::Reference< ucb::XContent > xThis = this; 2733 2734 deleted(); 2735 2736 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2737 2738 // Process instanciated children... 2739 2740 ::webdav_ucp::Content::ContentRefList aChildren; 2741 queryChildren( aChildren ); 2742 2743 ContentRefList::const_iterator it = aChildren.begin(); 2744 ContentRefList::const_iterator end = aChildren.end(); 2745 2746 while ( it != end ) 2747 { 2748 (*it)->destroy( bDeletePhysical ); 2749 ++it; 2750 } 2751 } 2752 2753 //========================================================================= 2754 bool Content::supportsExclusiveWriteLock( 2755 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 2756 { 2757 if ( getResourceType( Environment ) == DAV ) 2758 { 2759 if ( m_xCachedProps.get() ) 2760 { 2761 uno::Sequence< ucb::LockEntry > aSupportedLocks; 2762 if ( m_xCachedProps->getValue( DAVProperties::SUPPORTEDLOCK ) 2763 >>= aSupportedLocks ) 2764 { 2765 for ( sal_Int32 n = 0; n < aSupportedLocks.getLength(); ++n ) 2766 { 2767 if ( aSupportedLocks[ n ].Scope 2768 == ucb::LockScope_EXCLUSIVE && 2769 aSupportedLocks[ n ].Type 2770 == ucb::LockType_WRITE ) 2771 return true; 2772 } 2773 } 2774 } 2775 } 2776 return false; 2777 } 2778 2779 //========================================================================= 2780 void Content::lock( 2781 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 2782 throw( uno::Exception ) 2783 { 2784 try 2785 { 2786 std::auto_ptr< DAVResourceAccess > xResAccess; 2787 { 2788 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2789 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 2790 } 2791 2792 uno::Any aOwnerAny; 2793 aOwnerAny 2794 <<= rtl::OUString::createFromAscii( "http://ucb.openoffice.org" ); 2795 2796 ucb::Lock aLock( 2797 ucb::LockScope_EXCLUSIVE, 2798 ucb::LockType_WRITE, 2799 ucb::LockDepth_ZERO, 2800 aOwnerAny, 2801 180, // lock timeout in secs 2802 //-1, // infinite lock 2803 uno::Sequence< ::rtl::OUString >() ); 2804 2805 xResAccess->LOCK( aLock, Environment ); 2806 2807 { 2808 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2809 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 2810 } 2811 } 2812 catch ( DAVException const & e ) 2813 { 2814 cancelCommandExecution( e, Environment, sal_False ); 2815 // Unreachable 2816 } 2817 } 2818 2819 //========================================================================= 2820 void Content::unlock( 2821 const uno::Reference< ucb::XCommandEnvironment >& Environment ) 2822 throw( uno::Exception ) 2823 { 2824 try 2825 { 2826 std::auto_ptr< DAVResourceAccess > xResAccess; 2827 { 2828 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2829 xResAccess.reset( new DAVResourceAccess( *m_xResAccess.get() ) ); 2830 } 2831 2832 xResAccess->UNLOCK( Environment ); 2833 2834 { 2835 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 2836 m_xResAccess.reset( new DAVResourceAccess( *xResAccess.get() ) ); 2837 } 2838 } 2839 catch ( DAVException const & e ) 2840 { 2841 cancelCommandExecution( e, Environment, sal_False ); 2842 // Unreachable 2843 } 2844 } 2845 2846 //========================================================================= 2847 sal_Bool Content::exchangeIdentity( 2848 const uno::Reference< ucb::XContentIdentifier >& xNewId ) 2849 { 2850 if ( !xNewId.is() ) 2851 return sal_False; 2852 2853 osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); 2854 2855 uno::Reference< ucb::XContent > xThis = this; 2856 2857 // Already persistent? 2858 if ( m_bTransient ) 2859 { 2860 OSL_ENSURE( sal_False, "Content::exchangeIdentity - Not persistent!" ); 2861 return sal_False; 2862 } 2863 2864 // Exchange own identitity. 2865 2866 // Fail, if a content with given id already exists. 2867 // if ( !hasData( xNewId ) ) 2868 { 2869 rtl::OUString aOldURL = m_xIdentifier->getContentIdentifier(); 2870 2871 aGuard.clear(); 2872 if ( exchange( xNewId ) ) 2873 { 2874 // Process instanciated children... 2875 2876 ContentRefList aChildren; 2877 queryChildren( aChildren ); 2878 2879 ContentRefList::const_iterator it = aChildren.begin(); 2880 ContentRefList::const_iterator end = aChildren.end(); 2881 2882 while ( it != end ) 2883 { 2884 ContentRef xChild = (*it); 2885 2886 // Create new content identifier for the child... 2887 uno::Reference< ucb::XContentIdentifier > 2888 xOldChildId = xChild->getIdentifier(); 2889 rtl::OUString aOldChildURL 2890 = xOldChildId->getContentIdentifier(); 2891 rtl::OUString aNewChildURL 2892 = aOldChildURL.replaceAt( 2893 0, 2894 aOldURL.getLength(), 2895 xNewId->getContentIdentifier() ); 2896 uno::Reference< ucb::XContentIdentifier > xNewChildId 2897 = new ::ucbhelper::ContentIdentifier( 2898 m_xSMgr, aNewChildURL ); 2899 2900 if ( !xChild->exchangeIdentity( xNewChildId ) ) 2901 return sal_False; 2902 2903 ++it; 2904 } 2905 return sal_True; 2906 } 2907 } 2908 2909 OSL_ENSURE( sal_False, 2910 "Content::exchangeIdentity - " 2911 "Panic! Cannot exchange identity!" ); 2912 return sal_False; 2913 } 2914 2915 //========================================================================= 2916 sal_Bool Content::isFolder( 2917 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 2918 throw( uno::Exception ) 2919 { 2920 { 2921 osl::MutexGuard aGuard( m_aMutex ); 2922 2923 if ( m_bTransient ) 2924 return m_bCollection; 2925 } 2926 2927 uno::Sequence< beans::Property > aProperties( 1 ); 2928 aProperties[ 0 ].Name = rtl::OUString::createFromAscii( "IsFolder" ); 2929 aProperties[ 0 ].Handle = -1; 2930 uno::Reference< sdbc::XRow > xRow( getPropertyValues( aProperties, xEnv ) ); 2931 if ( xRow.is() ) 2932 { 2933 try 2934 { 2935 return xRow->getBoolean( 1 ); 2936 } 2937 catch ( sdbc::SQLException const & ) 2938 { 2939 } 2940 } 2941 2942 return sal_False; 2943 } 2944 2945 //========================================================================= 2946 uno::Any Content::MapDAVException( const DAVException & e, sal_Bool bWrite ) 2947 { 2948 // Map DAVException... 2949 uno::Any aException; 2950 2951 rtl::OUString aURL; 2952 if ( m_bTransient ) 2953 { 2954 aURL = getParentURL(); 2955 if ( aURL.lastIndexOf( '/' ) != ( aURL.getLength() - 1 ) ) 2956 aURL += rtl::OUString::createFromAscii( "/" ); 2957 2958 aURL += m_aEscapedTitle; 2959 } 2960 else 2961 { 2962 aURL = m_xIdentifier->getContentIdentifier(); 2963 } 2964 2965 switch ( e.getStatus() ) 2966 { 2967 case SC_NOT_FOUND: 2968 { 2969 uno::Sequence< uno::Any > aArgs( 1 ); 2970 aArgs[ 0 ] <<= beans::PropertyValue( 2971 rtl::OUString::createFromAscii("Uri"), -1, 2972 uno::makeAny(aURL), 2973 beans::PropertyState_DIRECT_VALUE); 2974 2975 aException <<= 2976 ucb::InteractiveAugmentedIOException( 2977 rtl::OUString::createFromAscii( "Not found!" ), 2978 static_cast< cppu::OWeakObject * >( this ), 2979 task::InteractionClassification_ERROR, 2980 ucb::IOErrorCode_NOT_EXISTING, 2981 aArgs ); 2982 return aException; 2983 } 2984 default: 2985 break; 2986 } 2987 2988 switch ( e.getError() ) 2989 { 2990 case DAVException::DAV_HTTP_ERROR: 2991 { 2992 if ( bWrite ) 2993 aException <<= 2994 ucb::InteractiveNetworkWriteException( 2995 e.getData(), 2996 static_cast< cppu::OWeakObject * >( this ), 2997 task::InteractionClassification_ERROR, 2998 e.getData() ); 2999 else 3000 aException <<= 3001 ucb::InteractiveNetworkReadException( 3002 e.getData(), 3003 static_cast< cppu::OWeakObject * >( this ), 3004 task::InteractionClassification_ERROR, 3005 e.getData() ); 3006 break; 3007 } 3008 3009 case DAVException::DAV_HTTP_LOOKUP: 3010 aException <<= 3011 ucb::InteractiveNetworkResolveNameException( 3012 rtl::OUString(), 3013 static_cast< cppu::OWeakObject * >( this ), 3014 task::InteractionClassification_ERROR, 3015 e.getData() ); 3016 break; 3017 3018 // @@@ No matching InteractiveNetwork*Exception 3019 // case DAVException::DAV_HTTP_AUTH: 3020 // break; 3021 3022 // @@@ No matching InteractiveNetwork*Exception 3023 // case DAVException::DAV_HTTP_AUTHPROXY: 3024 // break; 3025 3026 case DAVException::DAV_HTTP_CONNECT: 3027 aException <<= 3028 ucb::InteractiveNetworkConnectException( 3029 rtl::OUString(), 3030 static_cast< cppu::OWeakObject * >( this ), 3031 task::InteractionClassification_ERROR, 3032 e.getData() ); 3033 break; 3034 3035 // @@@ No matching InteractiveNetwork*Exception 3036 // case DAVException::DAV_HTTP_TIMEOUT: 3037 // break; 3038 3039 // @@@ No matching InteractiveNetwork*Exception 3040 // case DAVException::DAV_HTTP_REDIRECT: 3041 // break; 3042 3043 // @@@ No matching InteractiveNetwork*Exception 3044 // case DAVException::DAV_SESSION_CREATE: 3045 // break; 3046 3047 case DAVException::DAV_INVALID_ARG: 3048 aException <<= 3049 lang::IllegalArgumentException( 3050 rtl::OUString(), 3051 static_cast< cppu::OWeakObject * >( this ), 3052 -1 ); 3053 break; 3054 3055 case DAVException::DAV_LOCKED: 3056 #if 1 3057 aException <<= 3058 ucb::InteractiveLockingLockedException( 3059 rtl::OUString::createFromAscii( "Locked!" ), 3060 static_cast< cppu::OWeakObject * >( this ), 3061 task::InteractionClassification_ERROR, 3062 aURL, 3063 sal_False ); // not SelfOwned 3064 #else 3065 { 3066 uno::Sequence< uno::Any > aArgs( 1 ); 3067 aArgs[ 0 ] <<= beans::PropertyValue( 3068 rtl::OUString::createFromAscii("Uri"), -1, 3069 uno::makeAny(aURL), 3070 beans::PropertyState_DIRECT_VALUE); 3071 3072 aException <<= 3073 ucb::InteractiveAugmentedIOException( 3074 rtl::OUString::createFromAscii( "Locked!" ), 3075 static_cast< cppu::OWeakObject * >( this ), 3076 task::InteractionClassification_ERROR, 3077 ucb::IOErrorCode_LOCKING_VIOLATION, 3078 aArgs ); 3079 } 3080 #endif 3081 break; 3082 3083 case DAVException::DAV_LOCKED_SELF: 3084 aException <<= 3085 ucb::InteractiveLockingLockedException( 3086 rtl::OUString::createFromAscii( "Locked (self)!" ), 3087 static_cast< cppu::OWeakObject * >( this ), 3088 task::InteractionClassification_ERROR, 3089 aURL, 3090 sal_True ); // SelfOwned 3091 break; 3092 3093 case DAVException::DAV_NOT_LOCKED: 3094 aException <<= 3095 ucb::InteractiveLockingNotLockedException( 3096 rtl::OUString::createFromAscii( "Not locked!" ), 3097 static_cast< cppu::OWeakObject * >( this ), 3098 task::InteractionClassification_ERROR, 3099 aURL ); 3100 break; 3101 3102 case DAVException::DAV_LOCK_EXPIRED: 3103 aException <<= 3104 ucb::InteractiveLockingLockExpiredException( 3105 rtl::OUString::createFromAscii( "Lock expired!" ), 3106 static_cast< cppu::OWeakObject * >( this ), 3107 task::InteractionClassification_ERROR, 3108 aURL ); 3109 break; 3110 3111 default: 3112 aException <<= 3113 ucb::InteractiveNetworkGeneralException( 3114 rtl::OUString(), 3115 static_cast< cppu::OWeakObject * >( this ), 3116 task::InteractionClassification_ERROR ); 3117 break; 3118 } 3119 3120 return aException; 3121 } 3122 3123 //========================================================================= 3124 // static 3125 bool Content::shouldAccessNetworkAfterException( const DAVException & e ) 3126 { 3127 if ( ( e.getStatus() == SC_NOT_FOUND ) || 3128 ( e.getError() == DAVException::DAV_HTTP_LOOKUP ) || 3129 ( e.getError() == DAVException::DAV_HTTP_CONNECT ) || 3130 ( e.getError() == DAVException::DAV_HTTP_AUTH ) || 3131 ( e.getError() == DAVException::DAV_HTTP_AUTHPROXY ) ) 3132 return false; 3133 3134 return true; 3135 } 3136 3137 //========================================================================= 3138 void Content::cancelCommandExecution( 3139 const DAVException & e, 3140 const uno::Reference< ucb::XCommandEnvironment > & xEnv, 3141 sal_Bool bWrite /* = sal_False */ ) 3142 throw ( uno::Exception ) 3143 { 3144 ucbhelper::cancelCommandExecution( MapDAVException( e, bWrite ), xEnv ); 3145 // Unreachable 3146 } 3147 3148 //========================================================================= 3149 const rtl::OUString 3150 Content::getBaseURI( const std::auto_ptr< DAVResourceAccess > & rResAccess ) 3151 { 3152 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 3153 3154 // First, try to obtain value of response header "Content-Location". 3155 if ( m_xCachedProps.get() ) 3156 { 3157 rtl::OUString aLocation; 3158 m_xCachedProps->getValue( rtl::OUString( 3159 RTL_CONSTASCII_USTRINGPARAM( 3160 "Content-Location" ) ) ) >>= aLocation; 3161 if ( aLocation.getLength() ) 3162 { 3163 try 3164 { 3165 // Do not use m_xIdentifier->getContentIdentifier() because it 3166 // for example does not reflect redirects applied to requests 3167 // done using the original URI but m_xResAccess' URI does. 3168 return rtl::Uri::convertRelToAbs( rResAccess->getURL(), 3169 aLocation ); 3170 } 3171 catch ( rtl::MalformedUriException const & ) 3172 { 3173 } 3174 } 3175 } 3176 3177 return rtl::OUString( rResAccess->getURL() ); 3178 } 3179 3180 //========================================================================= 3181 const Content::ResourceType & Content::getResourceType( 3182 const uno::Reference< ucb::XCommandEnvironment >& xEnv, 3183 const std::auto_ptr< DAVResourceAccess > & rResAccess ) 3184 throw ( uno::Exception ) 3185 { 3186 if ( m_eResourceType == UNKNOWN ) 3187 { 3188 osl::Guard< osl::Mutex > aGuard( m_aMutex ); 3189 3190 ResourceType eResourceType; 3191 eResourceType = m_eResourceType; 3192 3193 const rtl::OUString & rURL = rResAccess->getURL(); 3194 const rtl::OUString aScheme( 3195 rURL.copy( 0, rURL.indexOf( ':' ) ).toAsciiLowerCase() ); 3196 3197 if ( aScheme.equalsAsciiL( 3198 RTL_CONSTASCII_STRINGPARAM( FTP_URL_SCHEME ) ) ) 3199 { 3200 eResourceType = FTP; 3201 } 3202 else 3203 { 3204 try 3205 { 3206 // Try to fetch some frequently used property value, e.g. those 3207 // used when loading documents... along with identifying whether 3208 // this is a DAV resource. 3209 std::vector< DAVResource > resources; 3210 std::vector< rtl::OUString > aPropNames; 3211 uno::Sequence< beans::Property > aProperties( 5 ); 3212 aProperties[ 0 ].Name 3213 = rtl::OUString::createFromAscii( "IsFolder" ); 3214 aProperties[ 1 ].Name 3215 = rtl::OUString::createFromAscii( "IsDocument" ); 3216 aProperties[ 2 ].Name 3217 = rtl::OUString::createFromAscii( "IsReadOnly" ); 3218 aProperties[ 3 ].Name 3219 = rtl::OUString::createFromAscii( "MediaType" ); 3220 aProperties[ 4 ].Name 3221 = DAVProperties::SUPPORTEDLOCK; 3222 3223 ContentProperties::UCBNamesToDAVNames( 3224 aProperties, aPropNames ); 3225 3226 rResAccess->PROPFIND( 3227 DAVZERO, aPropNames, resources, xEnv ); 3228 3229 if ( resources.size() == 1 ) 3230 { 3231 m_xCachedProps.reset( 3232 new CachableContentProperties( resources[ 0 ] ) ); 3233 m_xCachedProps->containsAllNames( 3234 aProperties, m_aFailedPropNames ); 3235 } 3236 3237 eResourceType = DAV; 3238 } 3239 catch ( DAVException const & e ) 3240 { 3241 rResAccess->resetUri(); 3242 3243 if ( e.getStatus() == SC_METHOD_NOT_ALLOWED ) 3244 { 3245 // Status SC_METHOD_NOT_ALLOWED is a safe indicator that the 3246 // resource is NON_DAV 3247 eResourceType = NON_DAV; 3248 } 3249 } 3250 } 3251 m_eResourceType = eResourceType; 3252 } 3253 return m_eResourceType; 3254 } 3255 3256 //========================================================================= 3257 const Content::ResourceType & Content::getResourceType( 3258 const uno::Reference< ucb::XCommandEnvironment >& xEnv ) 3259 throw ( uno::Exception ) 3260 { 3261 return getResourceType( xEnv, m_xResAccess ); 3262 } 3263