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